用PyTorch实现线性回归(刘二大人pytorch第五讲)
用PyTorch学习框架写深度学习代码可以分为以下几个步骤:
步骤1,准备数据集,转换为tensor
步骤2,设计模型(构造计算图,用来计算)
步骤3,选择损失和优化器
步骤4,写训练周期:前馈(算损失)、反馈(算梯度)、更新(使用梯度下降算法更新权重)
- 数据准备
输入数据需要转换成tensor张量。
在Mini_batch训练方式中,要使用张量(tensor)形式,而非直接使用数字作为输入。其原因有:(1)张量是多维数组,存储时可以利用GPU的内存空间,提高存储效率。在PyTorch中针对张量运算进行了高度优化,可以利用GPU的并行计算能力快速对张量进行各种数学运算,而数字无法利用GPU的并行计算能力;(2)在深度学习中,张量可以作为一种统一的数据结构来表示图片、音频、文本等不同类型的数据;(3)当使用张量进行计算时,深度学习框架会自动构建一个计算图,记录张量之间的运算关系,在反向传播过程中,框架可以根据间计算图自动计算每个张量的梯度,从而实现自动求导。如果直接使用数字作为输入,无法计算图。 - 设计模型(构造计算图)
定义模型的模板:
# python
class LinearModel(torch.nn.Module):
# 构造函数,用来存储需要用到的全局变量
def __init__(self):
super(LinearModel, self).__init__() # 调用父类的__init__方法。固定写法,必须有
self.linear = torch.nn.Linear(1,1) # 构造对象,Linear对象包含了权重、偏置
# 自定义前向传播函数(函数重写)
def forward(self,x):
y_pred = self.linear(x)
return y_pred
不定义反向传播的原因:使用Module构造出来的对象,会自动根据计算图实现backward的过程。
自定义前向传播:因为Module类中对forward有定义,我们需要根据我们模型的需要对forward重写。
- 构造损失函数和优化器
criterion = torch.nn.MSELoss(size_average=False) #需要的参数(y_pred,y)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
MSELoss继承自nn.Module,当输入的 和
是 PyTorch 的 Tensor 且其 requires_grad 属性为 True 时,torch.nn.MSELoss 会构建计算图。
优化器SGD 不是Module,不会构建计算图。
model.parameters():parameters()会检查model里所有成员,如果成员里有相应的权重,就把权重都加在要训练的参数集合上。
- 训练单元
for epoch in range(1000):
optimizer.zero_grad() # 梯度清零
y_pred = model(x_data) # 前馈,计算预测值y_pred
loss = criterion(y_pred, y_data) # 计算损失。
loss.backward() # 损失反向传播
optimizer.step() # 梯度更新
注:在训练过程中,有可能看到,在训练集上随着epoch增加loss会逐渐减小,但在测试集上可能会出现随着epoch增加loss先增加后减小,这是因为过度训练造成过拟合了。所有在真正训练时,epoch的选定不仅要观察loss在训练集上的趋势,也要观察在测试集上的趋势。
整体代码:
# !usr/bin/env python
# -*- conding:utf-8 -*-
# 刘二大人第五讲(用PyTorch实现线性回归)
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()
# 损失实例化 ,对torch.nn.MSELoss实例化后,得到一个可调用对象(即一个函数对象)criterion
criterion = torch.nn.MSELoss(size_average=False)
# 优化函数实例化
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
epoches=[]
losses=[]
for epoch in range(100):
optimizer.zero_grad()
y_pred = model(x_data)
# 当调用criterion(y_pred,y_data) 时,y_pred,y_data会作为参数传递给criterion的__call__方法
loss = criterion(y_pred,y_data) # 计算损失
print(epoch, loss.item())
loss.backward() # loss反向传播
optimizer.step() # 梯度更新
epoches.append(epoch)
losses.append(loss.item())
print('w=', model.linear.weight.item())
print('b=', model.linear.bias.item())
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred = ', y_test.data)
plt.figure(figsize=(10, 5))
plt.plot(epoches, losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss vs Epoch')
plt.show()