Pytorch Tutorial
基础元素 Tensor
Tensor 是 PyTorch 中的一个基础数据结构,和 numpy 中的 ndarray 非常相近,我们使用 tensors 去编码输入和输出,还有模型参数。
生成操作
1 |
|
Tensor 属性
1 |
|
Tensor 操作
1 |
|
和 Numpy 的关联
1 |
|
数据处理
PyTorch 处理数据有两个前提:torch.utils.data.Dataset
和 torch.utils.data.DataLoader
。Dataset
存储样本和它们对应的标签,DataLoader
对 Dataset
绑定迭代轮数。
数据集
torchvision.datasets
模块包含许多真实世界图像数据如 CIFAR, COCO (full list here)。
所有数据集都是 torch.utils.data.Dataset
的子类,也就是说,它们都有 __getitem__
和 __len__
这两个API。所以,它们可以通过 torch.multiprocessing
给 torch.utils.data.DataLoader
传递多个样本实现多线程。
所有数据集都有类似的API。它们有两个共同参数 transform
和 target_transform
来分别转换 input 和 target。可以通过提供的 base classes 创建自己的数据集。
导入官方提供数据集
此处以 ImageNet ILSVRC2012
数据集举例,但 PyTorch 不提供 ImageNet 数据集的下载,需要自己下载数据集后放在root路径,此处放在 ./dataset
路径下。如果 PyTorch 有提供数据集下载,download=True
后会将数据集下载在 root
路径下。
1 |
|
创建自定义数据集
Dataset
类的部分内容如下:
1 |
|
子类继承父类 Dataset
时,必须重写 __getitem__
和 __len__
方法,否则将会报错。
其中 __getitem__
实现通过索引来返回图像数据的功能,__len__
返回数据集的大小。
要自定义数据集,首先要继承 Dataset
类,然后在 __init__
方法中对数据进行整理,给图片打标签,划分数据集等等。
Example:
1 |
|
DataLoader
Dataset
每次检索提供一个样本和一个标签,在训练模型时,我们通常通过 minibatches 来取数据集,在每个 epoch 重新打乱数据来避免模型过拟合,并且使用 Python 的 multiprocessing
对数据检索加速。
DataLoader 类的定义如下:
1 |
|
Example:
1 |
|
变换 (Transforms)
由于大多数据在进行训练之前都需要进行处理,PyTorch 内置了一些函数,来方便用户对图像等数据进行处理。
以下提到的类都在 torchvision.transforms
下,例如 torchvision.transforms.Compose
裁剪
CenterCrop
将给定的 PIL.Image
进行中心切割,得到给定的 size。 size 可以是一个 tuple ([height, width]),也可以是一个整数,在整数的情况下,切割出来的图片形状是正方形。
1 |
|
RandomCrop
切割中心点的位置随便选取,根据给定的 size 进行切割,具体参数如下。
- size:可以是 tuple 也可以是整数。
- padding:设置填充多少个 pixel。当为
int
时,图像上下左右均填充int
个,若有两个数,则第一个数为左右扩充多少,第二个数表示上下的。当有 4 个数时,则为 左、上、右、下 各填充多少个。 - fill:填充的值 (仅当填充 mode 为 ‘constant’ 时有效。当为
int
时,各通道均填充该值,当为 [r, g, b] tuple 时,表示RGB通道分别填充的值。 - padding_mode:有 4 种填充模式:
- constant 常量。
- edge 按照图片边缘像素值填充。
- reflect 。以边缘值为中心做镜面对称,如 [1, 2, 3, 4] 边缘扩充一个值,结果为 [2, 1, 2, 3, 4, 3]。
- symmetric。以边缘为中心做镜面对称,如 [1, 2, 3, 4] 边缘扩充一个值,结果为 [1, 1, 2, 3, 4, 4]。
1 |
|
RandomResizedCrop
随机长宽比裁剪,之后再将图片 resize 到给定的 size。
- size:可以是 tuple 也可以是整数。
int
不支持,要用长度为1的序列 [size, ]。 - scale: float 的 tuple。指定随机 crop 的比例区间,如 0.08x~1.0x。
- ratio: float的tuple。随机长宽比范围设置,如 0.75~1.33。
- interpolation:插值方法。默认为双线性插值。由
torchvision.transforms.InterpolationMode
定义。如输入为 Tensor,只有InterpolationMode.NEAREST
,InterpolationMode.BILINEAR
和InterpolationMode.BICUBIC
可用。
1 |
|
FiveCrop
将给定图片裁剪成 4 张边角图片和 1 张中心图片。如果输入图片是 torch.Tensor
,则 expected shape 为 [d, H, W]
,其中 d 为指示维度的数。
- size:可以是 tuple 也可以是整数。
1 |
|
TenCrop
将给定的图片裁剪成 4 张边角图片和 1 张中心图片,然后全部翻转 (默认水平翻转)。如果输入图片是 torch.Tensor
,则 expected shape 为 [d, H, W]
,其中 d 为指示维度的数。
- size:可以是 tuple 也可以是整数。
- vertical_flip:使用水平翻转或竖直翻转。
True
垂直翻转,False
水平翻转。
1 |
|
翻转和旋转
RandomHorizontalFlip
根据给定概率 p 进行水平翻转。如果输入图片是 torch.Tensor
,则 expected shape 为 [d, H, W]
,其中 d 为指示维度的数。
1 |
|
RandomVerticalFlip
根据给定概率 p 进行垂直翻转。如果输入图片是 torch.Tensor
,则 expected shape 为 [d, H, W]
,其中 d 为指示维度的数。
1 |
|
RandomRotation
根据角度旋转图片。如果输入图片是 torch.Tensor
,则 expected shape 为 [d, H, W]
,其中 d 为指示维度的数。
- degrees:旋转角度。如果不是序列 $(min, max)$,则角度范围为 $(-degrees, +degrees)$
- interpolation:插值方法。默认为
NEAREST
。由torchvision.transforms.InterpolationMode
定义。如输入为 Tensor,只有InterpolationMode.NEAREST
,InterpolationMode.BILINEAR
和InterpolationMode.BICUBIC
可用。 - expand:
true
则填充到足够覆盖整个旋转后的图像,false
则使输出图像和输入图像大小一致。 - fill:旋转后的图像外面的区域填充的值,默认为0。
1 |
|
图像变换
Resize
把图像 Resize 成给定的 size。
- size:(sequence or int) 期望输出 size。如果 size=(h, w),则输出降为匹配的 size,如果 size 是一个
int
,将会把较小的边设置为该值。也就是说,如果 height > width,那么图片将会 rescale 成 (size * height / width, size)。 - interpolation:插值方法。默认为
BILINEAR
。由torchvision.transforms.InterpolationMode
定义。如输入为 Tensor,只有InterpolationMode.NEAREST
,InterpolationMode.BILINEAR
和InterpolationMode.BICUBIC
可用。
1 |
|
Normalize
用平均值和均方差归一化 Tensor 图像。
该方法不能被用于 PIL 图像。
给出 n 个 channel 的 (mean[1],...,mean[n])
和 (std[1],..,std[n])
,该方法将依次归一化每个 channel,也就是 output[channel] = (input[channel] - mean[channel]) / std[channel]
。
- mean:每个 channel 的均值。
- std:每个 channel 的均方差。
- inplace:是否采用
in-place
。
1 |
|
ToTensor
将 PIL Image
或者 numpy.ndarray
转换为 tensor
。
将 [0, 255] 范围内的 $(H\times W\times C)$ 转换为 [0.0, 1.0] 范围内的 $(C\times H\times W)$ torch.FloatTensor
。
PIL Image
应该是 (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1) 之中的一种模式, numpy.ndarray
的 dtype = np.uint8
。
1 |
|
ToPILImage
将 tensor
或者 ndarray
转换成 PIL Image
。
将 $(C\times H\times W)$ 的 Tensor
转换为 $(H\times W\times C)$ 的 PIL Image
。、
mode
可以参考 Pillow 官网 上的色彩空间。
- mode:
PIL Image
的色彩空间,如果mode=None
,则会根据输入数据进行适配input channel=4
,mode=RGBA
input channel=3
,mode=RGB
input channel=2
,mode=LA
input channel=1
,mode
由数据类型,也就是int
,float
,short
决定。
1 |
|
Pad
使用给定的 padding
值填充给定的图像。
如果 image 是 Tensor
,它的大小应该是 $[d, H, W]$。对于 reflect
和 symmetric
mode来说,最多 2 维,对于 edge
mode 来说,最多 3 维,对于 constant
mode 来说,可以是任意维度。
- padding:设置填充多少个 pixel。当为
int
时,图像上下左右均填充int
个,若有两个数,则第一个数为左右扩充多少,第二个数表示上下的。当有 4 个数时,则为 左、上、右、下 各填充多少个。 - fill:填充的值 (仅当填充 mode 为 ‘constant’ 时有效。当为
int
时,各通道均填充该值,当为 [r, g, b] tuple 时,表示RGB通道分别填充的值。 - padding_mode:有 4 种填充模式:
- constant 常量。
- edge 按照图片边缘像素值填充。
- reflect 。以边缘值为中心做镜面对称,如 [1, 2, 3, 4] 边缘扩充一个值,结果为 [2, 1, 2, 3, 4, 3]。
- symmetric。以边缘为中心做镜面对称,如 [1, 2, 3, 4] 边缘扩充一个值,结果为 [1, 1, 2, 3, 4, 4]。
1 |
|
ColorJitter
修改亮度,对比度,饱和度还有色调。
如果 image 是 Tensor
,它的大小应该是 $[\dots, 3, H, W]$,$\dots$ 是维度。
- brightness:浮点数 或 (min, max) 的 tuple,亮度的抖动。brightness_factor 从 [max(0, 1 - brightness), 1 + brightness] 或者 [min, max] 中均匀选择。应该是非负数。
- contrast:浮点数 或 (min, max) 的 tuple,对比度的抖动。contrast_factor 从 [max(0, 1 - contrast), 1 + contrast] 或者 [min, max] 中均匀选择。应该是非负数。
- saturation:浮点数 或 (min, max) 的 tuple,饱和度的抖动。saturation_factor 从 [max(0, 1 - saturation), 1 + saturation] 或者 [min, max] 中均匀选择。应该是非负数。
- hue:浮点数 或 (min, max) 的 tuple,色调的抖动。hue_factor 从 [-hue, hue] 或者 [min, max] 中均匀选择。应该
0<= hue <= 0.5
或者-0.5<= min <= max <=0.5
。
1 |
|
Grayscale
将图片转换为灰度图。
如果 image 是 Tensor
,它的大小应该是 $[\dots,3,H,W]$,$\dots$ 是维度。
- num_output_channels:(1 或者 3) 输出图像的通道数量。
num_output_channels == 1
:返回单通道图像。num_output_channels == 3
:返回r==g==b
的 3 通道图像。
1 |
|
RandomGrayscale
根据概率 p 将图片转为灰度图。
如果 image 是 Tensor
,它的大小应该是 $[\dots,3,H,W]$,$\dots$ 是维度。
如果输入图像为单通道,则返回单通道,如果为 3 通道,则返回 r==g==b
的 3 通道灰度图。
1 |
|
LinearTransformation
用方阵和偏移量的 mean_vector 来做线性变换,可用于白化处理。
给定 transformation_matrix
和 mean_vector
,会先将 Tensor
展平并从中减去 mean_vector
,然后用 transformation_matrix
计算点积,最后将 Tensor
重塑为之前的 shape。
- transformation_matrix:$[D\times D]$ 的
Tensor
,$D = C\times H\times W$。 - mean_vector:$[D]$ 的
Tensor
,$D=C\times H\times W$。
1 |
|
RandomAffine
图像保持中心不变的随机仿射变换。
如果 image 是 Tensor
,它的大小应该是 $[\dots,H,W]$,$\dots$ 是维度。
- degrees:旋转选择角度的范围。如果角度为一个值,则范围为 (-degrees, +degrees)。tuple 情况下范围为 (min, max)。如果
degrees=0
,则停用旋转。 - translate:水平和垂直平移的最大绝对比例的 tuple。如
translate=(a, b)
,那么水平平移在-img_width * a < dx < img_width * a
范围内随机选择,垂直平移在-img_height * b < dy < img_height * b
范围内随机选择。默认则不会偏移。 - scale:放缩的范围区间。如
(a, b)
,则范围为a<= scale <= b
,默认保持原大小。 - shear:错切选择角度的范围。如果
shear
是一个数字,则平行于 x 轴的错切范围为 (-shear, +shear)。如果shear
是一个包含两个数字的序列,则平行于 x 轴的错切范围为 (shear[0], shear[1])。如果shear
是一个包含 4 个数字的序列,那么平行于 x 轴的错切范围为 (shear[0], shear[1]),平行于 y 轴的错切范围为 (shear[2], shear[3])。默认不会应用错切。 - interpolation:插值方法。默认为
NEAREST
。由torchvision.transforms.InterpolationMode
定义。如输入为 Tensor,InterpolationMode.NEAREST
和InterpolationMode.BILINEAR
可用。 - fill:区域外填充的值,默认是 0 。
1 |
|
Transform 组合操作
Compose
将多个 transform 组合起来使用。
1 |
|
RandomChoice
应用从列表中随机选择的单个转换。
1 |
|
RandomApply
给一个 transform 加上概率,以一定的概率执行该操作。
1 |
|
RandomOrder
将 transforms 中的操作顺序随机打乱。
1 |
|
Lambda Transforms
还不了解,待补充。
构建模型
神经网络由对数据执行操作的层/模块组成。torch.nn
命名空间提供了构建自己的神经网络所需的所有构建块。 PyTorch 中的每个模块都是 nn.Module
的子类。 神经网络是一个模块本身,它由其他模块(层)组成。 这种嵌套结构允许轻松构建和管理复杂的架构。
设置训练设备
1 |
|
定义网络类
我们使用子类 nn.Module
定义自己的神经网络,然后在 __init__
中初始化网络层。每个 nn.Module
子类都在 forward
方法中实现对输入数据的操作。
1 |
|
模型 Layers
Containers
torch.nn.Module
是所有网络的基类,我们的模型也应该继承这个类。
模块添加和迭代
add_module(name, module)
将一个
child module
添加到当前module
。被添加的module
可以通过name
属性获取。1
2
3
4
5
6
7
8import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.add_module("conv", nn.Conv2d(10, 20, 4))
#self.conv = nn.Conv2d(10, 20, 4) 和上面这个增加module的方式等价
model = Model()
print(model.conv)modules()
返回一个包含 当前模型 所有模块的迭代器。
1
2
3
4
5
6
7
8
9
10import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.add_module("conv", nn.Conv2d(10, 20, 4))
self.add_module("conv1", nn.Conv2d(20 ,10, 4))
model = Model()
for module in model.modules():
print(module)children()
返回当前模型 子模块 的迭代器。
named_children()
返回 包含 模型当前子模块 的迭代器,包含模块名字和模块本身。
1
2
3for name, module in model.named_children():
if name in ['conv4', 'conv5']:
print(module)
模块设备管理
cpu(device_id=None)
将所有的模型参数
parameters
和buffers
复制到 CPU。cuda(device_id=None)
将所有的模型参数
parameters
和buffers
复制给 GPU。
模块数据类型
double()
将
parameters
和buffers
的数据类型转换为double
。float()
将
parameters
和buffers
的数据类型转换为float
。half()
将
parameters
和buffers
的数据类型转换为half
。
字典查看和导入
state_dict()
返回一个字典,保存着
module
的所有状态(state
)。parameters
和persistent buffers
都会包含在字典中,字典的key
就是parameter
和buffer
的names
。1
2
3
4
5
6
7
8
9
10
11
12
13
14import torch
from torch.autograd import Variable
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv2 = nn.Linear(1, 2)
self.vari = Variable(torch.rand([1]))
self.par = nn.Parameter(torch.rand([1]))
self.register_buffer("buffer", torch.randn([2,3]))
model = Model()
print(model.state_dict().keys())load_state_dict(state_dict)
将
state_dict
中的parameters
和buffers
复制到此module
和它的后代中。state_dict
中的key
必须和model.state_dict()
返回的key
一致。
网络训练,梯度,前向传播
forward(*input)
定义了每次执行的 计算步骤。 在所有的子类中都需要重写这个函数。
train(mode=True)
将
module
设置为training mode
。仅仅当模型中有Dropout
和BatchNorm
时才会有影响。zero_grad()
将
module
中的所有模型参数的梯度设置为0.
容器类 Sequential, ModuleList, ParameterList
torch.nn.Sequential(* args)
一个时序容器。
Modules
会以他们传入的顺序被添加到容器中。当然,也可以传入一个OrderedDict
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# Example of using Sequential
model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))torch.nn.ModuleList(modules=None)
将
submodules
保存在一个list
中。ModuleList
可以像一般的Python list
一样被索引
。而且ModuleList
中包含的modules
已经被正确的注册,对所有的module method
可见。1
2
3
4
5
6
7
8
9
10class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])
def forward(self, x):
# ModuleList can act as an iterable, or be indexed using ints
for i, l in enumerate(self.linears):
x = self.linears[i // 2](x) + l(x)
return xappend(module)
等价于 list 的
append()
。
torch.nn.ParameterList(parameters=None)
将
submodules
保存在一个list
中。ParameterList
可以像一般的Python list
一样被索引
。而且ParameterList
中包含的parameters
已经被正确的注册,对所有的module method
可见。1
2
3
4
5
6
7
8
9
10class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.params = nn.ParameterList([nn.Parameter(torch.randn(10, 10)) for i in range(10)])
def forward(self, x):
# ModuleList can act as an iterable, or be indexed using ints
for i, p in enumerate(self.params):
x = self.params[i // 2].mm(x) + p.mm(x)
return xappend(parameter)
等价于 list 的
append()
。
卷积层
X维卷积
卷积操作。
$N$ 为 batch size
,$C$ 为 channel
数量,$L$ 为信号序列的长度。
可使用的为 1-3
维的卷积层,函数如下:
torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
输入: $(N,C_{in},L_{in})$
输出: $(N,C_{out},L_{out})$
$L_{out}$ 的 Shape 为:
$$L_{out}=floor((L_{in}+2padding-dilation(kernerl_size-1)-1)/stride+1)$$
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
输入: $(N,C_{in},H_{in},W_{in})$
输出: $(N,C_{out},H_{out},W_{out})$
$H_{out}$ 和 $W_{out}$ 的 Shape 为:
$$H_{out}=floor((H_{in}+2padding[0]-dilation[0](kernerl_size[0]-1)-1)/stride[0]+1)$$
$$W_{out}=floor((W_{in}+2padding[1]-dilation[1](kernerl_size[1]-1)-1)/stride[1]+1)$$
torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
输入: $(N,C_{in},D_{in},H_{in},W_{in})$
输出: $(N,C_{out},D_{out},H_{out},W_{out})$
$D_{out}, H_{out}, W_{out}$ 的 Shape 为:
$$D_{out}=floor((D_{in}+2padding[0]-dilation[0](kernerl_size[0]-1)-1)/stride[0]+1)$$
$$H_{out}=floor((H_{in}+2padding[1]-dilation[1](kernerl_size[1]-1)-1)/stride[1]+1)$$
$$W_{out}=floor((W_{in}+2padding[2]-dilation[2](kernerl_size[2]-1)-1)/stride[2]+1)$$
输入输出的计算方式:
$$ out(N_i, C_{out_j})=bias(C_{out_j})+\sum^{C_{in}-1}{k=0}weight(C{out_j},k)\bigotimes input(N_i,k) $$
其中 $\bigotimes$ 为 cross-correlation
操作符。
参数及其意义为:
- in_channels(
int
) – 输入信号的通道 - out_channels(
int
) – 卷积产生的通道 - kerner_size(
int
ortuple
) - 卷积核的尺寸 - stride(
int
ortuple
,optional
) - 卷积步长 - padding(
int
ortuple
,optional
) - 输入的每一条边补充0的层数 - dilation(
int
ortuple
,optional
) – 卷积核元素之间的间距 - groups(
int
,optional
) – 从输入通道到输出通道的阻塞连接数groups=1
,所有输出由输入卷积得到groups=2
,将输入channel
平分成两份,卷积后进行concat
操作groups=in_channels
,所有input_channel
都由自己的滤波器进行卷积,大小为out_channels/in_channels
- bias(
bool
,optional
) - 如果bias=True
,添加偏置
转置卷积
反卷积操作,相当于使用空洞卷积进行上采样。
$N$ 为 batch size
,$C$ 为 channel
数量,$L$ 为信号序列的长度。
可使用的为 1-3
维的卷积层,函数如下:
torch.nn.ConvTranspose1d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1)
输入: $(N,C_{in},L_{in})$
输出: $(N,C_{out},L_{out})$
$L_{out}$ 的 Shape 为:
$$L_{out}=(L_{in}-1)stride-2padding+dilation\times(kernel_size-1)+output_padding+1$$
torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1)
输入: $(N,C_{in},H_{in},W_{in})$
输出: $(N,C_{out},H_{out},W_{out})$
$H_{out}$ 和 $W_{out}$ 的 Shape 为:
$$H_{out}=(H_{in}-1)stride[0]-2padding[0]+dilation[0]\times (kernel_size[0]-1)+output_padding[0]+1$$
$$W_{out}=(W_{in}-1)stride[1]-2padding[1]+dilation[1]\times(kernel_size[1]-1)+output_padding[1]+1$$
torch.nn.ConvTranspose3d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1)
输入: $(N,C_{in},D_{in},H_{in},W_{in})$
输出: $(N,C_{out},D_{out},H_{out},W_{out})$
$D_{out}, H_{out}, W_{out}$ 的 Shape 为:
$$D_{out}=(D_{in}-1)stride[0]-2padding[0]+dilation[0]\times(kernel_size[0]-1)+output_padding[0]+1$$
$$H_{out}=(H_{in}-1)stride[1]-2padding[1]+dilation[1]\times(kernel_size[1]-1)+output_padding[1]+1$$
$$W_{out}=(W_{in}-1)stride[2]-2padding[2]+dilation[2]\times(kernel_size[2]-1)+output_padding[2]+1$$
池化层
Maxpool
$N$ 为 batch size
,$C$ 为 channel
数量。
可使用的为 1-3
维的池化层,函数如下:
torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
输入: $(N,C_{in},L_{in})$
输出: $(N,C_{out},L_{out})$
$L_{out}$ 的 Shape 为:
$$L_{out}=floor((L_{in} + 2padding - dilation(kernel_size - 1) - 1)/stride + 1)$$
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
输入: $(N,C_{in},H_{in},W_{in})$
输出: $(N,C_{out},H_{out},W_{out})$
$H_{out}$ 和 $W_{out}$ 的 Shape 为:
$$H_{out}=floor((H_{in} + 2padding[0] - dilation[0](kernel_size[0] - 1) - 1)/stride[0] + 1)$$
$$W_{out}=floor((W_{in} + 2padding[1] - dilation[1](kernel_size[1] - 1) - 1)/stride[1] + 1)$$
torch.nn.MaxPool3d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
输入: $(N,C_{in},D_{in},H_{in},W_{in})$
输出: $(N,C_{out},D_{out},H_{out},W_{out})$
$D_{out}, H_{out}, W_{out}$ 的 Shape 为:
$$D_{out}=floor((D_{in} + 2padding[0] - dilation[0](kernel_size[0] - 1) - 1)/stride[0] + 1)$$
$$H_{out}=floor((H_{in} + 2padding[1] - dilation[1](kernel_size[1] - 1) - 1)/stride[1] + 1)$$
$$W_{out}=floor((W_{in} + 2padding[2] - dilation[2](kernel_size[2] - 1) - 1)/stride[2] + 1)$$
MaxUnpool
Maxpool
的逆过程,不过并不是完全的逆过程,因为在maxpool
的过程中,一些值已经丢失。 MaxUnpool
输入MaxPool
的输出,包括最大值的索引,并计算所有maxpool
过程中非最大值被设置为零的部分的反向。
torch.nn.MaxUnpool1d(kernel_size, stride=None, padding=0)
torch.nn.MaxUnpool2d(kernel_size, stride=None, padding=0)
torch.nn.MaxUnpool3d(kernel_size, stride=None, padding=0)
AvgPool
平均池化。
torch.nn.AvgPool1d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
torch.nn.AvgPool2d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
torch.nn.AvgPool3d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
参数:
- kernel_size(
int
ortuple
) - 池化窗口大小 - stride(
int
ortuple
,optional
) - max pooling的窗口移动的步长。默认值是kernel_size
- padding(
int
ortuple
,optional
) - 输入的每一条边补充0的层数 - dilation(
int
ortuple
,optional
) – 一个控制窗口中元素步幅的参数 - ceil_mode - 如果等于
True
,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作 - count_include_pad - 如果等于
True
,计算平均池化时,将包括padding
填充的0
非线性激活层
torch.nn.ReLU(inplace=False)
表达式:${ReLU}(x)= max(0, x)$
torch.nn.Sigmoid()
表达式:$f(x)=1/(1+e^{-x})$
torch.nn.Tanh()
表达式:$f(x)=\frac{exp(x)-exp(-x)}{exp(x)+exp(-x)}$
torch.nn.Softmax()
表达式:$f(x_i)=\frac{exp(x_i)}{\sum_j exp(x_j)}$
torch.nn.LeakyReLU(negative_slope=0.01, inplace=False)
表达式:$f(x) = max(0, x) + {negative_slope} * min(0, x)$
- negative_slope:控制负斜率的角度,默认等于0.01
torch.nn.ELU(alpha=1.0, inplace=False)
表达式:$f(x) = max(0,x) + min(0, alpha * (e^x - 1))$
torch.nn.Threshold(threshold, value, inplace=False)
表达式:$y=x, if ,,, x>=threshold;,, y=value, if,,,x<threshold$
- threshold:阈值
- value:输入值小于阈值则会被value代替
Normalization 层
BatchNorm
对 mini-batch 的输入进行 Batch Normalization 操作:
$$y=\frac{x-mean[x]}{\sqrt{Var[x]}+\epsilon}\times gamma+\beta$$
在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)
在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。
在验证时,训练求得的均值/方差将用于标准化验证数据。
torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True)
torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True)
torch.nn.BatchNorm3d(num_features, eps=1e-05, momentum=0.1, affine=True)
参数:
- num_features: 来自期望输入的特征数。
- eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
- momentum: 动态均值和动态方差所使用的动量。默认为0.1。
- affine: 一个布尔值,当设为true,给该层添加可学习的仿射变换参数。
Recurrent 层
RNN
torch.nn.RNN( *args,* * kwargs)
将一个多层的 Elman RNN
,激活函数为 tanh
或者 ReLU
,用于输入序列。
对输入序列中每个元素,RNN
每层的计算公式为 $$ h_t=tanh(W_{ih}x_t+b_{ih}+W_{hh}h_{t-1}+b_{hh}) $$ $h_t$是时刻$t$的隐状态。 $x_t$是上一层时刻$t$的隐状态,或者是第一层在时刻$t$的输入。如果 nonlinearity='relu'
,那么将使用 relu
代替 tanh
作为激活函数。
参数:
- input_size – 输入
x
的特征数量。 - hidden_size – 隐层的特征数量。
- num_layers – RNN的层数。
- nonlinearity – 指定非线性函数使用
tanh
还是relu
。默认是tanh
。 - bias – 如果是
False
,那么RNN层就不会使用偏置权重 $b_ih$和$b_hh$,默认是True
- batch_first – 如果
True
的话,那么输入Tensor
的shape应该是[batch_size, time_step, feature],输出也是这样。 - dropout – 如果值非零,那么除了最后一层外,其它层的输出都会套上一个
dropout
层。 - bidirectional – 如果
True
,将会变成一个双向RNN
,默认为False
。
LSTM
torch.nn.LSTM( *args,* * kwargs)
将一个多层的 (LSTM)
应用到输入序列。
对输入序列的每个元素,LSTM
的每层都会执行以下计算:
$$
\begin{aligned} i_t &=sigmoid(W_{ii}x_t+b_{ii}+W_{hi}h_{t-1}+b_{hi}) \ f_t &= sigmoid(W_{if}x_t+b_{if}+W_{hf}h_{t-1}+b_{hf}) \ o_t &= sigmoid(W_{io}x_t+b_{io}+W_{ho}h_{t-1}+b_{ho})\ g_t &= tanh(W_{ig}x_t+b_{ig}+W_{hg}h_{t-1}+b_{hg})\ c_t &= f_t\odot c_{t-1}+i_t\odot g_t\ h_t &= o_t\odot tanh(c_t) \end{aligned}
$$
$h_t$是时刻$t$的隐状态,$c_t$是时刻$t$的细胞状态,$x_t$是上一层的在时刻$t$的隐状态或者是第一层在时刻$t$的输入。$i_t, f_t, g_t, o_t$ 分别代表 输入门,遗忘门,细胞和输出门。
参数:
- input_size – 输入的特征维度
- hidden_size – 隐状态的特征维度
- num_layers – 层数(和时序展开要区分开)
- bias – 如果为
False
,那么LSTM
将不会使用$b_{ih},b_{hh}$,默认为True
。 - batch_first – 如果为
True
,那么输入和输出Tensor
的形状为(batch, seq, feature)
- dropout – 如果非零的话,将会在
RNN
的输出上加个dropout
,最后一层除外。 - bidirectional – 如果为
True
,将会变成一个双向RNN
,默认为False
。
Transformer 层
nn.Transformer
一个基于 “Attension is All You Need” 实现的 Transformer 模型。
1 |
|
参数:
- d_model – the number of expected features in the encoder/decoder inputs (default=512).
- nhead – the number of heads in the multiheadattention models (default=8).
- num_encoder_layers – the number of sub-encoder-layers in the encoder (default=6).
- num_decoder_layers – the number of sub-decoder-layers in the decoder (default=6).
- dim_feedforward – the dimension of the feedforward network model (default=2048).
- dropout – the dropout value (default=0.1).
- activation – the activation function of encoder/decoder intermediate layer, can be a string (“relu” or “gelu”) or a unary callable. Default: relu
- custom_encoder – custom encoder (default=None).
- custom_decoder – custom decoder (default=None).
- layer_norm_eps – the eps value in layer normalization components (default=1e-5).
- batch_first – If
True
, then the input and output tensors are provided as (batch, seq, feature). Default:False
(seq, batch, feature). - norm_first – if
True
, encoder and decoder layers will perform LayerNorms before other attention and feedforward operations, otherwise after. Default:False
(after).
nn.TransformerEncoder
由 N 个 encoder 层堆叠形成的 TransformerEncoder。
torch.nn.TransformerEncoder(encoder_layer, num_layers, norm=None)
参数:
- encoder_layer – an instance of the TransformerEncoderLayer() class (required).
- num_layers – the number of sub-encoder-layers in the encoder (required).
- norm – the layer normalization component (optional).
nn.TransformerDecoder
由 N 个 decoder 层堆叠形成的 TransformerDecoder。
torch.nn.TransformerDecoder(decoder_layer, num_layers, norm=None)
参数:
- decoder_layer – an instance of the TransformerDecoderLayer() class (required).
- num_layers – the number of sub-decoder-layers in the decoder (required).
- norm – the layer normalization component (optional).
Linear 层
Linear
torch.nn.Linear(in_features, out_features, bias=True)
对输入数据做线性变换:$y=Ax+b$。
参数:
- in_features - 每个输入样本的大小
- out_features - 每个输出样本的大小
- bias - 若设置为False,这层不会学习偏置。默认值:True
形状:
- 输入: $(N,in_features)$
- 输出: $(N,out_features)$
Bilinear
torch.nn.Bilinear(in1_features, in2_features, out_features, bias=True)
对输入数据做双线性变换:$y=x_1^TAx_2+b$。
参数:
- in1_features – size of each first input sample
- in2_features – size of each second input sample
- out_features – size of each output sample
- bias – If set to False, the layer will not learn an additive bias. Default:
True
Dropout 层
X 维 Dropout
torch.nn.Dropout(p=0.5, inplace=False)
torch.nn.Dropout2d(p=0.5, inplace=False)
torch.nn.Dropout3d(p=0.5, inplace=False)
输入输出形状参照 卷积层—X 维卷积。
训练
Optimization
每次优化循环的迭代为一个 epoch
。
每个 epoch
由以下两个重要部分组成:
- The Train Loop - 在训练数据集上迭代以收敛到最优参数。
- The Validation/Test Loop - 在测试集上测试来检查模型性能是否有提升。
Loss Function
对于回归任务来说,常用的 loss function 包括均方误差 nn.MSELoss
,对于分类任务来说,Negative Log Likehood nn.NLLLoss
。还有将 nn.LogSoftmax
和 nn.NLLLoss
结合起来的 nn.CrossEntropyLoss
交叉熵 loss function。
Autograd 求导
torch.autograd
提供了类和函数用来对任意标量函数进行求导。要想使用自动求导,只需要对已有的代码进行微小的改变。只需要将所有的tensor
包含进Variable
对象中即可。
可以通过创建 tensor
时设置 requires_grad
,也可以通过 x.requires_grad_(True)
来设置自动求导。
可以通过 z.grad_fn
来查看 Gradient function。
在模型中,只需要 loss.backward()
就可以计算后向传播时的导数。
如果想要关闭梯度跟踪,则需要在 with torch.no_grad():
下进行函数操作,或者对 tensor
使用 detach()
。
Optimizer
torch.optim
是一个实现了各种优化算法的库。大部分常用的方法得到支持,并且接口具备足够的通用性,使得未来能够集成更加复杂的方法。
为了构建一个Optimizer
,你需要给它一个包含了需要优化的参数(必须都是Variable
对象)的iterable。然后,你可以设置optimizer的参数选项,比如学习率,权重衰减。
常用的 Optimizer 有 SGD 和 Adam。
所有 Optimizer 中都含有 step()
和 zero_grad()
函数, step()
函数完成单次优化迭代,zero_grad()
将之前计算的梯度清空。通用训练流程如下:
1 |
|
如果要对 learning_rate 采用特殊下降方法,则通用训练流程为:
1 |
|
迭代优化方法
SGD
torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
) – 学习率 - momentum (
float
, 可选) – 动量因子(默认:0) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认:0) - dampening (
float
, 可选) – 动量的抑制因子(默认:0) - nesterov (
bool
, 可选) – 使用Nesterov动量(默认:False)
Adam
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:1e-3) - betas (Tuple[
float
,float
], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999) - eps (
float
, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
lr_scheduler
余弦退火
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1, verbose=False)
参数:
- optimizer (Optimizer) – Wrapped optimizer.
- T_max (int) – Maximum number of iterations.
- eta_min (float) – Minimum learning rate. Default: 0.
- last_epoch (int) – The index of last epoch. Default: -1.
- verbose (bool) – If
True
, prints a message to stdout for each update. Default:False
.
模型的存储和导入
存储模型权重
1 |
|
存储整个模型
将整个模型结构和权重一起存储,数据较大。
1 |
|