本文共 9370 字,大约阅读时间需要 31 分钟。
绝大多数深度学习中的目标函数都很复杂。因此,很多优化问题并不存在解析解,而需要使用基于数值方法的优化算法找到近似解。这类优化算法一般通过不断迭代更新解的数值来找到近似解。我们讨论的优化算法都是这类基于数值方法的算法。
非凸优化的阻碍:局部最小值、鞍点。
在每一轮自变量迭代里,梯度下降使用整个训练数据集来计算梯度
如果使用梯度下降,每次自变量迭代的计算开销为 O(n) O ( n ) ,它随着 n n 线性增长。因此,当训练数据样本数很大时,梯度下降每次迭代的计算开销很高。
每次只随机采样一个样本来计算梯度
每次迭代的开销从梯度下降的 O(n) O ( n ) 降到了常数 O(1) O ( 1 )
随机梯度下降的更新轨迹相对于梯度下降更加曲折,实际中,它来自样本的噪音使得梯度的准确度下降,所以在使用同样的超参数的情况下,随机梯度下降收敛到的值相对梯度下降来说更最优值远。但因为随机梯度下降每一次迭代的计算比梯度下降更加简单,在同样运行时间下,随机梯度下降可以进行更多次的自变量迭代,它最终得到的解的质量可能会比梯度下降更优。
深度学习训练中实际使用,每一轮迭代里我们随机采样多个样本来组成一个小批量(mini-batch),然后对它计算梯度
小批量随机梯度下降中每次迭代的计算开销为 O(|Bt|)。
可以通过调整的批量大小来权衡计算效率和训练误差下降速度。
深度学习常使用的优化算法均基于小批量随机梯度下降,但区别在于如何使用梯度来更新自变量。这些改进算法主要基于两个技术:使用指数加权移动平均来平滑时间步之间的变化,和对每个自变量元素使用自适应的学习率。
在时间步 0,动量法创建速度变量 v0∈Rd v 0 ∈ R d ,并将其元素初始化成 0。在时间步 t>0 t > 0 ,动量法对每次迭代的步骤做如下修改:
其中,动量超参数 γ γ 满足 。当 γ=0 γ = 0 时,动量法等价于小批量随机梯度下降。
def sgd_momentum(params, states, hyperparams): hp = hyperparams for p, v in zip(params, states): v[:] = hp['mom'] * v + hp['lr'] * p.grad p[:] -= v
指数加权移动平均(exponentially weighted moving average, EMA):
注意:存在冷启动问题,初始状态初始化为0,不断地用0来做平均,拖后腿
由指数加权移动平均理解动量法:
现在,我们对动量法的速度变量做变形:
由指数加权移动平均的形式可得,速度变量 vt v t 实际上对序列做了指数加权移动平均,相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将前者对应的最近 1/(1−γ) 1 / ( 1 − γ ) 个时间步的更新量做了指数加权移动平均后再除以 1−γ 1 − γ 。
动量法中,自变量在各个方向上的移动幅度不仅取决当前梯度,还取决过去各个梯度在各个方向上是否一致
重点:
据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。
在时间步 0,adagrad 将 s0 s 0 中每个元素初始化为 0。在每次迭代中,首先将梯度 gt g t 按元素平方后累加到变量 st s t
ϵ ϵ 是为了维持数值稳定性而添加的常数,例如 。这里开方、除法和乘法的运算都是按元素进行的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率。
def adagrad(params, states, hyperparams): hp, eps = hyperparams, 1e-6 for p, s in zip(params, states): s[:] += p.grad.square() p[:] -= hp['lr'] * p.grad / (s + eps).sqrt()
重点:
小批量随机梯度按元素平方的累加变量 s s 出现在学习率的分母项中。
RMSProp 算法对 Adagrad 做了一点小小的修改,RMSProp 将过去时间步里梯度按元素平方做指数加权移动平均。
因为 RMSProp 的状态变量是对平方项 gt⊙gt g t ⊙ g t 的指数加权移动平均,因此可以看作是最近 1/(1−γ) 1 / ( 1 − γ ) 个时刻的梯度平方项的加权平均,这样自变量每个元素的学习率在迭代过程中避免了“直降不升”的问题。
def rmsprop(params, states, hyperparams): hp, eps = hyperparams, 1e-6 for p, s in zip(params, states): s[:] = hp['gamma'] * s + (1 - hp['gamma']) * p.grad.square() p[:] -= hp['lr'] * p.grad / (s + eps).sqrt()
Adadelta 跟 RMSProp 不同的地方在于使用 Δxt Δ x t 来替代了超参数 ηt η t ,因此它的主要优势在于不需要手动选取学习率。
def adadelta(params, states, hyperparams): rho, eps = hyperparams['rho'], 1e-5 for p, (s, delta) in zip(params, states): s[:] = rho * s + (1 - rho) * p.grad.square() g = ((delta + eps).sqrt() / (s + eps).sqrt()) * p.grad p[:] -= g delta[:] = rho * delta + (1 - rho) * g * g
Adam 是一个对 RMSProp 的改进算法。
作者建议β1=0.9,β2=0.999
def adam(params, states, hyperparams): hp, beta1, beta2, eps = hyperparams, 0.9, 0.999, 1e-6 for p, (v, s) in zip(params, states): v[:] = beta1 * v + (1 - beta1) * p.grad s[:] = beta2 * s + (1 - beta2) * p.grad.square() v_bias_corr = v / (1 - beta1 ** hp['t']) s_bias_corr = s / (1 - beta2 ** hp['t']) p[:] -= hp['lr'] * v_bias_corr / (s_bias_corr.sqrt() + eps) hp['t'] += 1
重点:
初始参数需要在不同单元间“破坏对称性”。
通常情况下,使用高斯或均匀分布中随机抽取的值初始化权重(随机初始化权重)。
有些启发式方法可以用于选择权重的初始大小。一种初始化m个输入和n个输出的全连接层的权重的启发式方法是从分布 U(−1/sqrt(m),1/sqrt(m)) U ( − 1 / s q r t ( m ) , 1 / s q r t ( m ) ) 中采样权重。
Glorot and Bengio(2010)建议使用标准初始化:
设置偏置的方法必须和设置权重的方法协调,通常设置偏置为0是可行的。
设全连接层的输入为 u,权重参数和偏差参数分别为 W 和 b,激活函数为 ϕ。设批量归一化的操作符为 BN。那么,使用批量归一化的全连接层的输出为
其中批量归一化输入 x 由仿射变换
得到。考虑一个由 m 个样本组成的小批量,仿射变换的输出为一个新的小批量 B=x(1),…,x(m) B = x ( 1 ) , … , x ( m ) 。它们正是批量归一化层的输入。对于小批量 B 中任意样本 x(i),1≤i≤m x ( i ) , 1 ≤ i ≤ m ,批量归一化层的输出
由以下几步求得。首先,对小批量 B 求均值和方差:
其中的平方计算是按元素求平方。接下来,我们使用按元素开方和按元素除法对 x(i) 标准化:
这里 ϵ>0 是一个很小的常数,保证分母大于 0。在上面标准化的基础上,批量归一化层引入了两个可以学习的模型参数,拉升(scale)参数 γ 和偏移(shift)参数 β。这两个参数和 x(i) 形状相同,并与 x(i) 分别做按元素乘法(符号 ⊙)和加法计算:
至此,我们得到了 x(i) 的批量归一化的输出 y(i)。 值得注意的是,可学习的拉升和偏移参数保留了不对 x^(i) 做批量归一化的可能:我们可以对此这样理解,如果批量归一化无益,理论上学出的模型可以不使用批量归一化。
def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum): # 通过 autograd 来获取是不是在训练模式下。 if not autograd.is_training(): # 如果是在预测模式下,直接使用传入的移动平滑均值和方差。 X_hat = (X - moving_mean) / nd.sqrt(moving_var + eps) else: assert len(X.shape) in (2, 4) # 使用全连接层的情况,计算特征维上的均值和方差。 if len(X.shape) == 2: mean = X.mean(axis=0) var = ((X - mean) ** 2).mean(axis=0) # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持 X # 的形状以便后面可以正常的做广播运算。 else: mean = X.mean(axis=(0, 2, 3), keepdims=True) var = ((X - mean) ** 2).mean(axis=(0, 2, 3), keepdims=True) # 训练模式下用当前的均值和方差做标准化。 X_hat = (X - mean) / nd.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
对于全连接的2D输入,对每个特征在样本间的均值转变成0,方差变为1。
对于卷积,对每个chennal,均值变成0,方差变为1。
class BatchNorm(nn.Block): def __init__(self, num_features, num_dims, **kwargs): super(BatchNorm, self).__init__(**kwargs) shape = (1, num_features) if num_dims == 2 else (1, num_features, 1, 1) # 参与求导和更新的模型参数,分别初始化成 0 和 1。 self.gamma = self.params.get('gamma', shape=shape, init=init.One()) self.beta = self.params.get('beta', shape=shape, init=init.Zero()) # 不参与求导的模型参数。全在 CPU 上初始化成 0。 self.moving_mean = nd.zeros(shape) self.moving_var = nd.zeros(shape) def forward(self, X): # 如果 X 不在 CPU 上,将 moving_mean 和 moving_varience 复制到对应设备上。 if self.moving_mean.context != X.context: self.moving_mean = self.moving_mean.copyto(X.context) self.moving_var = self.moving_var.copyto(X.context) # 保存更新过的 moving_mean 和 moving_var。 Y, self.moving_mean, self.moving_var = batch_norm( X, self.gamma.data(), self.beta.data(), self.moving_mean, self.moving_var, eps=1e-5, momentum=0.9) return Y
好处:收敛更快,学习率可以设置的大一点。附带好处:缓解过拟合。
小结:
Duchi, J., Hazan, E., & Singer, Y. (2011). Adaptive subgradient methods for online learning and stochastic optimization. Journal of Machine Learning Research, 12(Jul), 2121-2159.
Tieleman, T., & Hinton, G. (2012). Lecture 6.5-rmsprop: Divide the gradient by a running average of its recent magnitude. COURSERA: Neural networks for machine learning, 4(2), 26-31.
Zeiler, M. D. (2012). ADADELTA: an adaptive learning rate method. arXiv preprint arXiv:1212.5701.
Kingma, D. P., & Ba, J. (2014). Adam: A method for stochastic optimization. arXiv preprint arXiv:1412.6980.
Ioffe, S., & Szegedy, C. (2015). Batch normalization: Accelerating deep network training by reducing internal covariate shift. arXiv preprint arXiv:1502.03167.
《深度学习》 8
转载地址:http://ksoji.baihongyu.com/