上一章介绍了线性回归的适用场景,代码实现以及简单的原理。但每次都要去写那么多代码去实现线性回归中的那些函数,例如优化算法,损失函数等等会比较麻烦,因此我们可以利用神经网络中的某些包中的某些方法就可以快速的来解决问题了。
我们还是使用上一个blog中的例子,通过 synthetic_data 这个函数我们可以获得样本数据,然后自定义w和b值,可以得到样本y值。数据集创建见上一篇文章,接下来的读取与训练的方法将稍有不同。
这些代码可以替代上一篇博客中的data_iter函数,pytorch有一个自带的迭代器,将shuffle设置为True就可以实现打乱下标的操作。一个data.DataLoader就可以省去上一篇博客中许多的代码,还是很方便的。
def load_array(data_arrays, batch_size, is_train=True): #@save
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays) #格式转变为数据集
return data.DataLoader(dataset, batch_size, shuffle=is_train) #随机挑选batch_size个样本出来
batch_size = 10
data_iter = load_array((features, labels), batch_size)
def linreg(X, w, b): #@save
"""线性回归模型"""
return torch.matmul(X, w) + b
Sequential这个类可以将神经网络中的多个层串联,例如第一层的输出就是第二层的输入,但我们这个问题只有一层就可以出结果,这边就是熟悉一下这个类。
这一层是一个全连接层,因为这层的计算就是矩阵点乘实现的,全连接是由神经网络中的Linear类实现的,他的两个参数分别是输入和输出的特征形状,因为本文中的例子是两个变量,也就有两个权重,是一个n行2列的矩阵点乘2行1列的矩阵,那么输入的特征形状就是2,假如有三个变量三个权重,那输入特征形状就是3。我是这样理解的,测试也验证了这一理解。接下来输出特征形状就是1,因为点乘出来的结果就是1个数,那么特征形状就是1。
from torch import nn #nn是神经网络的简写
net = nn.Sequential(nn.Linear(2, 1)) #
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
def squared_loss(y_hat, y): #@save
"""均方损失"""
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
用这个函数返回的是样本损失的均值,这里就和之前说的原理保持一致了
loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
这里的 l 是均分误差的均值,因此我们不需要像上一个博客先对 l 求sum(),也不需要在sgd里面去除以batch_size,使用神经网络中的包就能很方便的去使用线性回归。
num_epochs = 3 #3次迭代
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y) #获得一批的损失均值
trainer.zero_grad()
l.backward() #求导
trainer.step() #优化
l = loss(net(features), labels) #优化后的某次迭代的误差值
print(f'epoch {epoch + 1}, loss {l:f}')
使用神经网络的包可以快速的解决很多深度学习的问题,但我们还是最好能先了解一下每个算法的原理,这样可以帮助我们了解神经网络每个方法在做什么。
训练完成后,我们就可以用训练好的w和b值去预测y值。