PyTorch学习笔记的模型构建和模型的初始化
文章目录
- PyTorch学习笔记的模型构建和模型的初始化
-
- 2.3 模型构建
-
- 2.3.1 构建神经网络
- 2.3.2 基本介绍层结构
-
- 1)不含模型参数的层
- 2)含模型参数的层
- 3)卷积层
-
- a. 原理
- b. 代码
- c. 如何计算输出特征图的大小
- 4)反卷积
-
- a. 在双线插值上采样
- b. 转置卷积
- 5)池化层
-
- a. 原理
- b. 代码
- 6) 正则化层
-
- a. 原理
- b. 代码
- 7) 激活函数
-
- a. 原理
- b. 代码
- 8) 全连接层
- 2.3.3 模型举例
-
- 1)LeNet
- 2)AlexNet
- 2.4 模型初始化
-
- 2.4.1 `torch.nn.init`内容
- 2.4.2 `torch.nn.init`使用
- 2.4.3 包装初始函数
2.3 模型构建
2.3.1 构建神经网络
- Module类是nn模块中提供的模型结构类是所有神经网络模块的基本类别,可以继承它来定义模型
- 举例继承Module多层感知机的类结构
- 这里定义的MLP类重载了Module类的
init
函数(用于创建模型参数)和forward
函数(用于定义前向计算,即正向传播)
import torch from torch import nn class MLP(nn.Module): #声明了带有模型参数的层,这里声明了两个全连接层 def __init__(self, **kwargs): #调用MLP父类Block必要的初始化构造函数,以便在构造实例中指定其他函数 super(MLP, self).__init__(**kwargs) self.hidden = nn.Linear(784, 256) self.act = nn.ReLU() self.output = nn.Linear(256,10) #定义模型的前向计算,即如何根据输入x计算返回所需的模型输出 def forward(self, x): o = self.act(self.hidden(x)) return self.output(o)
- 以上的MLP类无需定义反向传播函数,系统将通过自动求梯度而自动生成反向传播所需的backward函数
- 实例化MLP类得到模型变量net
- 代码初始化net并传入输入数据 X 做一次前向运算
- 其中
net(X)
会调用MLP集成自Module类的call
函数,这个函数将调用MLP类定义的forward
函数来完成前向计算
X = torch.rand(2, 784)
net = MLP()
print(net)
net(X)
MLP(
(hidden): Linear(in_features=784, out_features=256, bias=True)
(act): ReLU()
(output): Linear(in_features=256, out_features=10, bias=True)
)
tensor([[ 0.0149, -0.2641, -0.0040, 0.0945, -0.1277, -0.0092, 0.0343, 0.0627,
-0.1742, 0.1866],
[ 0.0738, -0.1409, 0.0790, 0.0597, -0.1572, 0.0479, -0.0519, 0.0211,
-0.1435, 0.1958]], grad_fn=<AddmmBackward>)
- 注意:这里并未将Module类命名为层或者模型之类的名字,因为该类是一个可自由组建的部件,子类既可以是一个层(如PyTorch提供的Linear类),又可以是一个模型(如这里定义的 MLP 类),或者是模型的⼀个部分
2.3.2 层结构基本介绍
- 可以使用
torch.nn
包来构建神经网络。nn
包依赖autograd
包来定义模型并对它们求导。一个nn.Module
包含各个层和一个forward(input)
方法,该方法返回output
1)不含模型参数的层
- 下面构造的MyLayer类通过继承Module类自定义一个将输入减掉均值后输出的层,并将层的计算定义在forward函数里,这个层不含模型参数
import torch
from torch import nn
class MyLayer(nn.Module):
def __init__(self, **kwargs):
super(MyLayer, self).__init__(**kwargs)
def forward(self, x):
return x - x.mean()
- 测试,实例化该层,然后做前向计算
layer = MyLayer()
layer(torch.tensor([1, 2, 3, 4, 5]))
- 输出
tensor([-2., -1., 0., 1., 2.])
2)含模型参数的层
- 如果一个 Tensor 是 Parameter ,会自动被添加到模型的参数列表里。所以在自定义含模型参数的层时,我们应该将参数定义成 Parameter ,除了直接定义成 Parameter 类外,还可以使用 ParameterList 和 ParameterDict 分别定义参数的列表和字典
class MyListDense(nn.Module):
def __init__(self):
super(MyListDense, self).__init__()
self.params = nn.ParameterList([nn.Parameter(torch.randn(4, 4)) for i in range(3)])
self.params.append(nn.Parameter(torch.randn(4, 1)))
def forward(self, x):
for i in range(len(self.params)):
x = torch.mm(x, self.params[i])
return x
net = MyListDense()
print(net)
class MyDictDense(nn.Module):
def __init__(self):
super(MyDictDense, self).__init__()
self.params = nn.ParameterDict({
'linear1': nn.Parameter(torch.randn(4, 4)),
'linear2': nn.Parameter(torch.randn(4, 1))
})
self.params.update({
'linear3': nn.Parameter(torch.randn(4, 2))}) #新增
def forward(self, x, choice='linear1'):
return torch.mm(x, self.params[choice])
net = MyDictDense()
print(net)
3)卷积层
- 二维卷积层将输入和卷积核做互相关运算,并加上一个标量偏差来得到输出。模型参数包括卷积核和标量偏差。在训练模型时,通常先对卷积核随机初始化,然后不断迭代卷积核和偏差。
(1)注意卷积的计算方式方法,如何设置相应的参数
(2)步长和填充会影响最终输出特征图的尺寸
(3)特征图的计算公式:包含/不包含膨胀率
a. 原理
- 分类
- 离散
- 连续
- 实例
- 卷积核在数字图像上依次由左至右、由上至下滑动,将每次滑动的行数和列数称为步幅
- 取与卷积核大小相等的区域
- 逐像素相乘后再做加法运算
b. 代码
- 示例
#—————— 创建一个高和宽为3的二维卷积层,然后设输⼊高和宽两侧的填充数分别为1。给定一个高和宽为8的输入,我们发现输出的高和宽也是8 ——————#
import torch
from torch import nn
#定义一个函数来计算卷积层。它对输入和输出做相应的升维和降维
def comp_conv2d(conv2d, X):
# (1, 1)代表批量大小和通道数
X = X.view((1, 1) + X.shape)
Y = conv2d(X)
return Y.view(Y.shape[2:]) #排除不关心的前两维:批量和通道
# 注意这里是两侧分别填充1行或列,所以在两侧一共填充2行或列
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3,padding=1)
X = torch.rand(8, 8)
comp_conv2d(conv2d, X).shape
#—————— 更常见的卷积层写法 ——————#
import torch.nn as nn
conv_layer = nn.Conv2d(in_channels, out_channels,
kernel_size, stride=1,
padding=0, dilation=1,
groups=1, bias=True)
- 最基本的层结构指令:
- 具体参数包括输入通道、输出通道、卷积核、步长、膨胀率、组卷积、偏置
- 当卷积核的高和宽不同时,可以通过设置高和宽上不同的填充数使输出和输入具有相同的高和宽
# 使用高为5、宽为3的卷积核。在高和宽两侧的填充数分别为2和1
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
c. 如何计算输出特征图的大小
- 假设当前图像的大小为:Hin,Win
- 假设卷积核大小为FH、FW、个数为FN
- 填充数(padding)为P,可以增加输出的高和宽,常用来
- 步距(stride)为S,可以减小输出的高和宽
- 输出图像的大小为:Hout,Wout
- 输出图像的维度为:(FN,Hout,Wout)
- 其中Paddding如果取VALID模式,则p=0;如果取SAME,则p>0
- 不带有扩充卷积的公式1: H o u t = H i n + 2 P − F h S + 1 H_{out}=\frac{H_{in}+2P-Fh}{S}+1 Hout=SHin+2P−Fh+1
- 带有扩充卷积D(膨胀率≠0): H o = H i + 2 P − D ( F h − 1 ) − 1 S + 1 Ho=\frac{Hi+2P-D(Fh-1)-1}{S}+1 Ho=SHi+2P−D(Fh−1)−1+1
4)反卷积
反卷积是卷积的反向操作,pytorch中有两种反卷积方法
a. 双线性插值上采样
先获知四个顶点,再根据计算公式进行插值处理
- 公式
Q 11 = ( x 1 , y 1 ) , Q 12 = ( x 1 , y 2 ) Q_{11}=\left(x_{1}, y_{1}\right), \quad Q_{12}=\left(x_{1}, y_{2}\right) Q11=(x1,y1),Q12=(x1,y2) Q 21 = ( x 2 , y 1 ) , Q 22 = ( x 2 , y 2 ) Q_{21}=\left(x_{2}, y_{1}\right), \quad Q_{22}=\left(x_{2}, y_{2}\right) Q21=(x2,y1),Q22=(x2,y2)
→
f ( x , y 1 ) ≈ x 2 − x x 2 − x 1 f ( Q 11 ) + x − x 1 x 2 − x 1 f ( Q 21 ) f ( x , y 2 ) ≈ x 2 − x x 2 − x 1 f ( Q 12 ) + x − x 1 x 2 − x 1 f ( Q 22 ) f ( x 1 , y ) ≈ y 2 − y y 2 − y 1 f ( Q 11 ) + y − y 1 y 2 − y 1 f ( Q 21 ) f ( x 2 , y ) ≈ y 2 − y y 2 − y 1 f ( Q 12 ) + y − y 1 y 2 − y 1 f ( Q 22 ) \begin{array}{ll}f\left(x, y_{1}\right) \approx \frac{x_{2}-x}{x_{2}-x_{1}} f\left(Q_{11}\right)+\frac{x-x_{1}}{x_{2}-x_{1}} f\left(Q_{21}\right) & f\left(x, y_{2}\right) \approx \frac{x_{2}-x}{x_{2}-x_{1}} f\left(Q_{12}\right)+\frac{x-x_{1}}{x_{2}-x_{1}} f\left(Q_{22}\right) \\ f\left(x_{1}, y\right) \approx \frac{y_{2}-y}{y_{2}-y_{1}} f\left(Q_{11}\right)+\frac{y-y_{1}}{y_{2}-y_{1}} f\left(Q_{21}\right) & f\left(x_{2}, y\right) \approx \frac{y_{2}-y}{y_{2}-y_{1}} f\left(Q_{12}\right)+\frac{y-y_{1}}{y_{2}-y_{1}} f\left(Q_{22}\right)\end{array} f(x,y1)≈x2−x1x2−xf(Q11)+x2−x1x−x1f(Q21)f(x1,y)≈y2−y1y2−yf(Q11)+y2−y1