[PyTorch] 笔记03:神经网络

Posted 小郭学数据

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PyTorch] 笔记03:神经网络相关的知识,希望对你有一定的参考价值。

源自PyTorch 1.4教程[1]

Outline

  • LeNet概述
  • LeNet实现
    • 定义网络
    • 计算损失
    • 反向传播
    • 更新权重

[PyTorch] 笔记03:神经网络

构建神经网络所需要的包可以是torch.nn

而nn包则依赖于autograd包来定义模型并对它们求导

今天写的是LeNet网络,用来识别手写体

数据集的选用可以用mnist,可参见pytorch实现mnist手写数字识别[2]

1. LeNet概述

  • 一般的网络学习步骤可以分为以下几个步骤:
    • 定义网络,通过网络进行正向传播传递
    • 使用网络输出来计算损失
    • 使用loss.backward()通过网络进行反向传播误差
    • 使用优化器(比如随机梯度下降算法)更新权重
  • 复盘一下LeNet的网路结构 [PyTorch] 笔记03:神经网络
    • 当时使用的是平均池化,今天用最大池化来实现它
    • 由两个卷积层,两个池化,三个全连接层组成的网络结构
    • 当时是softmax函数实现多分类,今天用全连接实现

2. LeNet实现

2.1 定义网络

  • 包含初始化,前向传播,统计全连接层前输入的特征个数

  • 网络执行过程:conv1-->maxpool-->conv2-->maxpool-->fc1-->fc2-->fc3

    • 每一层之后执行激活函数relu
  • 代码如下:

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            # 输入图像channel:1;输出channel:6;5x5卷积核
            self.conv1 = nn.Conv2d(1, 6, 5)
            self.conv2 = nn.Conv2d(6, 16, 5)
            # an affine operation: y = Wx + b
            self.fc1 = nn.Linear(16 * 5 * 5, 120)
            self.fc2 = nn.Linear(120, 84)
            self.fc3 = nn.Linear(84, 10)

        def forward(self, x):
            # 2x2 Max pooling
            x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
            # 如果是方阵,则可以只使用一个数字进行定义,树池为2*2矩阵
            x = F.max_pool2d(F.relu(self.conv2(x)), 2)
            #变成一个1*num_flat_features(x)的张量
            x = x.view(-1, self.num_flat_features(x))
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(x))
            x = self.fc3(x)
            return x

        def num_flat_features(self, x):
            size = x.size()[1:]  # 除去批处理维度的其他所有维度
            num_features = 1
            for s in size:
                num_features *= s
            return num_features

    net = Net()
    print(net)
  • super() 函数是用于调用父类的一个方法,即调用了nn.Module。

  • Conv2d

    • 一般用于二维图像,Conv1d常用于文本数据的处理
    • 接口定义如下:
    •    class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
    • 参数含义:
    • in_channels:输入通道
    • out_channels:输出通道
    • kernel_size:过滤器大小
    • stride:步长
    • padding:填充数
    • dilation:卷积核即过滤器之间的空间距离
    • groups:分组卷积
    • bias:是否加偏移量即wx+b中的b
    • 关于groups介绍可参见nn.Conv2d中groups参数的理解 python [3]
  • 最大池化

    • 实现方式:nn.MaxPool2d(),torch.nn.functional.max_pool2d()
  • 输出

    Net(
      (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
      (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear(in_features=400, out_features=120, bias=True)
      (fc2): Linear(in_features=120, out_features=84, bias=True)
      (fc3): Linear(in_features=84, out_features=10, bias=True)
    )
  • 它定义完之后又反向传播计算了一下梯度,代码如下:
    清零所有参数的梯度缓存,然后进行随机梯度的反向传播:
    net.zero_grad()
    out.backward(torch.randn(1, 10))
  • 先开始不知道到这样做的目的是啥,问了同学,最后还问了老师,你敢信?
  • 后来啊,猛的一发现它是跟运行loss.backward()之后做了个比较,就是看了看计算损失函数之前的梯度和之后的梯度,也没啥太大意义。蒙了一下午,晕了,真的是。
  • 「torch.nn只支持小批量处理(mini-batches)。整个torch.nn包只支持小批量样本的输入,不支持单个样本的输入」

2.2 计算损失

  • 一个损失函数接受一对(output, target)作为输入,计算一个值来估计网络的输出和目标值相差多少
  • 常见的损失函数可参见几种常见的损失函数 [4]
  • 损失函数计算的是一个样本的损失,代价函数计算的是整个样本损失的平均值
    #计算损失,使用均方误差损失函数
    output = net(input)
    target = torch.randn(10)  # 本例子中使用模拟数据
    target = target.view(1, -1)  # 使目标值与数据值尺寸一致
    criterion = nn.MSELoss()

    loss = criterion(output, target)
    print(loss)
    
    #输出
    tensor(0.9866, grad_fn=<MseLossBackward>)

2.3 反向传播

  • 调用loss.backward()反向传播误差,查看conv1层的偏置(bias)在反向传播前后的梯度
  • 代码如下:
    net.zero_grad()     # 清零所有参数(parameter)的梯度缓存
    print('conv1.bias.grad before backward')
    print(net.conv1.bias.grad)
    loss.backward()
    print('conv1.bias.grad after backward')
    print(net.conv1.bias.grad)
    #输出
    conv1.bias.grad before backward
    tensor([0., 0., 0., 0., 0., 0.])
    conv1.bias.grad after backward
    tensor([-0.0003,  0.0005, -0.0140,  0.0026,  0.0057, -0.0056])

2.4 更新权重

  • 使用的更新规则:随机梯度下降算法(SGD)
  • 代码如下:
    learning_rate = 0.01
    for f in net.parameters():
        f.data.sub_(f.grad.data * learning_rate)
  • 常见的更新规则有:
    • Mini-batch梯度下降 [PyTorch] 笔记03:神经网络
    • 动量梯度下降法 Momentum [PyTorch] 笔记03:神经网络
    • RMSprop算法 [PyTorch] 笔记03:神经网络
    • Adam算法

下节写如何训练一个图片分类器

「欢迎批评指正,一起学习进步!!!」

Reference

[1]

PyTorch 1.4教程: https://pytorch.apachecn.org/docs/1.4/blitz/neural_networks_tutorial.html

[2]

pytorch实现mnist手写数字识别: https://www.jianshu.com/p/0504d5bfc26f

[3]

nn.Conv2d中groups参数的理解 python: https://blog.csdn.net/qq_39938666/article/details/89378096

[4]

几种常见的损失函数 : https://www.cnblogs.com/lliuye/p/9549881.html


以上是关于[PyTorch] 笔记03:神经网络的主要内容,如果未能解决你的问题,请参考以下文章

pytorch学习笔记:卷积神经网络CNN(进阶篇)

Pytorch学习笔记——多层感知机的实现

(d2l-ai/d2l-zh)《动手学深度学习》pytorch 笔记(序言pytorch的安装神经网络涉及符号)

快速上手笔记,PyTorch模型训练实用教程(附代码)

PyTorch学习笔记 4. 定义神经网络

PyTorch学习笔记 4. 定义神经网络