神经网络工具箱nn

手动实现一些深度学习的模型,需要编写的代码量很大。在这种情况下,torch.nn便应运而生。
这是专门为深度学习设计的模块,核心的数据结构是Module

  • 既可以表示神经网络中的某一层
  • 也可以表示一个包含很多层的神经网络

在实际编写神经网络的时候,一般都是继承nn.Module,然后再编写自己的网络

  • 自定义神经网络Net必须要继承nn.Module,并在构造函数中调用nn.Module的构造函数
  • 在构造函数__init__中必须定义自己可学习的参数
  • forward函数实现前向传播过程,其输入可以看作是一个或者多个Variable
  • 不用编写反向传播函数,nn.Module能够利用autograd自动实现反向传播
  • 可以将layer视为数学概念中的函数,通过调用layer(input)就可以得到对应的输出结果(虽然在调用函数的时候,主要的调用的是layer.forward(x),但是另外还对钩子做了处理。所以在实际使用中应要尽量使用layer(x),而不是layer.forward(x)
  • 输入的时候对输入的形状都有假设:输入的并不是单个数据,而是batch_size个数据。因此如果要想输入单个数据(比如测试的时候),必须先对数据升高一个维度,也就是调用unsqueeze(0)函数将数据伪装成batch_size=1的batch

    常用的神经网络层

    图像相关

    图像相关的神经网络层主要包括:

  • 卷积层(Conv)

  • 池化层(Pool)

这些层在实际使用中又可以分为一维、二维和三维,池化方式又可以分为平均池化(AvgPool)、最大值池化(MaxPool)和自适应池化(AdaptiveAvgPool)
示例如下:
假设我们现在想要将一张三通道的RGB图像转换为单通道灰度图像,然后对图像进行锐化操作

  1. from PIL import Image
  2. from torchvision.transforms import ToTensor, ToPILImage,Grayscale
  3. import torch as t
  4. from torch.autograd import Variable as V
  5. from torch import nn
  6. img = Image.open('imgs/icon.jpg') # 打开图片
  7. to_tensor = ToTensor() # 将图片转换为tensor的函数
  8. to_pil = ToPILImage() # 将tensor转换为实际的图片
  9. gray_scale = Grayscale(num_output_channels=1) # RGB三通道图像转单通道灰度图像
  10. pool = nn.AvgPool2d(2,2) # 平均池化层
  11. img

index.png
index.png
(左边是灰度处理后的图片,右边是原始图片)

  1. img = gray_scale(img) # 将图像转换为单通道
  2. input_data = to_tensor(img).unsqueeze(0) # 转换为tensor
  3. kernel = t.ones(3,3) / -9 # 定义锐化卷积核
  4. kernel[1][1] = 1
  5. conv = nn.Conv2d(1,1,(3,3),1,bias=False) # 卷积层
  6. conv.weight.data = kernel.view(1,1,3,3)
  7. out = pool(conv(V(input_data))) # 进行卷积
  8. to_pil(out.data.squeeze(0)) # 将卷积锐化后的图像展示

index.png(输出显示的是锐化后的图像)

池化层:用于图像的下采样,减少图片的特征
除了卷积层和池化层以外,图像相关的问题中还有用到以下几个层:

  • Linear:全连接层
  • BatchNorm:批规范化层,同样按照数据的类型分为1D、2D和3D
  • Dropout用来防止过拟合,同样分为1D、2D和3D

    激活函数

    激活函数通常用来给模型中的参数添加非线性的关系

Pytorch提供了一些已经实现好的激活函数,这些激活函数可以作为独立的layer来使用。
其中最常见的激活函数就是ReLU,数学表达式如下:
Pytorch - 图4
image.png
在上述神经网络中的各个层之间,都是将上一层的输出作为下一层的输入,这种网络被称为前馈神经网络
对于这种网络,如果不断重复的写复杂的forward函数显得有些冗余复杂,一般可以采用ModuleList或者Sequential来进行简化。

Sequential是一个特殊的Module,它包含几个子module,前向传播时会 将 输 入 一 层 接 一 层 地 传 递 下 去 。 ModuleList 也 是 一 个 特 殊 的 Module,可以包含几个子module,可以像用list一样使用它,但不能 直接把输入传给ModuleList。

image.png

循环神经网络

损失函数

在深度学习中要用到各种各样的损失函数(Loss Function),这些损失函数可以看做是一种特殊的layer,Pytorch将这些损失函数作为nn.Module的子类,在分类问题中使用较多的就是交叉熵损失CrossEntropyloss

优化器

Pytorch将深度学习中常用的优化方法全部封装到了torch.optim中,并且支持自定义参数,扩展成自定义的优化方法。
所有的优化方法都是继承于optim.Optimizer,并实现了自己的优化步骤,比较常见的优化方法是:

  • 随机梯度下降法(SGD)
  • 自适应矩估计法(Adam)

    nn.functional

    pytorch中,大多数的layerfunctional中都有一个与之对应的函数。
    nn.Moduleslayer都是通过class这种类的方式进行定义,能够提取可以学习的参数。而functional中的函数更像是纯函数,使用def function(input)来定义

    1. my_input = V(t.randn(2,3))
    2. model = nn.Linear(3,4)
    3. output1 = model(my_input)
    4. output2 = nn.functional.linear(my_input, model.weight, model.bias)
    5. output1 == output2

    如上代码所示,输出结果如下:
    image.png

    如果模型中有可以学习的参数,那么就使用nn.Module 反之,则两者都可以使用,取决于个人的爱好

  • 由于激活函数、池化等层没有可以学习的参数,可以使用对应的functional函数来代替使用

  • 而卷积、全连接等具有可学习参数的网络建议使用Model
  • dropout操作也没有可学习参数,但建议还是用nn.Dropout,因此在训练和测试的时候Dropout存在一定的差别,使用nn.Module对象可以通过model.eval来加以区分。

Pytorch中常用的工具

数据处理

torchvision

可视化