1. 生成数据集
在构建模型之前,我们需要生成一个合适的数据集。我们可以用已知参数生成样本数据,从而在训练结束时检查模型是否能够有效逼近这些参数。
# d2l.py
def synthetic_data(w, b, num_examples):
"""生成y=Xw+b+噪声"""
X = torch.normal(0, 1, (num_examples, len(w)), requires_grad=True)
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
import torch
import d2l
num_examples = 1000
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, num_examples)
2. 读取数据集
我们可以通过 DataLoader 轻松创建一个数据迭代器,用于从数据集中逐批量提取数据。
# d2l.py
from torch.utils import data
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = d2l.load_array((features, labels), batch_size)
这样我们可以在训练时分批读取数据,大大提高数据处理效率。
3. 定义模型
在 PyTorch 中,我们可以直接使用 nn.Sequential 类来快速构建一个全连接层的线性回归模型。
net = nn.Sequential(nn.Linear(2, 1))
这行代码创建了一个包含一个输出节点的线性层。这里,输入形状为 ,输出形状为 。
4. 初始化模型参数
我们用 normal_ 方法将权重参数从均值为 0、标准差为 0.01 的正态分布中随机采样,并将偏置初始化为零。
net[0].weight.data.normal_(0, 0.01)
net[0].weight.data.fill_(0)
这一步有助于避免初始值相同导致的参数收敛过慢。
5. 定义损失函数
这里我们选择均方误差(MSE)作为损失函数。
loss = nn.MSELoss()
均方误差的公式为:
6. 定义优化算法
PyTorch 提供了多种优化算法,我们这里使用小批量随机梯度下降(SGD)。
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
7. 训练
训练过程包括生成预测、计算损失、反向传播梯度和更新参数。每个周期结束后,我们都会打印损失。
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
y_hat = net(X)
l = loss(y_hat, y)
trainer.zero_grad()
l.backward(retain_graph=True)
trainer.step()
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')
epoch 1, loss 0.000208
epoch 2, loss 0.000096
epoch 3, loss 0.000095
总结
通过以上步骤,我们用 PyTorch 框架高效地完成了线性回归的实现。这种方法不仅简化了模型定义和训练过程,也为后续更复杂的深度学习模型提供了基础。
import torch
from torch import nn
import d2l
num_examples = 1000 # 样本数
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, num_examples)
batch_size = 10
data_iter = d2l.load_array((features, labels), batch_size)
net = nn.Sequential(nn.Linear(2, 1)) # 定义线性模型
net[0].weight.data.normal_(0, 0.01) # 初始化权重参数
net[0].bias.data.fill_(0) # 初始化偏置参数
loss = nn.MSELoss() # 均方差损失函数
# 小批量随机梯度下降(SGD)
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X), y) # 预测值与真实值计算损失
trainer.zero_grad() # 清除参数梯度
l.backward(retain_graph=True) # 反向传播
trainer.step() # 更新梯度
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')