PyTorch的nn.Linear()详解
PyTorch的nn.Linear()是用于设置网络中的全连接层的,需要注意的是全连接层的输入与输出都是二维张量,一般形状为[batch_size, size],不同于卷积层要求输入输出是四维张量。其用法与形参说明如下:
in_features指的是输入的二维张量的大小,即输入的[batch_size, size]中的size。
out_features指的是输出的二维张量的大小,即输出的二维张量的形状为[batch_size,output_size],当然,它也代表了该全连接层的神经元个数。
从输入输出的张量的shape角度来理解,相当于一个输入为[batch_size, in_features]的张量变换成了[batch_size, out_features]的输出张量。
用法示例:
pytorch——nn.BatchNorm1d()
Batch Normalization原理:
其主要描述的是:训练深度网络的时候经常发生训练困难的问题,因为,每一次参数迭代更新后,上一层网络的输出数据经过这一层网络计算后,数据的分布会发生变化,为下一层网络的学习带来困难(神经网络本来就是要学习数据的分布,要是分布一直在变,学习就很难了),此现象称之为InternalInternal Covariate Shift。
Internal Covariate Shift 和Covariate Shift具有相似性,但并不是一个东西,前者发生在神经网络的内部,所以是InternalInternal,后者发生在输入数据上。Covariate Shift主要描述的是由于训练数据和测试数据存在分布的差异性,给网络的泛化性和训练速度带来了影响,我们经常使用的方法是做归一化或者白化。
机器学习领域有个很重要的假设:IID独立同分布假设,就是假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。
BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。
原理:
Internal Covariate Shift除了增加模型学习的难度之外,还会导致梯度消失的问题。深层神经网络在做非线性变换前的激活输入值(就是那个x=WU+B,U是输入)随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因。
就是说Internal Covariate Shift 主要导致两个问题:1.中间层输入分布总是变化,增加了模型拟合的难度。2.中间层输入分布会使输出逐渐靠近激活函数梯度较小的地方,导致梯度消失。
所以解决Internal Covariate Shift 就可以提升模型的性能,BatchNorm就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到正态分布。这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。
对于每个隐层神经元,把逐渐向非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。因为梯度一直都能保持比较大的状态,所以很明显对神经网络的参数调整效率比较高,就是变动大,就是说向损失函数最优值迈动的步子大,也就是说收敛地快
实现:
为了减小Internal Covariate Shift,对神经网络的每一层做归一化不就可以了,假设将每一层输出后的数据都归一化到0均值,1方差,满足正态分布。但是,此时有一个问题,每一层的数据分布都是标准正太分布,导致其完全学习不到输入数据的特征,因为,费劲心思学习到的特征分布被归一化了,因此,直接对每一层做归一化显然是不合理的。
但是如果稍作修改,加入可训练的参数做归一化,那就是Batch Norm实现的。
代码:
首先计算均值和方差,然后归一化,然后缩放和平移,完事!但是这是在训练中完成的任务,每次训练给一个批量,然后计算批量的均值方差,但是在测试的时候可不是这样,测试的时候每次只输入一个样本,这怎么计算批量的均值和方差,于是,就有了代码中下面两行,在训练的时候实现计算好mean var测试的时候直接拿来用就可以了,不用计算均值和方差。
应用:
根据前面的理论,Batch Norm主要是为了输入在激活函数的敏感区。所以BatchNorm层要加在激活函数前面。
nn.BatchNorm1d(dim),dim等于前一层输出的维度。BatchNorm层输出的维度也是dim。
优点:
①不仅仅极大提升了训练速度,收敛过程大大加快;
②还能增加分类效果,一种解释是这是类似于Dropout的一种防止过拟合的正则化表达方式,所以不用Dropout也能达到相当的效果;
③另外调参过程也简单多了,对于初始化要求没那么高,而且可以使用大的学习率等。
其他:https://www.itsiwei.com/22671.html
有种说法,BatchNorm起作用和Internal Covariate Shift没啥关系。
BatchNorm对训练过程有着更根本的影响:它能使优化问题的解空间更加平滑,而这种平滑性确保了梯度更具预测性和稳定性,因此可以使用更大范围的学习速率并获得更快的网络收敛。
nn.Sequential()
一、关于Sequential类的简介
先来看一下它的定义吧,在之前,我们首先需要明确一个特别重要的观念,那就是——torch的核心是Module类,
Module类在下面这个模块中:
D:\ProgramData\Anaconda3\envs\pytorch1.1.0\Lib\site-packages\torch\nn\modules\module.py
Sequential继承自Module,在下面这个模块里面:
D:\ProgramData\Anaconda3\envs\pytorch1.1.0\Lib\site-packages\torch\nn\modules\container.py
这样看起来,Sequential似乎是一个容器,的确,他确确实实是可以作为一个容器包装几个层,这里简单看一下它的定义:
这里还看一下这个所谓的container.py里面还有哪些“容器”存在
二、Sequential类不同的实现(3种实现)
2.1 最简单的序贯模型
注意:这样做有一个问题,每一个层是没有名称,默认的是以0、1、2、3来命名,从上面的运行结果也可以看出。
2.2 给每一个层添加名称
注意:从上面的结果中可以看出,这个时候每一个层都有了自己的名称,但是此时需要注意,我并不能够通过名称直接获取层,依然只能通过索引index,即
model[2] 是正确的
model["conv2"] 是错误的
这其实是由它的定义实现的,看上面的Sequenrial定义可知,只支持index访问。
2.3 Sequential的第三种实现
Sequential里面并没有定义 add_module()方法啊,实际上,这个方法是定义在它的父类Module里面的,Sequential继承了而已,它的定义如下
总结:上面的3种定义顺序模型的方法是较为常见的,但是我们说了Sequential除了本身可以用来定义模型之外,它还可以包装层,把几个层包装起来像一个块一样
网友评论