机器学习&&深度学习——torch.nn模块
- 卷积层
- 池化层
- 激活函数
- 循环层
- 全连接层
torch.nn模块包含着torch已经准备好的层,方便使用者调用构建网络。
卷积层
卷积就是输入和卷积核之间的内积运算,如下图:
容易发现,卷积神经网络中通过输入卷积核来进行卷积操作,使输入单元(图像或特征映射)和输出单元(特征映射)之间的连接时稀疏的,能够减少需要的训练参数的数量,从而加快网络计算速度。
卷积的分类如下所示,大体分为一维卷积、二维卷积、三位卷积以及转置卷积(简单理解为卷积操作的逆操作)
层对应的类 | 功能作用 |
---|---|
torch.nn.Conv1d() | 针对输入信号上应用1D卷积 |
torch.nn.Conv2d() | 针对输入信号上应用2D卷积 |
torch.nn.Conv3d() | 针对输入信号上应用3D卷积 |
torch.nn.ConvTranspose1d() | 在输入信号上应用1D转置卷积 |
torch.nn.ConvTranspose2d() | 在输入信号上应用2D转置卷积 |
torch.nn.ConvTranspose3d() | 在输入信号上应用3D转置卷积 |
以torch.nn.Conv2d()为例,介绍卷积在图像上的使用方法,其调用方式为:
torch.nn.Conv2d(in_channels,outchannels,kernel_size,stride=1,padding=0,dilation=1,groups=1,bias=True)
直接说前面三个参数吧,这三个是必选的参数,其他的参数作用可以看下面的这个文章:
torch.nn.Conv2d() 用法讲解
必选参数:
in_channels:输入的通道数目
out_channels:输出的通道数目
kernel_size:卷积核的大小,类型为int或元组,当卷积为方形时,只需要一个整形边长即可,否则要输入一个元组表示高和宽
现在我们针对一个二维图像来做卷积并观察结果:
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image# 使用PIL包读取图像数据,使用matplotlib包来可视化图像和卷积后的结果
# 读取图像->转化为灰度图像->转化为Numpy数组
myim = Image.open("data/chap2/yier.jpg")
myimgray = np.array(myim.convert("L"), dtype=np.float32)
# 可视化图片
plt.figure(figsize=(6, 6))
plt.imshow(myimgray, cmap=plt.cm.gray)
plt.axis("off")
# plt.show()# 上述操作得到一个512×512的数组,在卷积前,需要转化为1×1×512×512的张量
imh, imw = myimgray.shape
myimgray_t = torch.from_numpy(myimgray.reshape(1, 1, imh, imw))
# print(myimgray_t.shape)# 卷积时需将图像转化为四维来表示[batch,channel,h,w],卷积后得到两个特征映射:
# 第一个特征映射使用图像轮廓提取卷积核获取,第二个特征映射使用的卷积核为随机数
# 卷积核大小为5×5,且不使用0填充,则卷积后输出特征映射的尺寸为508×508
# 下面进行卷积,且对卷积后的两个特征映射进行可视化kersize = 5 # 定义边缘检测卷积核,并将维度处理为1*1*5*5
ker = torch.ones(kersize, kersize, dtype=torch.float32) * -1
ker[2, 2] = 24
ker = ker.reshape((1, 1, kersize, kersize))
# 此时ker矩阵为:
# tensor([[[[-1., -1., -1., -1., -1.],
# [-1., -1., -1., -1., -1.],
# [-1., -1., 24., -1., -1.],
# [-1., -1., -1., -1., -1.],
# [-1., -1., -1., -1., -1.]]]])
# 用意还是很好理解的,如果不再边缘上,那么乘积之和就是0,否则看结果正负也容易知道边缘所在的大概位置# 进行卷积操作
conv2d = nn.Conv2d(1, 2, (kersize, kersize), bias=False)
# 设置卷积时使用的核,第一个核使用边缘检测核
conv2d.weight.data[0] = ker
# 对灰度图像进行卷积操作
imconv2dout = conv2d(myimgray_t)
# 对卷积后的输出进行维度压缩
imconv2dout_im = imconv2dout.data.squeeze()
# print(imconv2dout_im.shape)
# 可视化卷积后的图像
plt.figure(figsize=(12, 12))
plt.subplot(2, 2, 1)
plt.imshow(myim)
plt.axis("off")
plt.subplot(2, 2, 2)
plt.imshow(myimgray, cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(2, 2, 3)
plt.imshow(imconv2dout_im[0], cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(2, 2, 4)
plt.imshow(imconv2dout_im[1], cmap=plt.cm.gray)
plt.axis("off")
plt.show()
结果:
可以看出,使用的边缘特征提取卷积核很好地提取出了图像的边缘信息。而使用随机数的卷积核得到的卷积结果与原始图像很相似。
池化层
池化的一个重要目的是对卷积后得到的特征进行进一步处理(主要是降维),池化层可以对数据进一步浓缩,从而缓解内存压力。
池化会选取一定大小区域,将该区域内的像素值用一个代表元素表示,如下图表示滑动窗口2×2,且步长为2时的最大值池化和平均值池化:
在pytorch中有多种池化的类,分别是最大值池化(MaxPool)、最大值池化的逆过程(MaxUnPool)、平均值池化(AvgPool)与自适应池化(AdaptiveMaxPool、AdaptiveAvgPool)等,且都提供了一二三维的池化操作。
如果对上一个卷积后的图像进行池化,并且使用步长为2的最大值池化或平均值池化以后,所得到的尺寸将会变为254×254。
如果使用nn.AdaptiveAvgPool2d()函数,构造时可以指定其池化后的大小。
池化后,特征映射的尺寸变小,图像变得更模糊。
激活函数
下面的一些函数感觉也都是很基础的,一些关于双曲正余弦函数、双曲正切函数、梯度的概念给搞懂了就没什么问题。
层对应的类 | 功能 |
---|---|
torch.nn.Sigmoid | Sigmoid激活函数 |
torch.nn.Tanh | Tanh激活函数 |
torch.nn.ReLU | ReLU激活函数 |
torch.nn.Softplus | ReLU激活函数的平滑近似 |
torch.nn.Sigmoid()
其对应的Sigmoid激活函数,又叫logistic激活函数:
f ( x ) = 1 1 + e − x f(x)=\frac{1}{1+e^{-x}} f(x)=1+e−x1
其输出在(0,1)这个开区间内,该函数在神经网络早期也是很常用的激活函数之一,但是当输入远离坐标源点时,函数的梯度就会变得很小,几乎为0,因此会影响参数的更新速度
torch.nn.Tanh()
对应双曲正切函数:
f ( x ) = e x − e − x e x + e − x f(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} f(x)=ex+e−xex−e−x
其输出区间在(-1,1)之间,整个函数以0为中心,虽然与Sigmoid一样,当输入很大或很小时,梯度很小,不利于权重的更新,但毕竟是以0为对称,使用效果会比Sigmoid好很多
torch.nn.ReLU()
其对应的ReLU函数又叫修正线性单元,计算方式为:
f ( x ) = m a x ( 0 , x ) f(x)=max(0,x) f(x)=max(0,x)
其只保留大于0的输出。而在输入正数时,不会存在梯度饱和的问题,计算速度会更快,而且因为ReLU函数只有线性关系,所以不管是前向传播还是反向传播都很快。
torch.nn.Softplus()
对应的平滑近似ReLU的激活函数,计算公式:
f ( x ) = 1 β l o g ( 1 + e β x ) f(x)=\frac{1}{β}log(1+e^{βx}) f(x)=β1log(1+eβx)
β默认为1。这个函数可以在任何位置求导数,且尽可能保留了ReLU函数的优点。
循环层
pytorch提供三种循环层实现:
层对应的类 | 功能 |
---|---|
torch.nn.RNN() | 多层RNN单元 |
torch.nn.LSTM() | 多层长短期记忆LSTM单元 |
torch.nn.GRU() | 多层门限循环GRU单元 |
torch.nn.RNNCell() | 一个RNN循环层单元 |
torch.nn.LSTMCell() | 一个长短期记忆LSTM单元 |
torch.nn.GRUCell() | 一个门限循环GRU单元 |
几个循环层函数的原理将在之后更新。
全连接层
指一个由多个神经元所组成的层,其所有的输出和该层的所有输入都有连接,即每个输入都会影响所有神经元的输出。
在pytorch中,nn.Linear()表示线性变换,全连接层可以看作是nn.Linear()表示线性变层再加上一个激活函数层所构成的结构。
nn.Linear()全连接操作及相关参数:
torch.nn.Linear(in_features,out_features,bias=True)
参数说明如下:
in_feature:每个输入样本的特征数量
out_feature:每个输出样本的特征数量
bias:若设置为False,则该层不会设置偏置,默认为True
torch.nn.Linear()的输入为(N,in_feature)的张量,输出为(N,out_feature)的张量。
全连接层的应用广泛,只有全连接层组成的网络是全连接神经网络,可用于数据的分类或回归预测,卷积神经网络和循环神经网络的末端,通常多个连接层组成。