Pytorch之Linear与MSELoss

在前面我们介绍了如何用Pytorch来实现一个两层的神经网络,但是其编码过程略微显得有点复杂。例如我们要手动自己定义权重参数,自己书写如何进行梯度更新等等。但要是某个网络多达几十层,那这个工作量显然是巨大的。因此,将一些常用的操作定义成更高级的API接口也是每个深度学习框架应该包含的东西。下面,在这篇文章中我们就介绍如何用Pytorch来简洁的实现多层全连接网络。

1 数据集与网络结构

数据集我们还是使用sklearn中的波士顿房价预测数据集,其每个样本包含有13个特征维度。因此我们神经网络的输入层就应该是13个神经元。同时,由于是做房价预测的回归任务,因此其输出层应该为1个神经元。在这个任务中,我们以一个4层神经网络为例进行示例。

图 1.网络结构图(偏置未画出)

对于这么一个稍显复杂的网络结构应该怎么的快速实现呢?尽管图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=<SelectBackward>)

#前文中的单层神经网络(线性回归)
RMSE: 3.308687686920166
真实房价: tensor(21.7000)
预测房价: tensor([20.9065], grad_fn=<SelectBackward>)

如上所示为代码运行结果,可以看出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]这样拟合正弦函数你会吗?

[2]你告诉我什么是深度学习

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页