手动构建线性回归(代码+注释)
"""
torch:PyTorch 库,用于构建和训练模型。
make_regression:Scikit-learn 中的函数,用于生成回归问题的数据集。
math:Python 数学库,用于数学计算(如向上取整)。
"""
import torch
from sklearn.datasets import make_regression
import math
# 生成数据集
def data_sets():
# 研究下这个API
x,y,ceof = make_regression(n_samples=150, n_features=4, bias=3,noise=80, random_state=42,shuffle=True,coef=True)
print(x.shape,y.shape,ceof)
return x,y,ceof
"""
make_regression:生成一个回归问题的数据集。
n_samples=150:生成 150 个样本。
n_features=4:每个样本有 4 个特征。
bias=3:线性模型的偏置项为 3。
noise=80:添加噪声,噪声的标准差为 80。
random_state=42:随机种子,确保每次生成的数据相同。
shuffle=True:打乱数据顺序。
coef=True:返回生成数据时使用的真实系数。
# 返回:
x:特征矩阵,形状为 (150, 4)。
y:目标值,形状为 (150,)。
ceof:生成数据时使用的真实系数。
"""
# 定义线性回归模型
def model_regression(x,w,b):
# print(w.shape,x.shape,(x*w).shape,b.shape)
return x@w+b
"""
这是一个简单的线性回归模型:
x:输入特征矩阵。
w:权重参数。
b:偏置参数。
@:矩阵乘法运算符,计算 x 和 w 的点积,然后加上偏置 b。
"""
# 初始化模型参数
def init_w_b(x):
w = torch.rand(x.shape[1],requires_grad=True,dtype=torch.float32)
b = torch.rand(1, requires_grad=True,dtype=torch.float32)
return w,b
"""
初始化权重 w 和偏置 b:
w:形状为 (n_features,),随机初始化。
b:形状为 (1,),随机初始化。
requires_grad=True:表示这些参数需要计算梯度。
dtype=torch.float32:指定数据类型为 32 位浮点数。
"""
# 定义损失函数
def mse(y,y_pred):
return torch.mean((y-y_pred)**2)
"""
计算均方误差(MSE):
y:真实目标值。
y_pred:模型预测值。
torch.mean:计算平均值。
"""
# 更新模型参数
def step(w,b,lr=0.01):
w.data = w.data - lr*w.grad
b.data = b.data - lr*b.grad
"""
使用梯度下降法更新参数:
w.data 和 b.data:直接修改参数的值。
lr:学习率,控制更新步长。
w.grad 和 b.grad:参数的梯度。
"""
# 梯度清零
def my_zero_grad(w,b):
if w.grad is not None:
w.grad.zero_()
if b.grad is not None:
b.grad.zero_()
"""
在每次反向传播前,将参数的梯度清零,避免梯度累积。
"""
# 模型训练
def train():
# 加载数据并转换为 PyTorch 张量
x,y,ceof = data_sets()
x = torch.tensor(x,dtype=torch.float32)
y = torch.tensor(y,dtype=torch.float32)
# 初始化模型参数
w,b = init_w_b(x)
print(w.requires_grad,b.requires_grad)
# 设置训练参数
# 学习率
lr = 0.001
# 训练轮数
epochs = 100
# 小批量
batch_size = 16
for epoch in range(epochs):
e=[] # 用于存储每批数据的损失
for i in range(math.ceil(x.shape[0]/batch_size)):
# 获取小批量数据
x_batch=x[batch_size*i:batch_size*(i+1)]
y_batch=y[batch_size*i:batch_size*(i+1)]
# 预测
y_pred=model_regression(x_batch,w,b)
# 16条数据的均方误查(计算损失)
loss=mse(y_batch,y_pred)
e.append(loss)
# 梯度清零
my_zero_grad(w,b)
# 反向传播(求梯度)
loss.backward()
# 更新参数
step(w,b,lr)
# 计算平均损失
mse_loss=torch.tensor(e).mean()
print(f"{epoch}/{epochs},当前loss:{mse_loss},grad_w:{w.grad},grad_b:{b.grad}")
pass
train()
"""
!!!!!!循环训练的详细步骤解释!!!!!!
1、外层循环:训练轮数
-for epoch in range(epochs):遍历每一轮训练。
2、内层循环:小批量训练
-for i in range(math.ceil(x.shape[0] / batch_size)):将数据分成小批量进行训练。
-math.ceil(x.shape[0] / batch_size):计算需要多少个小批量。
-x_batch 和 y_batch:获取当前小批量的特征和目标值。
3、预测
-y_pred = model_regression(x_batch, w, b):使用当前参数 w 和 b 对 x_batch 进行预测。
4、计算损失
-loss = mse(y_batch, y_pred):计算预测值 y_pred 和真实值 y_batch 之间的均方误差(MSE)。
-e.append(loss):将当前批次的损失值存储到列表 e 中。
5、梯度清零
-my_zero_grad(w, b):在每次反向传播前,将 w 和 b 的梯度清零,避免梯度累积。
6、反向传播
-loss.backward():计算损失函数对 w 和 b 的梯度。
7、更新参数
-step(w, b, lr):使用梯度下降法更新 w 和 b 的值。
8、计算平均损失
-mse_loss = torch.tensor(e).mean():计算当前轮次所有小批量的平均损失。
-print(f"{epoch}/{epochs}, 当前 loss: {mse_loss}, grad_w: {w.grad}, grad_b: {b.grad}"):打印当前轮次的损失和梯度。
"""
详细步骤:
- 导入库
- 生成数据集
- 定义线性回归模型
- 初始化模型参数
- 定义损失函数
- 定义参数更新函数
- 定义梯度清零函数
- 训练模型(包括加载数据、初始化参数、设置训练参数、训练循环)
- 运行训练