在前面我们介绍了如何用Pytorch来实现一个两层的神经网络,但是其编码过程略微显得有点复杂。例如我们要手动自己定义权重参数,自己书写如何进行梯度更新等等。但要是某个网络多达几十层,那这个工作量显然是巨大的。因此,将一些常用的操作定义成更高级的API接口也是每个深度学习框架应该包含的东西。下面,在这篇文章中我们就介绍如何用Pytorch来简洁的实现多层全连接网络。
1 数据集与网络结构
数据集我们还是使用sklearn中的波士顿房价预测数据集,其每个样本包含有13个特征维度。因此我们神经网络的输入层就应该是13个神经元。同时,由于是做房价预测的回归任务,因此其输出层应该为1个神经元。在这个任务中,我们以一个4层神经网络为例进行示例。
对于这么一个稍显复杂的网络结构应该怎么的快速实现呢?尽管图1中的网络结构比起前面的是多了几层,但是好在均为全连接层。在Pytorch中,我们可以直接调用nn.Linear(in_features, out_features, bias=True):
来进行实现。
2 代码实现
2.1 导入相关包
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler
import torch
import torch.nn as nn
第四行代码为导入torch
中有关神经网络的相关操作。
2.2 载入数据
def load_data():
data = load_boston()
x, y = data.data, data.target
ss = StandardScaler()
x = ss.fit_transform(x) # 特征标准化
x = torch.tensor(x, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)
return x, y
2.3 定义并训练模型
def train(x, y):
epoches = 500
lr = 0.1
input_node = x.shape[1]
hidden_nodes = [10, 20, 10]
output_node = 1
net = nn.Sequential(
nn.Linear(input_node, hidden_nodes[0]), # 第一层 shape: [1,10]
nn.Sigmoid(), # 非线性变换
nn.Linear(hidden_nodes[0], hidden_nodes[1]), # 第二层 shape: [10,20]
nn.Sigmoid(),
nn.Linear(hidden_nodes[1], hidden_nodes[2]), # 第三层 shape: [20,10]
nn.Sigmoid(),
nn.Linear(hidden_nodes[2], output_node) # 第四层 shape: [10,1]
)
loss = nn.MSELoss()# 定义损失函数
optimizer = torch.optim.SGD(net.parameters(), lr=lr)# 定义优化器
for epoch in range(epoches):
logits = net(x)
l = loss(logits.reshape(y.shape), y)
optimizer.zero_grad()
l.backward()
optimizer.step()# 执行梯度下降
print("Epoch: {}, loss: {}".format(epoch, l))
logits = net(x)
l = loss(logits.reshape(y.shape), y)
print("RMSE: {}".format(torch.sqrt(l / 2)))
print("真实房价:", y[12])
print("预测房价:", logits[12])
前6行代码为定义网络结构中的相关参数,其中三个隐藏层的神经元个数分别为10,20和10。第7行至第15行代码为定义整个网络结构,其中nn.Linear()
需要转入两个参数,分别为上一层神经元的个数,和下一层神经元的个数。nn.Sigmoid()
为对上一层的输出加入一个非线性变换,nn.Sequential()
接收的是一个定义好的类,而这个类必须继承自nn.Module
,这方面的知识等用到时再进行介绍。
第16行代码为定义损失函数,默认为均方误差,如果设置为MSELoss(reduction='sum')
则返回的差误和。同时需要注意的是,Pytorch在计算MSE
的时候返回的结果并没有除以2。以下为Pytorch实现源码:
ret = (input - target) ** 2
if reduction != 'none':
ret = torch.mean(ret) if reduction == 'mean' else torch.sum(ret)
第17行代码为定义一个优化器,这里我们使用的是通过梯度下降来进行网络参数的更新。SGD()
优化器接收至少两个参数:需要训练的参数和学习率。由于我们使用的是nn.Sequential()
来进行网络搭建的,所以可以直接通过net.parameters()
一次传入所有参数。
第21至23行代码则分别进行的是梯度的清零、梯度求解和参数更新的工作。同时,为了和前面的线性回归做比较,在第27行在输出RMSE
时首先对损失值除以了2。
2.4 运行结果
#本文中的四层神经网络
RMSE: 1.8467791080474854
真实房价:tensor(21.7000)
预测房价:tensor([21.6100], grad_fn=)#前文中的单层神经网络(线性回归)
RMSE: 3.308687686920166
真实房价:tensor(21.7000)
预测房价:tensor([20.9065], grad_fn=)
如上所示为代码运行结果,可以看出4层的神经网络相较于单层的神经网络在同等条件下RMSE上有了很大的提升。因此可以再次看出,先通过多层神经网络进行特征提取,然后再进行回归任务能够有效提高最终的预测结果。
3 总结
在本篇文章中,笔者首先了一个如何通过一个4层的神经网络来完成房价预测的任务;然后介绍了如何通过Pytorch已经实现的高级API来完成网络模型的构建,并依次介绍了代码中各个API的使用方法和含义;最后还将运行得到的结果同之前的单层网络得到的结果进行了对比。本次内容就到此结束,感谢您的阅读!
本次内容就到此结束,感谢您的阅读!如果你觉得上述内容对你有所帮助,欢迎关注并传播本公众号!若有任何疑问与建议,请添加笔者微信'nulls8'加群进行交流。青山不改,绿水长流,我们月来客栈见!
引用
[1]深度学习与PyTorch入门实战教程 https://www.bilibili.com/video/BV11z4y1R748?p=39
[2]Pytorch官网 https://pytorch.org/
[3]示例代码:https://github.com/moon-hotel/DeepLearningWithMe
推荐阅读
[1]Pytorch之拟合正弦函数你会吗?
[2]你告诉我什么是深度学习
[3]《跟我一起深度学习》终于来了