使用PyTorch构建线性回归模型
写在前面
之前写过一篇博客,是不基于任何深度学习框架的纯numpy实现,其实整个过程比较繁琐。而深度学习框架能够提供给很多便利,避免一些重复性的工作,也使得代码变得更加简洁。本文主要是基于Pytorch框架实现一个线性回归模型。
基于numpy的线性回归模型构建:波士顿房价预测——线性模型(numpy实现)
代码
import依赖库
import torch
import torch.nn as nn
from time import time
import matplotlib.pyplot as plt
import random
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline
数据生成
人为地生成一批数据,基于y=2x1 - 3.4x2 + 4.2
加上一些高斯噪声,从而生成一批数据(1000个)。
# 数据生成
true_w = [2, -3.4]
true_b = 4.2
features = torch.randn((1000, 2), dtype=torch.float32) # x的shape为[1000, 2]
labels = true_w[0]*features[:,0] + true_w[1]*features[:,1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float32) # label为Wx+b+噪声
features.shape, labels.shape
(torch.Size([1000, 2]), torch.Size([1000]))
# 绘制三维散点图
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(features[:,0], features[:,1], labels)
plt.show()
导入数据
使用torch.utils.data构造Dataset,然后导入
import torch.utils.data as Data # 导入data包
# 定义batchsize
batch_size = 10
# 利用TensorDataset封装为一个torch的Dataset
dataset = Data.TensorDataset(features, labels)
# 使用DataLoader加载数据
data_iter = Data.DataLoader(dataset, batch_size=batch_size, shuffle=True)
构建模型
nn意为neural network
,torch的nn模块提供了很多可直接调用的API用于构建网络模型。
nn的核心数据结构是Module
,它是一个抽象概念,既可以表示神经网络中的某个层(layer),也可以表示一个包含很多层的神经网络。在实际使用中,最常见的做法是继承nn.Module,撰写自己的网络/层。一个nn.Module实例应该包含一些层以及返回输出的前向传播(forward)方法。
# 构建模型
class LinearNet(nn.Module):
def __init__(self, n_feature):
super().__init__()
self.linear = nn.Linear(n_feature, 1) # Linear层 传入input sample、output的size
self.initialize_weight() # 初始化权重
def forward(self, x):
z = self.linear(x)
return z
def initialize_weight(self): # 参数初始化
for m in self.modules():
if isinstance(m, nn.Linear): # isinstance() 函数来判断一个对象是否是一个已知的类型
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)
net = LinearNet(2) # 实例化模型
print(net) # 打印网络结构
for name,param in net.named_parameters(): # 通过named_parameters()来查看网络的参数和对应的name
print(name,param)
定义优化器和损失函数
使用torch.optim定义优化器,nn定义损失函数
# 定义优化器以及loss function
import torch.optim as optim
criterion = nn.MSELoss() ## nn中提供了很多损失函数,这里使用MSE
optimizer = optim.SGD(net.parameters(), lr=0.03) # optim提供了许多优化器选择 使用简单的SGD
还可以为不同子网络(层)设置不同的学习率,这在finetune时经常用到,下例与Linear Model无关,因为线性回归只有层。
optimizer = optim.SGD([
# 如果对某个参数不指定学习率,就使用最外层的默认学习率
{'params': net.subnet1.parameters()}, # lr=0.03
{'params': net.subnet2.parameters(), 'lr':0.01}
], lr=0.03)
有时候对于学习率的调整,我们也不希望是一成不变的,希望是随着训练轮次的增加动态调整的。
这主要有两种做法:一种是修改optimizer.param_groups中对应的学习率,另一种是更简单也是较为推荐的做法——新建优化器,由于optimizer十分轻量级,构建开销很小,故而可以构建新的optimizer。
# 调整学习率
for param_group in optimizer.param_groups:
param_group['lr'] *= 0.1 # 学习率为之前的0.1倍
但是后者对于使用动量的优化器(如Adam),会丢失动量等状态信息,可能会造成损失函数的收敛出现震荡等情况。
模型训练
epochs = 3
for epoch in range(epochs):
epoch_loss = 0.
for (x, y) in data_iter:
optimizer.zero_grad() # 梯度清零
z = net(x) # 前向传递
loss = criterion(z, y.view(-1,1)) # 求loss
epoch_loss += loss.item()
loss.backward() # loss反向传播
optimizer.step() # 更新参数
if (epoch+1)%1==0:
print("epoch{} loss: {}".format(epoch+1, epoch_loss))
epoch1 loss: 94.01486129091427
epoch2 loss: 0.010219457717539626
epoch3 loss: 0.010239769631880336
检验
对比模型参数与标准设置参数:
for param in net.parameters():
print(param)
for param in net.parameters():
print(param)
可以看到结果还是很不错的
参考
[1] https://github.com/ShusenTang/Dive-into-DL-PyTorch/blob/master/docs/chapter03_DL-basics/3.3_linear-regression-pytorch.md 《Dive-into-DL-PyTorch》
[2] https://zh.gluon.ai/chapter_deep-learning-basics/linear-regression-gluon.html 李沐《动手学深度学习》
上一篇: 创建数据表