批量归一化和残差网络
利用神经网络训练模型时,我们总希望输入数据的特征分布相近,这样便于网络的收敛。尤其是深度神经网络,如果每次输入的batch数据分布相差太大的话,网络则每次都需要较大步幅更新参数,这样不利于网络的收敛。因此,对于浅层模型,通常对输入进行标准化,使得处理后的任意一个特征在数据集中所有样本上的均值为0、标准差为1。标准化处理输入数据能够使各个特征的分布相近。而对于深度模型,则采用批量归一化。利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使整个神经网络在各层的中间输出的数值更稳定。
对全连接层做批量归一化,位置在全连接层中的仿射变换和激活函数之间。对卷积层做批量归一化,位置则在卷积计算之后、激活函数之前。在这里需要注意,如果卷积计算输出多个通道,我们需要对这些通道的输出分别做批量归一化,且每个通道都拥有独立的拉伸和偏移参数。计算:对单通道,batchsize=m,卷积计算输出=pxq 对该通道中m×p×q个元素同时做批量归一化,使用相同的均值和方差。预测时的批量归一化,训练时,以batch为单位,对每个batch计算均值和方差。预测时用移动平均估算整个训练数据集的样本均值和方差。
移动平均:
def batch_norm(is_training, X, gamma, beta, moving_mean, moving_var, eps, momentum):
# 判断当前模式是训练模式还是预测模式
if not is_training:
# 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
else:
assert len(X.shape) in (2, 4)
if len(X.shape) == 2:
# 使用全连接层的情况,计算特征维上的均值和方差
mean = X.mean(dim=0)
var = ((X - mean) ** 2).mean(dim=0)
else:
# 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
# X的形状以便后面可以做广播运算
mean = X.mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
var = ((X - mean) ** 2).mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
# 训练模式下用当前的均值和方差做标准化
X_hat = (X - mean) / torch.sqrt(var + eps)
# 更新移动平均的均值和方差
moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
moving_var = momentum * moving_var + (1.0 - momentum) * var
Y = gamma * X_hat + beta # 拉伸和偏移
return Y, moving_mean, moving_var
右边的moving_mean、moving_var是前一次得到的移动平均和方差,初始化为0。更新与momentum相关。拉伸和偏移处采取了广播机制。
to(X.device)操作通常是因为处理的数据和变量不在同一块内存上,因此需要将它们挪到一起。
def forward(self, X):
# 如果X不在内存上,将moving_mean和moving_var复制到X所在显存上
if self.moving_mean.device != X.device:
self.moving_mean = self.moving_mean.to(X.device)
self.moving_var = self.moving_var.to(X.device)
# 保存更新过的moving_mean和moving_var, Module实例的traning属性默认为true, 调用.eval()后设成false
Y, self.moving_mean, self.moving_var = batch_norm(self.training,
X, self.gamma, self.beta, self.moving_mean,
self.moving_var, eps=1e-5, momentum=0.9)
return Y
利用Pytorch实现BN层时,BatchNorm1d代表全连接层后面的BN,num_dims默认为2,BatchNorm2d用在卷积层后面,num_dims默认为4,余下的一个参数为卷积之后的通道数。
残差网络(ResNet)
深度学习的问题:深度CNN网络达到一定深度后再一味地增加层数并不能带来进一步地分类性能提高,反而会招致网络收敛变得更慢,准确率也变得更差。
残差块(Residual Block)
恒等映射:
左边:f(x)=x
右边:f(x)-x=0 (易于捕捉恒等映射的细微波动)
在残差块中,输⼊可通过跨层的数据线路更快地向前传播。
在这里需要注意的是,前面经过加权运算的Y与X的维度(通道数)不同,因此在相加之前需要经过一个1x1的卷积操作来保持维度相同,从而可以相加。
稠密连接网络(DenseNet)
DensNet与ResNet最大不同就是:ResNet是X与Y相加,而DensNet是X与Y在通道维度上进行串联。这里就出现一个问题,串联的越多,通道数就越大,因此需要一个过渡层来控制通道数。
主要构建模块:
稠密块(dense block): 定义了输入和输出是如何连结的。
过渡层(transition layer):用来控制通道数,使之不过大。
过渡层通常是
1
×
1
1\times1
1×1卷积层:来减小通道数,加上步幅为2的平均池化层:减半高和宽。
凸优化
优化与深度学习需要明确的一点是,尽管优化方法可以最小化深度学习中的损失函数值,但本质上优化方法达到的目标与深度学习的目标并不相同。
优化方法目标:训练集损失函数值
深度学习目标:测试集损失函数值(泛化性)
优化在深度学习中的挑战
- 局部最小值
- 鞍点
- 梯度消失
鞍点:梯度等于零,在其附近Hessian矩阵有正的和负的特征值,行列式小于0,即是不定的。神经网络优化问题中的鞍点即一个维度向上倾斜且另一维度向下倾斜的点。
鞍点和局部极小值相同的是,在该点处的梯度都等于零,不同在于在鞍点附近Hessian矩阵是不定的(行列式小于0),而在局部极值附近的Hessian矩阵是正定的。转自【深度学习】鞍点
梯度下降
梯度下降与随机梯度下降的差别在于,梯度下降是对整个训练数据集求下降的梯度方向,而随机梯度下降是每次选取一个样本,计算下降方向,然后迭代更新。梯度下降的更新时间复杂度为
O
(
n
)
\mathcal{O}(n)
O(n),而随机梯度下降为
O
(
1
)
\mathcal{O}(1)
O(1)。
对于有
n
n
n个样本对训练数据集,设
f
i
x
f_i{x}
fix是第
i
i
i个样本的损失函数, 则目标函数为:
f
(
x
)
=
1
n
∑
i
=
1
n
f
i
(
x
)
f(\mathbf{x})=\frac{1}{n} \sum_{i=1}^{n} f_{i}(\mathbf{x})
f(x)=n1i=1∑nfi(x)
其梯度为:
∇
f
(
x
)
=
1
n
∑
i
=
1
n
∇
f
i
(
x
)
\nabla f(\mathbf{x})=\frac{1}{n} \sum_{i=1}^{n} \nabla f_{i}(\mathbf{x})
∇f(x)=n1i=1∑n∇fi(x)
使用该梯度的一次更新的时间复杂度为
O
(
n
)
\mathcal{O}(n)
O(n)。
随机梯度下降更新公式
O
(
1
)
\mathcal{O}(1)
O(1):
x
←
x
−
η
∇
f
i
(
x
)
\mathbf{x} \leftarrow \mathbf{x}-\eta \nabla f_{i}(\mathbf{x})
x←x−η∇fi(x)
且有:
E
i
∇
f
i
(
x
)
=
1
n
∑
i
=
1
n
∇
f
i
(
x
)
=
∇
f
(
x
)
\mathbb{E}_{i} \nabla f_{i}(\mathbf{x})=\frac{1}{n} \sum_{i=1}^{n} \nabla f_{i}(\mathbf{x})=\nabla f(\mathbf{x})
Ei∇fi(x)=n1i=1∑n∇fi(x)=∇f(x)
动态学习率
η
(
t
)
=
η
i
if
t
i
≤
t
≤
t
i
+
1
piecewise constant
η
(
t
)
=
η
0
⋅
e
−
λ
t
exponential
η
(
t
)
=
η
0
⋅
(
β
t
+
1
)
−
α
polynomial
\begin{array}{ll}{\eta(t)=\eta_{i} \text { if } t_{i} \leq t \leq t_{i+1}} & {\text { piecewise constant }} \\ {\eta(t)=\eta_{0} \cdot e^{-\lambda t}} & {\text { exponential }} \\ {\eta(t)=\eta_{0} \cdot(\beta t+1)^{-\alpha}} & {\text { polynomial }}\end{array}
η(t)=ηi if ti≤t≤ti+1η(t)=η0⋅e−λtη(t)=η0⋅(βt+1)−α piecewise constant exponential polynomial