本节使用Pytorch中的linear做回归
使用pytorch做深度学习分析,一般有如下范式
- 1,准备数据集,数据集有很多种类型,图像数据集、表格数据集等。
- 2,设计自己的模型,继承Pytorch的nn.module类。
- 3,构建损失函数和优化器,调用pytorch现成的接口。
- 4,循环训练,前向传播–>反向传播–>更新权重。
1,准备数据集
pytorch中的数据集一般是mini-batch风格,也就是(N,data.dim),对于本节的任务。有三个样本,一次batch就是3个样本,构建成矩阵。
import torch
#构建数据集
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[2.0], [4.0], [6.0]])
2,构建模型
本小结使用的模型为只包含一个神经元的线性层
#模型类继承于nn.Module
class LinearModel(torch.nn.Module):
def __init__(self):#构造函数,初始化对象时默认调用的函数
#重写了__init__,要继承父类的构造
super(LinearModel, self).__init__() #调用父类的构造,继承父类的资源
#nn.Linear类包含两个成员张量:weight和bias
#Linear类也是继承自Module,可以自动进行反向传播
self.linear = torch.nn.Linear(1, 1) #类后面加括号-构造对象
def forward(self, x):
y_pred = self.linear(x)#对象后面加括号-实现了一个__call__(),可调用的对象
return y_pred
#创建一个LinearModel实例
model = LinearModel() #注意这个model是可调用的,callable
3,构建损失函数和优化器
criterion = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01) #SGD类的实例化
损失函数用的是平均平方损失
创建损失函数有三个参数,但前两个pytorch并不建议使用
实际上前两个参数的修改都可以通过第三个参数的修改到达目的,下面有个小实验
import torch
criterion = torch.nn.MSELoss(reduction='sum')
# 一个批次是3个样本
input = torch.arange(3,dtype=torch.float32).reshape(-1,1)
target = torch.arange(3,6,dtype=torch.float32).reshape(-1,1)
loss = criterion(input,target)
loss
实验结果
- 把size_average=False设置成FALSE就是不对每个batch求平均,损失函数编程平方损失,而不是平均平方损失。
优化器采用的是随机梯度下降,实际上应该叫小批量随机梯度下降 - pytorch实际上预设有13种优化方法,本小结的作业,需要对比采用不同的优化器,损失迭代的曲线有何不同,有些优化器使用方法略有不同。如下图所示:
4,循环训练
for epoch in range(100):
y_pred = model(x_data)#forward:预测
loss = criterion(y_pred, y_data)#forward:loss
print(epoch, loss) #打印loss时会自动调用__str__()函数,不会产生计算图,这是安全的
optimizer.zero_grad()#注意.backward()时梯度会被累计,注意所有的权重设为0
loss.backward()#反向传播:autograd
optimizer.step()#update,根据梯度和设好的学习率进行更新
完整代码
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):
def __init__(self):
super(LinearModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self, x):
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(1000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
print("epoch:",epoch,"loss:",loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("**************test***************")
print('w = ', model.linear.weight.item())
print('b = ', model.linear.bias.item())
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('when x = 4, y_pred = ',y_test.data)
作业
- 同时设置不同的优化器,我使用的是列表。先把方法存到列表中。
import numpy as np
import torch
import matplotlib.pyplot as plt
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):
def __init__(self):
super(LinearModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self, x):
y_pred = self.linear(x)
return y_pred
model = LinearModel()
# 线性层实际接受的是向量,但是注意,我们输入的是mini-batch,所以输入到线性层就是矩阵。那么输出也是batch的矩阵。
criterion = torch.nn.MSELoss()
# optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 作业要求:对比不同优化器的损失曲线
optimizer_list = ['Adagrad','Adam','Adamax','ASGD',
'RMSprop','Rprop','SGD']
l1 = [] # 总的优化器损失列表
for opt in range(len(optimizer_list)):
optimizer = 'torch.optim.' + optimizer_list[opt]
optimizer = eval(optimizer)(model.parameters(), lr=0.01) # eval消除引号
l2 = [] # 当前被选中的优化器损失列表
for epoch in range(50):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
# 记录损失
l2.append(loss.item())
optimizer.zero_grad() # 消除上一步梯度信息
loss.backward() # 反向传播,更新梯度
optimizer.step() # 更新参数
l1.append(l2)
l1 = np.array(l1) # 转成numpy格式方便作图
# 作图
marker = ['s','p','*','+','x','d','2']
plt.rc('legend', fontsize=14)
fig = plt.figure(figsize=(10,5.5),dpi=100)
for i in range(len(optimizer_list)):
plt.plot(l1[i],marker=marker[i],label=optimizer_list[i])
plt.xlabel('epoch',fontsize=14)
plt.ylabel('loss',fontsize=14)
plt.legend()
plt.show()
这里对比7种算法
再把学习率调成0.001,和老师的0.01不同。如下图为0.001
再把学习率调成0.01
作业实验结果与讨论
- 学习率有时候会显著影响训练情况。
- 不同的优化器产生的训练效果不同,但这不是说明哪个优化器更好,仅仅说明在当前任务下哪些优化器更好。