从零实现线性回归模型 - d2l-ai/d2l-en 项目解析
引言
线性回归是机器学习中最基础也最重要的模型之一。在d2l-ai/d2l-en项目中,作者通过从零实现线性回归模型,帮助读者深入理解模型的工作原理。本文将详细解析这一实现过程,涵盖模型定义、损失函数、优化算法以及训练循环等关键环节。
模型定义
参数初始化
在构建线性回归模型时,首先需要初始化模型参数。这里采用正态分布初始化权重w,偏置b初始化为0:
class LinearRegressionScratch(d2l.Module):
def __init__(self, num_inputs, lr, sigma=0.01):
super().__init__()
self.save_hyperparameters()
self.w = d2l.normal(0, sigma, (num_inputs, 1))
self.b = d2l.zeros(1)
num_inputs
:输入特征的数量lr
:学习率sigma
:初始化标准差,默认为0.01
这种初始化方式在实践中表现良好,既避免了参数过大导致的梯度爆炸,也避免了过小导致的梯度消失。
前向传播
线性模型的前向传播非常简单,就是输入特征X与权重w的矩阵乘法加上偏置b:
@d2l.add_to_class(LinearRegressionScratch)
def forward(self, X):
return d2l.matmul(X, self.w) + self.b
这里利用了广播机制,使得偏置b能够自动扩展到每个样本上。
损失函数
线性回归通常使用均方误差(MSE)作为损失函数:
@d2l.add_to_class(LinearRegressionScratch)
def loss(self, y_hat, y):
l = (y_hat - y) ** 2 / 2
return d2l.reduce_mean(l)
MSE衡量了预测值与真实值之间的差距,除以2是为了简化后续梯度计算的表达式。损失函数返回的是整个小批量样本的平均损失。
优化算法
随机梯度下降(SGD)实现
SGD是最基础的优化算法,其核心思想是沿着负梯度方向更新参数:
class SGD(d2l.HyperParameters):
def __init__(self, params, lr):
self.save_hyperparameters()
def step(self):
for param in self.params:
param -= self.lr * param.grad
params
:需要优化的参数列表lr
:学习率,控制每次更新的步长
对于PyTorch实现,还需要添加梯度清零的操作:
def zero_grad(self):
for param in self.params:
if param.grad is not None:
param.grad.zero_()
优化器配置
将SGD优化器与模型参数关联:
@d2l.add_to_class(LinearRegressionScratch)
def configure_optimizers(self):
return SGD([self.w, self.b], self.lr)
训练过程
训练循环
完整的训练循环包括以下步骤:
- 前向传播计算预测值
- 计算损失
- 反向传播计算梯度
- 使用优化器更新参数
@d2l.add_to_class(d2l.Trainer)
def fit_epoch(self):
self.model.train()
for batch in self.train_dataloader:
loss = self.model.training_step(self.prepare_batch(batch))
self.optim.zero_grad()
loss.backward()
self.optim.step()
模型验证
在每个epoch结束后,可以在验证集上评估模型性能:
if self.val_dataloader is None:
return
self.model.eval()
for batch in self.val_dataloader:
with torch.no_grad():
self.model.validation_step(self.prepare_batch(batch))
实验验证
合成数据
使用合成数据可以精确控制数据分布,便于验证模型实现的正确性:
model = LinearRegressionScratch(2, lr=0.03)
data = d2l.SyntheticRegressionData(w=d2l.tensor([2, -3.4]), b=4.2)
trainer = d2l.Trainer(max_epochs=3)
trainer.fit(model, data)
参数评估
训练完成后,可以比较学习到的参数与真实参数:
print(f'error in estimating w: {data.w - d2l.reshape(model.w, data.w.shape)}')
print(f'error in estimating b: {data.b - model.b}')
在理想情况下,这些误差应该非常小,表明模型成功学习到了数据的真实分布。
总结
通过从零实现线性回归模型,我们深入理解了:
- 模型参数初始化的重要性
- 前向传播的计算过程
- 损失函数的选择与实现
- 优化算法的工作原理
- 完整的训练循环流程
这种从底层实现的方式虽然比直接使用高级框架更繁琐,但对于理解深度学习的基本原理至关重要。掌握了这些基础知识后,才能更好地理解和自定义更复杂的模型结构。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考