文章目录
- 简述
- 代码重构要点
- 数学模型、运行结果
- 数据构建与分批
- 模型封装
- 运行测试
简述
python使用 数值微分法 求梯度,实现单层线性回归-CSDN博客
python使用 计算图(forward与backward) 求梯度,实现单层线性回归-CSDN博客
数值微分求梯度、计算图求梯度,实现单层线性回归 模型速度差异及损失率比对-CSDN博客上述文章都是使用python来实现求梯度的,是为了学习原理,实际使用上,pytorch实现了自动求导,原理也是(基于计算图的)链式求导,本文还就 “单层线性回归” 问题用pytorch实现。
代码重构要点
1.nn.Moudle
torch.nn.Module
的继承、nn.Sequential
、nn.Linear
:
torch.nn — PyTorch 2.4 documentation
对于nn.Sequential
的理解可以看python使用 计算图(forward与backward) 求梯度,实现单层线性回归-CSDN博客一文代码的模型初始化与计算部分,如图:
nn.Sequential
可以说是把图中标注的代码封装起来了,并且可以放多层。
2.torch.optim
优化器
本例中使用随机梯度下降torch.optim.SGD()
。
torch.optim — PyTorch 2.4 documentation
SGD — PyTorch 2.4 documentation
3.数据构建与数据加载
data.TensorDataset
、data.DataLoader
,之前为了实现数据分批,手动实现了data_iter
,现在可以直接调用pytorch的data.DataLoader
。
对于data.DataLoader
的参数num_workers
,默认值为0,即在主线程中处理,但设置其它值时存在反而速度变慢的情况,以后再讨论。
数学模型、运行结果
y = X W + b y = XW + b y=XW+b
y为标量,X列数为2. 损失函数使用均方误差。
运行结果:
数据构建与分批
def build_data(weights, bias, num_examples):
x = torch.randn(num_examples, len(weights))
y = x.matmul(weights) + bias
# 给y加个噪声
y += torch.randn(1)
return x, y
def load_array(data_arrays, batch_size, num_workers=0, is_train=True):
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size=batch_size, num_workers=num_workers, shuffle=is_train)
模型封装
class TorchLinearNet(torch.nn.Module):
def __init__(self):
super(TorchLinearNet, self).__init__()
model = nn.Sequential(Linear(in_features=2, out_features=1))
self.model = model
self.criterion = nn.MSELoss()
def predict(self, x):
return self.model(x)
def loss(self, y_predict, y):
return self.criterion(y_predict, y)
运行测试
if __name__ == '__main__':
start = time.perf_counter()
true_w1 = torch.rand(2, 1)
true_b1 = torch.rand(1)
x_train, y_train = build_data(true_w1, true_b1, 5000)
net = TorchLinearNet()
print(net)
init_loss = net.loss(net.predict(x_train), y_train)
loss_history = list()
loss_history.append(init_loss.item())
num_epochs = 3
batch_size = 50
learning_rate = 0.01
dataloader_workers = 6
data_loader = load_array((x_train, y_train), batch_size=batch_size, is_train=True)
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)
for epoch in range(num_epochs):
# running_loss = 0.0
for x, y in data_loader:
y_pred = net.predict(x)
loss = net.loss(y_pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# running_loss = running_loss + loss.item()
loss_history.append(loss.item())
end = time.perf_counter()
print(f"运行时间(不含绘图时间):{(end - start) * 1000}毫秒\n")
plt.title("pytorch实现单层线性回归模型", fontproperties="STSong")
plt.xlabel("epoch")
plt.ylabel("loss")
plt.plot(loss_history, linestyle='dotted')
plt.show()
print(f'初始损失值:{init_loss}')
print(f'最后一次损失值:{loss_history[-1]}\n')
print(f'正确参数: true_w1={true_w1}, true_b1={true_b1}')
print(f'预测参数:{net.model.state_dict()}')