PyTorch搭建卷积神经网络流程

一、数据的读取

PyTorch 为我们提供了一种十分方便的数据读取机制,即使用 Dataset 类与 DataLoader 类的组合,来得到数据迭代器。在训练或预测时,数据迭代器能够输出每一批次所需的数据,并且对数据进行相应的预处理与数据增强操作。

下面我们分别来看下 Dataset 类与 DataLoader 类。

1. Dataset 类

PyTorch 中的 Dataset 类是一个抽象类,它可以用来表示数据集。我们通过继承 Dataset 类来自定义数据集的格式、大小和其它属性,后面就可以供 DataLoader 类直接使用。

其实这就表示,无论使用自定义的数据集,还是官方为我们封装好的数据集,其本质都是继承了 Dataset 类。而在继承 Dataset 类时,至少需要重写以下几个方法:

  • __ init __():构造函数,可自定义数据读取方法以及进行数据预处理;
  • __ len __():返回数据集大小;
  • __ getitem __():索引数据集中的某一个数据。

光看原理不容易理解,下面我们来编写一个简单的例子,看下如何使用 Dataset 类定义一个 Tensor 类型的数据集。

import torch
from torch.utils.data import Dataset

class MyDataset(Dataset):
    # 构造函数
    def __init__(self, data_tensor, target_tensor):
        self.data_tensor = data_tensor
        self.target_tensor = target_tensor
    # 返回数据集大小
    def __len__(self):
        return self.data_tensor.size(0)
    # 返回索引的数据与标签
    def __getitem__(self, index):
        return self.data_tensor[index], self.target_tensor[index]

结合代码可以看到,我们定义了一个名字为 MyDataset 的数据集,在构造函数中,传入 Tensor 类型的数据与标签;在 __ len __ 函数中,直接返回 Tensor 的大小;在 __ getitem __ 函数中返回索引的数据与标签。

下面,我们来看一下如何调用刚才定义的数据集。首先随机生成一个 10*3 维的数据 Tensor,然后生成 10 维的标签 Tensor,与数据 Tensor 相对应。利用这两个 Tensor,生成一个 MyDataset 的对象。查看数据集的大小可以直接用 len() 函数,索引调用数据可以直接使用下标。

# 生成数据
data_tensor = torch.randn(10, 3)
target_tensor = torch.randint(2, (10,)) # 标签是0或1

# 将数据封装成Dataset
my_dataset = MyDataset(data_tensor, target_tensor)

# 查看数据集大小
print('Dataset size:', len(my_dataset))
'''
输出:
Dataset size: 10
'''

# 使用索引调用数据
print('tensor_data[0]: ', my_dataset[0])
'''
输出:
tensor_data[0]:  (tensor([ 0.4931, -0.0697,  0.4171]), tensor(0))
'''

2. DataLoader 类

在实际项目中,如果数据量很大,考虑到内存有限、I/O 速度等问题,在训练过程中不可能一次性的将所有数据全部加载到内存中,也不能只用一个进程去加载,所以就需要多进程、迭代加载,而 DataLoader 就是基于这些需要被设计出来的。

DataLoader 是一个迭代器,最基本的使用方法就是传入一个 Dataset 对象,它会根据参数 batch_size 的值生成一个 batch 的数据,节省内存的同时,它还可以实现多进程、数据打乱等处理。

DataLoader 类的调用方式如下:

from torch.utils.data import DataLoader
tensor_dataloader = DataLoader(dataset=my_dataset, # 传入的数据集, 必须参数
                               batch_size=2,       # 输出的batch大小
                               shuffle=True,       # 数据是否打乱
                               num_workers=0)      # 进程数, 0表示只有主进程

# 以循环形式输出
for data, target in tensor_dataloader: 
    print(data, target)
'''
输出:
tensor([[-0.1781, -1.1019, -0.1507],
        [-0.6170,  0.2366,  0.1006]]) tensor([0, 0])
tensor([[ 0.9451, -0.4923, -1.8178],
        [-0.4046, -0.5436, -1.7911]]) tensor([0, 0])
tensor([[-0.4561, -1.2480, -0.3051],
        [-0.9738,  0.9465,  0.4812]]) tensor([1, 0])
tensor([[ 0.0260,  1.5276,  0.1687],
        [ 1.3692, -0.0170, -1.6831]]) tensor([1, 0])
tensor([[ 0.0515, -0.8892, -0.1699],
        [ 0.4931, -0.0697,  0.4171]]) tensor([1, 0])
'''
 
# 输出一个batch
print('One batch tensor data: ', iter(tensor_dataloader).next())
'''
输出:
One batch tensor data:  [tensor([[ 0.9451, -0.4923, -1.8178],
        [-0.4046, -0.5436, -1.7911]]), tensor([0, 0])]
'''

结合代码,我们梳理一下 DataLoader 中的几个参数,它们分别表示:

  • dataset:Dataset 类型,输入的数据集,必须的参数;
  • batch_size:int 类型,每个 batch 有多少个样本;
  • shuffle:bool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱;
  • num_workers:int 类型,加载数据的进程数,0 意味着所有的数据都会被加载进主进程,默认为 0。

二、Pytorch搭建神经网络的流程

原文链接: 十分钟掌握Pytorch搭建神经网络的流程.


如果你想做一个网络,需要先定义一个Class,继承 nn.Module(这个是必须的,所以先import torch.nn as nn,nn是一个工具箱,很好用),我们把class的名字就叫成Net.

Class Net(nn.Module):

这个Class里面主要写两个函数,一个是初始化的__init__函数,另一个是forward函数。我们随便搭一个,如下:

    def __init__(self):
        super().__init__()
        self.conv1=nn.Conv2d(1,6,5)
        self.conv2=nn.Conv2d(6,16,5)
 
    def forward(self, x):
        x=F.max_pool2d(F.relu(self.conv1(x)),2)
        x=F.max_pool2d(F.relu(self.conv2(x)),2)
        return x
  1. __ init__ 里面就是定义卷积层,当然先得super()一下,给父类nn.Module初始化一下。(Python的基础知识)在这个里面主要就是定义卷积层的,比如第一层,我们叫它conv1,把它定义成输入1通道,输出6通道,卷积核5*5的的一个卷积层。conv2同理。神经网络“深度学习”其实主要就是学习卷积核里的参数,像别的不需要学习和改变的,就不用放进去。比如激活函数relu(),你非要放进去也行,再给它起个名字叫myrelu,也是可以的。
  2. forward里面就是真正执行数据的流动。比如上面的代码,输入的x先经过定义的conv1(这个名字是你自己起的),再经过激活函数F.relu()(这个就不是自己起的名字了,最开始应该先import torch.nn.functional as F,F.relu()是官方提供的函数。当然如果你在__init__里面把relu定义成了我上面说的myrelu,那你这里直接第一句话就成了x=F.max_pool2d(myrelu(self.conv1(x)),2)。下一步的F.max_pool2d池化也是一样的,不多废话了。在一系列流动以后,最后把x返回到外面去。
  3. 这个Net的Class定义主要要注意两点第一:是注意前后输出通道和输入通道的一致性。不能第一个卷积层输出4通道,第二个输入6通道,这样就会报错。 第二:它和我们常规的python的class还有一些不同,发现了没有?我们该怎么用这个Net呢? 先定义一个Net的实例(毕竟Net只是一个类不能直接传参数,output=Net(input)当然不行)
net=Net()

这样我们就可以往里传x了,假设你已经有一个要往神经网络的输入的数据“input"(这个input应该定义成tensor类型,怎么定义tensor那就自己去看看书了。另外pytorch三点几版本的你还得把它弄成Variable类型,4.0以后的就不需要了) 在传入的时候,是:

output=net(input)

看之前的定义:

def __init__(self):
   ……
 
def forward(self, x):
   ……

有点奇怪。好像常规python一般向class里面传入一个数据x,在class的定义里面,应该是把这个x作为形参传入__init__函数里的,而在上面的定义中,x作为形参是传入forward函数里面的。 其实也不矛盾,因为你定义net的时候,是net=Net(),并没有往里面传入参数。如果你想初始化的时候按需传入,就把需要的传入进去。只是x是神经网络的输入,但是并非是初始化需要的,初始化一个网络,必须要有输入数据吗?未必吧。只是在传入网络的时候,会自动认为你这个x是喂给forward里面的。


在网络定义好以后,就涉及到传入参数,算误差,反向传播,更新权重…确实很容易记不住这些东西的格式和顺序。 传入的方式上面已经介绍了,相当于一次正向传播,把一路上各层的输入x都算出来了。 想让神经网络输出的output跟你期望的ground truth差不多,那就是不断减小二者间的差异,这个差异是你自己定义的,也就是目标函数(object function)或者就是损失函数(loss function)。如果损失函数loss趋近于0,那么自然就达到目的了。损失函数loss基本上没法达到0,但是希望能让它达到最小值,那么就是希望它能按照梯度进行下降。梯度下降的公式,大家应该都很熟悉,不熟悉的话,建议去看一下相关的理论。 只是你的输入是由你来决定的,那神经网络能学习和决定什么呢?自然它只能决定每一层卷积层的权重。所以神经网络只能不停修改权重,比如y=wx+b,x是你给的,它只能改变w,b让最后的输出y尽可能接近你希望的y值,这样损失loss就越来越小。如果loss对于卷积层里面的参数W的偏导数接近0了,不就意味着到达了一个极小值吗?而在你的loss计算方式已经给定的情况下,loss对于w的偏导数的减小,其实只能通过更新参数卷积层参数W来实现(别的它决定不了啊,都是你输入和提供的)。 所以,通过下述方式实现对W的更新:(注意这些编号,下面还要提【1】 先算loss对于输入x的偏导,(当然网络好几层,这个x指的是每一层的输入,而不是最开始的输入input);【2】 对【1】的结果再乘以一个步长(这样就相当于是得到一个对参数W的修改量);【3】 用W减掉这个修改量,完成一次对参数W的修改。 说的不太严谨,但是大致意思是这样的。这个过程你可以手动实现,但是大规模神经网络怎么手动实现?那是不可能的事情。所以我们要利用框架pytorch和工具箱torch.nn。 所以要定义损失函数,以MSEloss为例

compute_loss=nn.MSELoss()

明显它也是个类,不能直接传入输入数据,所以直接loss=nn.MSEloss(target,output)是不对的。需要把这个函数赋一个实例,叫成compute_loss。之后就可以把你的神经网络的输出,和标准答案target传入进去:

loss=compute_loss(target,output)

算出loss,下一步就是反向传播

loss.backward()

这一步其实就是把【1】给算完了,得到对参数W一步的更新量,算是一次反向传播。这里就注意了,loss.backward()是啥玩意?如果是自己的定义的loss(比如你就自己定义了个def loss(x,y):return y-x )这样肯定直接backward会出错。所以应当用nn里面提供的函数。当然搞深度学习不可能只用官方提供的loss函数,所以如果你要想用自己的loss函数,必须也把loss定义成上面Net的样子(不然你的loss不能反向传播,这点要注意 ,注:这点是以前写的,很久之前的版本不行,现在都可以了,基本不太需要这样了),也是继承nn.Module,把传入的参数放进forward里面,具体的loss在forward里面算,最后return loss。__init()__就空着,写个super().__init__就行了。 在反向传播之后,第【2】和第【3】怎么实现?就是通过优化器来实现。让优化器来自动实现对网络权重W的更新。所以在Net定义完以后,需要写一个优化器的定义(选SGD方式为例):

from torch import optim
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)

同样,优化器也是一个类,先定义一个实例optimizer,然后之后会用。注意在optimizer定义的时候,需要给SGD传入了net的参数parameters,这样之后优化器就掌握了对网络参数的控制权,就能够对它进行修改了。传入的时候把学习率lr也传入了。 在每次迭代之前,先把optimizer里存的梯度清零一下(因为W已经更新过的“更新量”下一次就不需要用了)

optimizer.zero_grad()

在loss.backward()反向传播以后,更新参数:

optimizer.step()

所以我们的顺序是:

  1. 先定义网络:写网络Net的Class,声明网络的实例net=Net(),
  2. 定义优化器optimizer=optim.xxx(net.parameters(),lr=xxx),
  3. 再定义损失函数(自己写class或者直接用官方的,compute_loss=nn.MSELoss()或者其他。
  4. 在定义完之后,开始一次一次的循环: ①先清空优化器里的梯度信息,optimizer.zero_grad(); ②再将input传入,output=net(input) ,正向传播 ③算损失,loss=compute_loss(target,output) ##这里target就是参考标准值GT,需要自己准备,和之前传入的input一一对应 ④误差反向传播,loss.backward() ⑤更新参数,optimizer.step() 这样就实现了一个基本的神经网络。大部分神经网络的训练都可以简化为这个过程,无非是传入的内容复杂,网络定义复杂,损失函数复杂,等等等等。 说的有问题的地方感谢指正。

三、卷积层

卷积层是通过特定数目的卷积核(又称滤波器)对输入的多通道(channel)特征图进行扫描和运算,从而得到多个拥有更高层语义信息的输出特征图(通道数目等于卷积核的个数)。

3.1. 一维卷积层:torch.nn.Conv1d()

class 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)

3.1.1. 参数说明:

  • in_channels(int) – 输入信号的通道
  • out_channels(int) – 卷积产生的通道
  • kerner_size(int or tuple) - 卷积核的尺寸
  • stride(int or tuple, optional) -卷积步长
  • padding (int or tuple, optional)- 输入的每一条边补充0的层数
  • dilation(int or tuple, `optional``) – 卷积核元素之间的间距
  • groups(int, optional) –从输入通道到输出通道的阻塞连接数。 group=1,输出是所有的输入的卷积;group=2,此时相当于有并排的两个卷积层,每个卷积层计算输入通道的一半,并且产生的输出是输出通道的一半,随后将这两个输出连接起来。
  • bias(bool, optional) - 如果bias=True,添加偏置

3.1.2. example:

m = nn.Conv1d(16, 33, 3, stride=2)
input = autograd.Variable(torch.randn(20, 16, 50))
output = m(input)

3.2. 二维卷积层:torch.nn.Conv2d()

class 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)

  1. 2.1. 参数说明:
  • in_channels(int) – 输入信号的通道
  • out_channels(int) – 卷积产生的通道
  • kerner_size(int or tuple) - 卷积核的尺寸
  • stride(int or tuple, optional) - 卷积步长
  • padding(int or tuple, optional) - 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 卷积核元素之间的间距
  • groups(int, optional) – 从输入通道到输出通道的阻塞连接数
  • bias(bool, optional) - 如果bias=True,添加偏置

3.2.2. example:

# With square kernels and equal stride
m = nn.Conv2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
# non-square kernels and unequal stride and with padding and dilation
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)

3.3. 三维卷积层:torch.nn.Conv3d()

class torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

三维卷积层, 输入的尺度是(N, C_in,D,H,W),输出尺度是(N, C_out, D_out, H_out,W_out)

3.3.1. 参数说明:

  • in_channels(int) – 输入信号的通道
  • out_channels(int) – 卷积产生的通道
  • kerner_size(int or tuple) - 卷积核的尺寸
  • stride(int or tuple, optional) - 卷积步长
  • padding(int or tuple, optional) - 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 卷积核元素之间的间距
  • groups(int, optional) – 从输入通道到输出通道的阻塞连接数
  • bias(bool, optional) - 如果bias=True,添加偏置

3.2. example:

# With square kernels and equal stride
m = nn.Conv3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(4, 2, 0))
input = autograd.Variable(torch.randn(20, 16, 10, 50, 100))
output = m(input)

四、池化层

在卷积神经网络中通常会在相邻的卷积层之间加入一个池化层,池化层可以有效的缩小参数矩阵的尺寸,从而减少最后连接层的中的参数数量。所以加入池化层可以加快计算速度和防止过拟合的作用。

4.1. 1维最大池化:torch.nn.MaxPool1d()

class 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)

4.1.1. 参数说明:

  • kernel_size(int or tuple) - max pooling的窗口大小
  • stride(int or tuple,optional) - max pooling的窗口移动的步长。默认值是kernel_size
  • padding(int or tuple,optional) - 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 一个控制窗口中元素步幅的参数
  • return_indices - 如果等于True,会返回输出最大值的序号,对于上采样操作会有帮助
  • ceil_mode - 如果等于True,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作

4.1.2. example:

# pool of size=3, stride=2
m = nn.MaxPool1d(3, stride=2)
input = autograd.Variable(torch.randn(20, 16, 50))
output = m(input)

4.2. 2维最大池化:torch.nn.MaxPool2d()

class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

如果输入的大小是 (N,C, H i n H_{in} Hin, W i n W_{in} Win),那么输出的大小是 (N,C, H o u t H_{out} Hout, W o u t W_{out} Wout)

4.2.1. 参数说明:

  • kernel_size(int or tuple) - max pooling的窗口大小
  • stride(int or tuple,optional) - max pooling的窗口移动的步长。默认值是kernel_size
  • padding(int or tuple,optional) - 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 一个控制窗口中元素步幅的参数
  • return_indices - 如果等于True,会返回输出最大值的序号,对于上采样操作会有帮助
  • ceil_mode - 如果等于True,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作

4.2.2. example:

# pool of square window of size=3, stride=2
m = nn.MaxPool2d(3, stride=2)
# pool of non-square window
m = nn.MaxPool2d((3, 2), stride=(2, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)

4.3. 3维最大池化:torch.nn.MaxPool3d()

class torch.nn.MaxPool3d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

如果输入的大小是 (N,C,D,H,W),那么输出的大小是 (N,C,D , H o u t ,H_{out} ,Hout, W o u t W_{out} Wout)

4.3.1. 参数说明:

  • kernel_size(int or tuple) - max pooling的窗口大小
  • stride(int or tuple,optional) - max pooling的窗口移动的步长。默认值是kernel_size
  • padding(int or tuple,optional) - 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 一个控制窗口中元素步幅的参数
  • return_indices - 如果等于True,会返回输出最大值的序号,对于上采样操作会有帮助
  • ceil_mode - 如果等于True,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作

4.3.2. example:

# pool of square window of size=3, stride=2
m = nn.MaxPool3d(3, stride=2)
# pool of non-square window
m = nn.MaxPool3d((3, 2, 2), stride=(2, 1, 2))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)

五、非线性激活层

5.1. torch.nn.ReLU()

class torch.nn.ReLU(inplace=False)

5.1.1 参数:

  • inplace-选择是否进行覆盖运算

5.1.2 example:

m = nn.ReLU()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

5.2. torch.nn.ELU()

class torch.nn.ELU(alpha=1.0, inplace=False)

5.2.1 参数:

  • inplace-选择是否进行覆盖运算

5.2.2 example:

m = nn.ELU()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

5.3. torch.nn.LeakyReLU()

class torch.nn.LeakyReLU(negative_slope=0.01, inplace=False)

5.3.1 参数:

  • inplace-选择是否进行覆盖运算
  • negative_slope:控制负斜率的角度,默认等于0.01

5.3.2 example:

m = nn.LeakyReLU(0.1)
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

5.4. torch.nn.Softmax()

对n维输入张量运用Softmax函数,将张量的每个元素缩放到(0,1)区间且和为1。

class torch.nn.Softmax()

5.4.1 example:

m = nn.Softmax()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

5.5. torch.nn.Sigmoid()

对n维输入张量运用Softmax函数,将张量的每个元素缩放到(0,1)区间且和为1。

class torch.nn.Sigmoid()

5.5.1 example:

m = nn.Sigmoid()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

5.6. torch.nn.Tanh ()

对n维输入张量运用Softmax函数,将张量的每个元素缩放到(0,1)区间且和为1。

class torch.nn.Tanh()

5.6.1 example:

m = nn.Tanh()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))

六、归一化层

6.1. torch.nn.BatchNorm1d()

对小批量(mini-batch)的2d或3d输入进行批标准化(Batch Normalization)操作

class torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True)

y = x − m e a n [ x ] V a r [ x ] + ϵ ∗ g a m m a + b e t a y = \frac{x - mean[x]}{ \sqrt{Var[x]} + \epsilon} * gamma + beta y=Var[x] +ϵxmean[x]gamma+beta
在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)。

在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。

在验证时,训练求得的均值/方差将用于标准化验证数据。

6.1.1 参数:

  • num_features: 来自期望输入的特征数,该期望输入的大小为’batch_size x num_features [x
    width]’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum:动态均值和动态方差所使用的动量。默认为0.1。
  • affine:一个布尔值,当设为true,给该层添加可学习的仿射变换参数。

Shape: - 输入:(N, C)或者(N, C, L) - 输出:(N, C)或者(N,C,L)(输入输出相同)

6.1.2 example:

# With Learnable Parameters
m = nn.BatchNorm1d(100)
# Without Learnable Parameters
m = nn.BatchNorm1d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100))
output = m(input)

6.2. torch.nn.BatchNorm2d()

对小批量(mini-batch)3d数据组成的4d输入进行批标准化(Batch Normalization)操作

class torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True)

y = x − m e a n [ x ] V a r [ x ] + ϵ ∗ g a m m a + b e t a y = \frac{x - mean[x]}{ \sqrt{Var[x]} + \epsilon} * gamma + beta y=Var[x] +ϵxmean[x]gamma+beta
在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)。

在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。

在验证时,训练求得的均值/方差将用于标准化验证数据。

6.2.1 参数:

  • num_features: 来自期望输入的特征数,该期望输入的大小为’batch_size x num_features x height x width’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum:动态均值和动态方差所使用的动量。默认为0.1。
  • affine:一个布尔值,当设为true,给该层添加可学习的仿射变换参数。

Shape: - 输入:(N, C,H, W) - 输出:(N, C, H, W)(输入输出相同)

6.2.2 example:

# With Learnable Parameters
m = nn.BatchNorm2d(100)
# Without Learnable Parameters
m = nn.BatchNorm2d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100, 35, 45))
output = m(input)

6.3. torch.nn.BatchNorm3d()

对小批量(mini-batch)4d数据组成的5d输入进行批标准化(Batch Normalization)操作

class torch.nn.BatchNorm3d(num_features, eps=1e-05, momentum=0.1, affine=True)

y = x − m e a n [ x ] V a r [ x ] + ϵ ∗ g a m m a + b e t a y = \frac{x - mean[x]}{ \sqrt{Var[x]} + \epsilon} * gamma + beta y=Var[x] +ϵxmean[x]gamma+beta
在每一个小批量(mini-batch)数据中,计算输入各个维度的均值和标准差。gamma与beta是可学习的大小为C的参数向量(C为输入大小)。

在训练时,该层计算每次输入的均值与方差,并进行移动平均。移动平均默认的动量值为0.1。

在验证时,训练求得的均值/方差将用于标准化验证数据。

6.3.1 参数:

  • num_features: 来自期望输入的特征数,该期望输入的大小为 ‘batch_size x num_features depth x height x width’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum:动态均值和动态方差所使用的动量。默认为0.1。
  • affine:一个布尔值,当设为true,给该层添加可学习的仿射变换参数。

Shape: - 输入:(N, C,D, H, W) - 输出:(N, C, D, H, W)(输入输出相同)

6.3.2 example:

# With Learnable Parameters
m = nn.BatchNorm3d(100)
# Without Learnable Parameters
m = nn.BatchNorm3d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100, 35, 45, 10))
output = m(input)

七、线性层

class torch.nn.Linear(in_features, out_features, bias=True)

对输入数据做线性变换:(y = Ax + b)

7.1.参数:

  • in_features - 每个输入样本的大小
  • out_features - 每个输出样本的大小
  • bias - 若设置为False,这层不会学习偏置。默认值:True

7.2.shape

  • 输入: (N,in_features)
  • 输出: (N,out_features)

7.3.example

m = nn.Linear(20, 30)
input = autograd.Variable(torch.randn(128, 20))
output = m(input)
print(output.size())

八、Dropout layers

class torch.nn.Dropout(p=0.5, inplace=False)

随机将输入张量中部分元素设置为0。对于每次前向调用,被置0的元素都是随机的。

8.1.参数:

  • p - 将元素置0的概率。默认值:0.5
  • in-place - 若设置为True,会在原地执行操作。默认值:False

8.2.shape

  • 输入: 任意。输入可以为任意形状。
  • 输出: 相同。输出和输入形状相同。

8.3.example

m = nn.Dropout(p=0.2)
input = autograd.Variable(torch.randn(20, 16))
output = m(input)

九、Loss functions

基本用法:

criterion = LossCriterion() #构造函数有自己的参数
loss = criterion(x, y) #调用标准时也有参数

9.1. torch.nn.L1Loss()

原型:

class torch.nn.L1Loss(size_average=True)

创建一个衡量输入x(模型预测输出)和目标y之间差的绝对值的平均值的标准。计算公式:
l o s s ( x , y ) = 1 / n ∑ ∣ x i − y i ∣ loss(x,y)=1/n\sum|x_i-y_i| loss(x,y)=1/nxiyi

参数:

  • xy 可以是任意形状,每个包含n个元素。
  • n个元素对应的差值的绝对值求和,得出来的结果除以n
  • 如果在创建L1Loss实例的时候在构造函数中传入size_average=False,那么求出来的绝对值的和将不会除以n

9.2. torch.nn.MSELoss()

原型:

class torch.nn.MSELoss(size_average=True)

创建一个衡量输入x(模型预测输出)和目标y之间差均方误差标准。计算公式:
l o s s ( x , y ) = 1 / n ∑ ( x i − y i ) 2 loss(x,y)=1/n\sum(x_i-y_i)^2 loss(x,y)=1/n(xiyi)2

参数:

  • xy 可以是任意形状,每个包含n个元素。
  • n个元素对应的差值的绝对值求和,得出来的结果除以n
  • 如果在创建MSELoss实例的时候在构造函数中传入size_average=False,那么求出来的平方和将不会除以n

9.3. torch.nn.CrossEntropyLoss()

原型:

class torch.nn.CrossEntropyLoss(weight=None, size_average=True)

此标准将 LogSoftMax NLLLoss 集成到一个类中。

当训练一个多类分类器的时候,这个方法是十分有用的。

  • weight(tensor): 1-D tensor,n个元素,分别代表n类的权重,如果你的训练样本很不均衡的话,是非常有用的。默认值为None。

l o s s ( x , y ) = 1 / n ∑ ( x i − y i ) 2 loss(x,y)=1/n\sum(x_i-y_i)^2 loss(x,y)=1/n(xiyi)2

调用时参数:

  • input : 包含每个类的得分, 2-D tensor, shape batch*n
  • target: 大小为 n 1—D tensor,包含类别的索引 (0到 n-1)

Loss可以表述为以下形式:

在这里插入图片描述
当weight参数被指定的时候,loss的计算公式变为:
l o s s ( x , c l a s s ) = w e i g h t s [ c l a s s ] ∗ ( − x [ c l a s s ] + l o g ( ∑ j e x p ( x [ j ] ) ) ) loss(x, class) = weights[class] * (-x[class] + log(\sum_j exp(x[j]))) loss(x,class)=weights[class](x[class]+log(jexp(x[j])))

计算出的loss对mini-batch的大小取了平均。

shape:

  • Input: (N,C) C 是类别的数量
  • Target: (N) N是mini-batch的大小,0 <= targets[i] <= C-1

9.4. 更多Loss functions参见pytorch手册:

pytorch手册Loss functions链接.

猜你喜欢

转载自blog.csdn.net/luanfenlian0992/article/details/111084991