在之前的几节里涉及到过简单的线性模型,本章将利用pytorch提供的工具来实现线性回归。我们会介绍诸如Module、构造Loss函数、构造随机梯度下降优化器等。这些东西pytorch都会提供,因此本章的主要作用就是如何利用pytorch提供的工具来帮助我们更方便的实现构建线性模型。
首先回顾一下前面讲过的,第一步是要确定Linear Model,再定义损失函数进行优化。在pytorch中进行优化的时候,要用到的是sgd(随机梯度下降),而用sgd核心的步骤是要求出每一个损失函数关于权重的偏导(梯度),这就是在优化这一步我们要做的工作。接下来我们就开始利用pytorch提供的工具来实现线性模型,虽然下面的代码可能会更加麻烦,但它具有更好的可扩展性,换句话说就是能用他干很多事情。
- 准备数据集
- 用class构建模型(继承自nn.Moudle),用来计算y_hat
- 构造损失函数 和 优化器(使用pytorch的API)
- 写训练周期(forward, backward, update;前馈算损失,反馈算梯度,随机梯度下降更新权重)
这里我们准备的数据集样例很简单,如下所示,x和y都是3×1的矩阵。
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[2.0], [4.0], [6.0]])
我们在前面进行训练的时候是要人工求导的,在pytorch里我们就不再人工求导。我们的重心要转移到构建计算图,只要计算图能够成功地构建出来,梯度一类的就会自动求出来,然后我们就可以去做优化了。一个简单的计算图如图1所示。
x被输入后,经过一个线性单元的运算得到y_hat,再进入loss函数求出loss值。求出loss值后就可以在loss这里调用backward,之后对整个计算图进行反向传播。下面是模型构建的代码部分:
class LinearModel (torch.nn.Module) : # 必须继承自 torch.nn.Module
def __init__(self) : # 所有的模型至少都要实现 init 和 forward
super(LinearModel, self).__init__() # 这行不用管他为什么,直接写上就对了
self.linear = torch.nn.Linear(1, 1) # 构造对象,linear 中已经包含了 ω 和 b,两个参数分别为输入输出的 size
# 用 module 构造出来的对象,会自动帮助实现 backward 的过程
def forward (self, X) : # forward 是前馈的过程中所要进行的计算
y_pred = self.linear (x)
return y_pred
model = LinearModel()
# 优化器
criterion = torch.nn.MSELoss(size_average = False)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
下面是训练的过程:这一套过程都是在框架中进行的,其原理与之前讲的手工训练完全一样。显然,采用框架可以大大的减少代码量。
for epoch in range(100) :
y_pred = model(x_data) # 先在前馈中算y_hat
loss = criterion(y_pred, y_data) # 计算损失
print(epoch, loss)
optimizer.zero_grad () # 一定注意--梯度清零--
loss.backward() # 反向传播
optimizer.step () # 进行更新
# 训练情况的输出
print('W = ',model.linear.weight.item())
print('b = ',model.linear.bias.item())
# Test Model
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred =',y_test.data)
以上就是模型训练的一个完整套路。
完整的可复制代码如下:
import torch
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[2.0], [4.0], [6.0]])
class LinearModel(torch.nn.Module): # 必须继承自 torch.nn.Module
def __init__(self): # 所有的模型至少都要实现 init 和 forward
super(LinearModel, self).__init__() # 这行不用管他为什么,直接写上就对了
self.linear = torch.nn.Linear(1, 1) # 构造对象,linear 中已经包含了 ω 和 b,两个参数分别为输入输出的 size
# 用 module 构造出来的对象,会自动帮助实现 backward 的过程
def forward(self, X): # forward 是前馈的过程中所要进行的计算
y_pred = self.linear(x)
return y_pred
model = LinearModel()
# 优化器
criterion = torch.nn.MSELoss(size_average = False)
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01)
for epoch in range(100):
y_pred = model(x_data) # 先在前馈中算y_hat
loss = criterion(y_pred, y_data) # 计算损失
print(epoch, loss)
optimizer.zero_grad() # 一定注意--梯度清零--
loss.backward() # 反向传播
optimizer.step() # 进行更新
# 训练情况的输出
print('W = ', model.linear.weight.item())
print('b = ', model.linear.bias.item())
# Test Model
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred =', y_test.data)