【Deep Learning】02 优化深度神经网络

本文为吴恩达 Deep Learning 笔记


深度学习的实用层面


概念

训练 / 验证 / 测试:

Training Set 训练集

Development Set 验证集

Test Set 测试集

偏差 / 方差:

Bias 偏差

Variance 方差

Underfitting 欠拟合

Overfitting 过拟合

Optimal Error / Bayes Error 理想误差 / 贝叶斯误差

  • 对于猫的识别,假设理想误差为 \(0\%\),则:

    High Bias Low Bias & Low Variance High Variance High Bias & High Variance
    训练集误差 \(15\%\) \(0.5\%\) \(1\%\) \(15\%\)
    测试集误差 \(16\%\) \(1\%\) \(11\%\) \(30\%\)

j5rtJg.png

机器学习的基本方法:

  • 高方差 (High Variance):过拟合,增加训练样本数据,进行正则化,选择其他更复杂的神经网络模型。
  • 高偏差 (High Bias):欠拟合,增加神经网络的隐藏层个数、神经元个数,延长训练时间,选择其它更复杂的神经网络模型。

正则化

正则化:

Regularization 正则化

L1 Regularization L1 正则化

L2 Regularization L2 正则化

Regularization Parameter 正则化参数

Frobenius Norm Frobenius 范数

Weight Decay 权重下降

  • 对于逻辑回归:

    • L2 正则化:

      \[J(w, b) = \frac{1}{m} \sum_{i = 1}^{m} L(\hat{y}^{(i)}, y^{(i)}) + \frac{\lambda}{2m} \left \| w \right \|_2^2 ,\quad \left \| w \right \|_2^2 = \sum_{j = 1}^{n_x}w_j^2 = w^\mathrm{T}w \]

    • L1 正则化:

      \[J(w, b) = \frac{1}{m} \sum_{i = 1}^{m} L(\hat{y}^{(i)}, y^{(i)}) + \frac{\lambda}{2m} \left \| w \right \|_1 ,\quad \left \| w \right \|_1 = \sum_{j = 1}^{n_x}\left | w_j \right | \]

    • 其中 \(\lambda\) 是超参数。

    • 与 L2 正则化相比,L1 正则化得到的 \(w\) 更加稀疏,即很多 \(w\) 为零值,节约存储空间。

    • 然而,L1 正则化在解决高方差 (High Variance) 方面比 L2 正则化并不更具优势。而且 L1 的在微分求导方面比较复杂,所以一般 L2 更加常用。

  • 对于深层神经网络:

    \[J(w^{[1]}, b^{[1]}, \cdots , w^{[L]}, b^{[L]}) = \frac{1}{m} \sum_{i = 1}^{m} L(\hat{y}^{(i)}, y^{(i)}) + \frac{\lambda}{2m} \sum_{l=1}^L \left \| w^{[l]}\right \|_F^2 ,\quad \left \| w^{[l]} \right \|_F^2 = \sum_{i = 1}^{n^{[l]}} \sum_{j = 1}^{n^{[l-1]}}(w_{ij}^{[l]})^2 \]

    • 其中 \(\left \| w^{[l]} \right \|_F\) 是 Frobenius 范数。
  • 由于加入了正则化项,梯度下降算法中的 \(dw^{[l]}\) 计算表达式需要做如下修改:

    \[dw^{[l]} = dw^{[l]}_{before} + \frac{\lambda}{m}w^{[l]} \\ w^{[l]} := w^{[l]} − \alpha \cdot dw^{[l]} = (1 - \alpha \frac{\lambda}{m})w^{[l]} - \alpha \cdot dw_{before}^{[l]} \]

丢弃法正则化:

Dropout Regularization 丢弃法

Inverted Dropout Technique 反向随机失活技术

  • 丢弃法是指在深度学习网络的训练过程中,对于每层的神经元,按照一定的概率将其暂时从网络中丢弃。也就是说,每次训练时,每一层都有部分神经元不工作,起到简化复杂网络模型的效果,从而避免发生过拟合。
dl = np.random.rand(al.shape[0], al.shape[1]) < keep_prob  # keep_prob 是要保留的神经元比例
al = np.multiply(al, dl)
al /= keep_prob  # 使下一层神经元的输入值尽量保持不变
  • 对于 \(m\) 个样本,单次迭代训练时,随机删除掉隐藏层一定数量的神经元,在删除后的剩下的神经元上正向和反向更新权重 \(w\) 和常数项 \(b\)
  • 下一次迭代中,再恢复之前删除的神经元,重新随机删除一定数量的神经元,进行正向和反向更新 \(w\)\(b\),不断重复上述过程,直至迭代训练完成。
  • 训练结束后,在测试和实际应用模型时,不需要进行随机删减神经元,所有的神经元都在工作。

理解丢弃法:

  • 不同隐藏层的系数 keep_prob 可以不同。
  • 神经元越多的隐藏层,keep_prob 可以设置得小一些;神经元越少的隐藏层,keep_prob 可以设置的大一些。

其他正则化方法:

Data Augmentation 数据扩充

Early Stopping 早停法

  • 数据增强:对已有的图片进行水平翻转、垂直翻转、任意角度旋转、缩放或扩大等。
  • 早停法:一个神经网络模型随着迭代训练次数增加,训练集代价一般是单调减小的,而测试集代价先减后增。训练次数过多时,模型会对训练样本拟合的越来越好,但是对验证集拟合效果逐渐变差,即发生了过拟合。因此,可以通过训练集代价和测试集代价随着迭代次数的变化趋势,选择合适的迭代次数。

输入

标准化输入:

Normalizing 标准化

  • 标准化:将原始数据减去其均值 \(\mu\) ,再除以方差 \(\sigma^2\)

    \[\mu = \frac{1}{m} \sum_{i = 1}^m X^{(i)} ,\quad \sigma^2 = \frac{1}{m} \sum_{i = 1}^m (X^{(i)})^2 ,\quad X := \frac{X −\mu}{\sigma^2} \]

  • 训练集和测试集都要进行标准化操作。


梯度

梯度消失和梯度爆炸:

Vanishing Gradients 梯度消失

Exploding Gradients 梯度爆炸

  • 当训练一个层数非常多的神经网络时,计算得到的梯度可能非常小或非常大。

神经网络的权重初始化:

  • 这是改善梯度消失和梯度爆炸的一种方法。

  • 如果激活函数是 \(tanh\)

    w[l] = np.random.randn(n[l], n[l-1]) * np.sqrt(1 / n[l-1])
    
  • 如果激活函数是 \(ReLU\)

    w[l] = np.random.randn(n[l], n[l-1]) * np.sqrt(2 / n[l-1]) 
    
  • 其他初始化方法:

    w[l] = np.random.randn(n[l], n[l-1]) * np.sqrt(2 / n[l-1] * n[l]) 
    

梯度的数值逼近:

  • 函数 \(g\)\(\theta\) 点的梯度可以表示为:

    \[g(\theta) = \frac{f(\theta + \varepsilon) - f(\theta - \varepsilon)}{2\varepsilon} \]

梯度检验:

  • 将代价函数 \(J(W^{[1]}, b^{[1]}, \cdots, W^{[L]}, b^{[L]})\) 表示为 \(J(\theta)\)

    • \(J(\theta)\) 计算 \(d\theta_i\)

      \[d\theta_i = \frac{J(\theta_1, \theta_2, \cdots, \theta_i + \varepsilon, \cdots) - J(\theta_1, \theta_2, \cdots, \theta_i - \varepsilon, \cdots)}{2\varepsilon} \]

    • \(d\theta_i\)\(d\theta_{approx}\)

  • 由反向传播 \(dW^{[1]}, db^{[1]}, \cdots, dW^{[L]}, db^{[L]}\) 得到 \(d\theta\)

  • 计算 \(d\theta_{approx}\)\(d\theta\) 的欧式距离比较二者相似度。

    \[\frac{\left \| d\theta_{approx} - d\theta \right \|_2}{\left \| d\theta_{approx} \right \|_2 + \left \| d\theta \right \|_2} \]

关于梯度检验的注记:

  • 不要在整个训练过程中都进行梯度检查,仅仅作为 debug 使用。
  • 如果梯度检查出现错误,找到对应出错的梯度,检查其推导是否出现错误。
  • 注意不要忽略正则化项,计算近似梯度的时候要包括进去。
  • 梯度检查时关闭 Dropout,检查完毕后再打开 Dropout。
  • 随机初始化时运行梯度检查,经过一些训练后再进行梯度检查(不常用)。

优化算法


Mini-batch

Mini-batch 梯度下降:

Batch Gradient Descent 批梯度下降法

Mini-batch Gradient Descent Mini-batch 梯度下降法

  • 如果样本数量 \(m\) 很大,例如达到百万数量级,训练速度往往会很慢,因为每次迭代都要对所有样本进行进行求和运算和矩阵运算。

  • 我们可以把 \(m\) 个训练样本分成若干个子集,称为 Mini-batches,这样每个子集包含的数据量就小了,然后每次在单一子集上进行神经网络训练,速度就会大大提高。这种梯度下降算法叫做 Mini-batch 梯度下降法。

  • 符号 \(X^{\{t\}}\), \(Y^{\{t\}}\):第 \(t\) 组 Mini-batch。

  • 流程:

    for t in range(T):
        Forward Propagation
        Compute Cost Function
        Backward Propagation
        W := W − alpha * dW
        b := b − alpha * db
    
    • 对于 Mini-batch 梯度下降法,一个 epoch 会进行 T 次梯度下降。
    • Mini-batch 可以进行多次 epoch,每次迭代,最好将总体训练数据重新打乱、重新分成 T 组。

理解 Mini-batch 梯度下降:

Stochastic Gradient Descent 随机梯度下降

  • 使用 Batch Gradient Descent,随着迭代次数增加,代价函数是不断减小的;使用 Mini-batch Gradient Descent,随着在不同的 Mini-batch 上迭代训练,其代价不是单调下降,而是受类似噪音的影响,出现振荡,但整体的趋势是下降的。
  • 当 Mini-batch 的大小为 \(m\) 时,即为 Batch Gradient Descent;当 Mini-batch 的大小为 \(1\) 时,即为 Stochastic gradient descent。Mini-batch 的大小推荐设置为 \(64, 128, 256, 512\)
  • Mini-batch 最终会在最小值附近来回波动,难以真正达到最小值处,而且在数值处理上不能使用向量化的方法来提高运算速度。

指数加权平均

指数加权平均:

Exponentially Weighted Averages 指数加权平均

  • 公式:

    \[V_t = \beta V_{t-1} + (1-\beta)\theta_t \]

    \(\beta\) 值决定了指数加权平均的天数,近似表示为:

    \[\frac{1}{1 - \beta} \]

    例如 \(\beta=0.9\) 表示将前 \(10\) 天进行指数加权平均。

理解指数加权平均:

v = 0
while (true):
    get next theta
    v := beta * v + (1 - beta) * theta

指数加权平均的参数修正:

  • 开始时我们设置 \(V_0 = 0\),所以初始值会相对小一些,直到后面受前面的影响渐渐变小,趋于正常。

  • 可以在每次计算完 \(V_t\) 时,作如下处理:

    \[V_t = \frac{V_t}{1 - \beta^t} \]


其他优化算法

动量梯度下降:

Gradient Descent With Momentum 动量梯度下降

  • 在每次训练时,对梯度进行指数加权平均处理,然后用得到的梯度值更新权重 \(w\) 和常数项 \(b\)

  • 公式:

    \[V_{dW} = \beta \cdot V_{dW} + (1 − \beta) \cdot dW ,\quad V_{db} = \beta \cdot V_{db} + (1 − \beta) \cdot db \\ W = W - \alpha V_{dW} ,\quad b = b - \alpha V_{db} \]

  • 超参数:\(\alpha\)\(\beta\)

RMSprop:

Root Mean Square Prop (RMSprop) 均方根传递

  • 公式:

    \[S_W = \beta S_{dW} + (1 − \beta)dW^2 ,\quad S_b = \beta S_{db} + (1 − \beta)db^2 \\ W := W − \alpha \frac{dW}{\sqrt{S_W} + \varepsilon} ,\quad b := b − \alpha \frac{db}{\sqrt{S_b} + \varepsilon} \]

  • 为了避免 RMSprop 算法中分母为零,通常可以在分母增加一个极小的常数 \(\varepsilon\)

Adam 优化算法:

Adaptive Moment Estimation 自适应矩阵估计

  • 结合了动量梯度下降算法和 RMSprop 算法。

  • 公式:

    \[\begin{aligned} V_{dW} = \beta_1 V_{dW} + (1 − \beta_1)dW &,\quad V_{db} = \beta_1 V_{db} + (1 − \beta_1)db \\ S_{dW} = \beta_2 S_{dW} + (1 − \beta_2)dW^2 &,\quad S_{db} = \beta_2 S_{db} + (1 − \beta_2)db^2 \\ V^{corrected}_{dW} = \frac{V_{dW}}{1 − \beta^t_1} &,\quad V^{corrected}_{db} = \frac{V_{db}}{1 − \beta^t_1} \\ S^{corrected}_{dW} = \frac{S_{dW}}{1 − \beta^t_2} &,\quad S^{corrected}_{db} = \frac{S_{db}}{1 − \beta^t_2} \\ W := W − \alpha \frac{V^{corrected}_{dW}}{\sqrt{S^{corrected}_{dW}} + \varepsilon} &,\quad b := b − \alpha \frac{V^{corrected}_{db}}{\sqrt{S^{corrected}_{db}} + \varepsilon} \end{aligned} \]

  • 超参数:\(\alpha\)\(\beta_1\)\(\beta_2\)\(\varepsilon\)

学习率衰减:

Learning Rate Decay 学习率衰减

  • 随着迭代次数增加,令学习因子 \(\alpha\) 逐渐减小。

  • 公式:

    \[\alpha = \frac{1}{1 + decay\_rate * epoch}\alpha_0 \quad or \quad \alpha = 0.95^{epoch}\alpha_0 \quad or \quad \alpha = \frac{k}{\sqrt{epoch}}\alpha_0 \quad or \quad \alpha = \frac{k}{\sqrt{t}}\alpha_0 \]

    • \(deacy\_rate\)\(k\) 是可调参数,\(epoch\) 是训练次数,\(t\) 是 Mini-batch 数量。

局部最优化

局部最优化问题:

Local Optima 局部最优化

Saddle Point 鞍点

Plateau 停滞区

  • 大部分梯度为零的 "最优点" 并不是这些凹槽处,而是马鞍状的鞍点 (Saddle Point)。
  • 梯度为零并不能保证都是极小值 (Convex),也有可能是极大值 (Concave)。
  • 类似马鞍状的停滞区 (Plateaus) 会降低神经网络学习速度,但是由于随机扰动,梯度一般能够离开鞍点 (Saddle Point),继续前进,只是在停滞区 (Plateaus) 上花费了太多时间。

总结

  • "+" 表示损失的最小值。

  • 梯度下降 (Gradient Descent) 与随机梯度下降 (Stochastic Gradient Descent, SGD):

    • 梯度下降:
    X = data_input  
    Y = labels  
    parameters = initialize_parameters(layers_dims)  
    for i in range(0, num_iterations):  
        a, caches = forward_propagation(X, parameters)  
        cost = compute_cost(a, Y)  
        grads = backward_propagation(a, caches, parameters)  
        parameters = update_parameters(parameters, grads)
    
    • 随机梯度下降:
    X = data_input  
    Y = labels  
    parameters = initialize_parameters(layers_dims)  
    for i in range(0, num_iterations):  
        for j in range(0, m):  
            a, caches = forward_propagation(X[:,j], parameters)  
            cost = compute_cost(a, Y[:,j])  
            grads = backward_propagation(a, caches, parameters)  
            parameters = update_parameters(parameters, grads)
    
    • 对于随机梯度下降,在更新梯度之前,只使用 1 个训练样例。
    • 当训练集大时,随机梯度下降可以更新的更快,但是这些参数会向最小值摆动而不是平稳地收敛。
  • 小批量梯度下降 (Mini-batch):

    • 如果既不使用整个训练集,也不使用一个训练示例,来执行每次更新,则通常会得到更快的结果。
    • 小批量梯度下降通常会胜过梯度下降或随机梯度下降,尤其是训练集较大时。
  • 动量梯度下降 (Gradient Descent With Momentum):

    • 传统的梯度下降在梯度下降过程中,振荡较大,每一点处的梯度只与当前方向有关,产生类似折线的效果,前进缓慢。
    • 动量梯度下降对梯度进行指数加权平均,使当前梯度不仅与当前方向有关,还与之前的方向有关。这样处理让梯度前进方向更加平滑,减少振荡,能够更快地到达最小值处。
    • 如果动量梯度下降的参数 \(\beta=0\),则它变为没有冲量的标准梯度下降。\(\beta\) 越大,更新越平滑,我们对过去的梯度的考虑也更多。
  • RMSprop:

    • 对于 \(w\)\(b\),如果哪个方向振荡大,就减小该方向的更新速度,从而减小振荡。
  • Adam:

    • 结合了动量梯度下降和 RMSProp 的优点。

j5rNWQ.png


超参数 批标准化 编程框架


超参数调试

调试过程:

  • 深度神经网络需要调试的超参数包括:
    • 学习因子 \(\alpha\):通常来说是需要重点调试的超参数。
    • 动量梯度下降因子 \(\beta\):通常来说重要程度仅次于 \(\alpha\)
    • Adam 算法参数:\(\beta_1\)\(\beta_2\)\(\varepsilon\)
    • 神经网络层数。
    • 各隐藏层神经元个数:通常来说重要程度仅次于 \(\alpha\)
    • 学习因子下降参数 \(decay\_rate\)
    • 批量训练样本包含的样本个数 \(mini\_batch\_size\):通常来说重要程度仅次于 \(\alpha\)
  • 通常做法:
    • 随机化选择参数,尽可能地得到更多种参数组合。
    • 为得到更精确的最佳参数,放大表现较好的区域,对选定的区域进行由粗到细的采样。

为超参数选择合适的范围:

  • 对于某些超参数,如神经网络层数、各隐藏层神经元个数,取值只能是正整数,可以进行随机均匀采样。

  • 对于另一些参数,如学习因子 \(\alpha\)

    • 设待调范围为 \([0.0001, 1]\),如果随机均匀采样,则 \(90\%\) 的采样点分布在 \([0.1, 1]\),但是 \(\alpha\) 的最佳取值更可能出现在 \([0.0001, 0.1]\)

    • 因此可以采用取对数的方法,线性区间是 \([a, b]\),对数区间是 \([m, n]\)

      m = np.log10(a)
      n = np.log10(b)
      r = np.random.rand()
      r = m + (n - m) * r
      r = np.power(10, r)
      
  • \(\alpha\) 外,\(\beta\) 也不能随机均匀采样,因为 \(\beta\) 越接近 \(1\),则对 \(1/(1 - \beta)\) 的影响越大。

超参数训练的实践:

Babysitting One Model 只对一个模型进行训练

Training Many Models In Parallel 对多个模型同时进行训练


批标准化

标准化网络中的激活函数:

Batch Normalization 批标准化

  • 批标准化可以让调试超参数更加简单,让模型可接受的超参数范围更大。

  • 在《标准化输入》一节对输入数据进行标准化,同样,可以对 \(l\) 层的输入,即 \(A^{[l - 1]}\)\(Z^{[l - 1]}\) 标准化:

    \[\mu = \frac{1}{m} \sum_i z^{(i)} ,\quad \sigma^2 = \frac{1}{m} \sum_i(z_i - \mu)^2 ,\quad z_{norm}^{(i)} = \frac{z^{(i)} - \mu}{\sqrt{\sigma^2 + \varepsilon}} \]

    • \(m\) 是单个 Mini-batch 包含样本个数。
    • \(\varepsilon\) 是为了防止分母为 \(0\)
  • 上式使得 \(z^{(i)}\) 均值为 \(0\),方差为 \(1\),但是实际并不希望这样,于是:

    \[\tilde z^{(i)} = \gamma \cdot z_{noem}^{(i)} + \beta \]

    • \(\gamma\)\(\beta\)\(w\)\(b\) 一样是可以通过梯度下降等算法求得的参数。
    • 从激活函数的角度来讲,如果 \(z^{(i)}\) 的均值为 \(0\),处于激活函数的线性区域,不利于训练好的非线性神经网络。

将 Batch Norm 应用于神经网络:

  • 整体流程:

    \[X \xrightarrow{W^{[1]}, b^{[1]}} Z^{[1]} \xrightarrow[BN]{\beta^{[1]}, \gamma^{[1]}} \tilde Z^{[1]} \rightarrow A^{[1]} \rightarrow \cdots \rightarrow A^{[L - 1]} \xrightarrow{W^{[L]}, b^{[L]}} Z^{[L]} \xrightarrow[BN]{\beta^{[L]}, \gamma^{[L]}} \tilde Z^{[L]} \rightarrow A^{[L]} \]

  • 在 BN 中,参数 \(b\) 可以删去,需要使用梯度下降求的参数只有 \(W\)\(\gamma\)\(beta\)

Batch Norm 为什么凑效:

Covariate Shift 列分布差异

  • Batch Norm 减少了各层 \(W^{[l]}\)\(B^{[l]}\) 之间的耦合性,让各层更加独立。
  • Batch Norm 起到了轻微正则化的作用。

Batch Norm 在测试集上的使用:

  • 在训练时 \(\mu\)\(\sigma\) 是通过单个 Mini-batch 中的 \(m\) 个样本求得的,测试时,如果只有一个样本,求其均值和方差是没有意义的,这就要对 \(\mu\)\(\sigma\) 进行估计。
  • 方法一:将所有训练集放入最终的神经网络模型中,将每个隐藏层计算得到的 \(\mu^{[l]}\)\(\sigma^{[l]}\) 直接作为测试过程的 \(\mu^{[l]}\)\(\sigma^{[l]}\) 来使用。实际应用中一般不使用这种方法。
  • 方法二:对于第 \(l\) 层隐藏层,考虑所有 Mini-batch 在该隐藏层下的 \(\mu^{[l]}\)\(\sigma^{[l]}\),然后用指数加权平均的方式来预测得到当前单个样本的 \(\mu^{[l]}\)\(\sigma^{[l]}\)

多分类

Softmax 回归:

  • 一般使用 Softmax 回归处理多分类问题,对于一个长度为 \(C\) 的任意实数向量,Softmax 可以把它压缩为一个长度为 \(C\) 的、取值在 \((0, 1)\) 区间的实数矢量,且矢量中各元素之和为 \(1\),因此 Softmax 的输出可以作为概率。

  • \(C\) 代表种类个数。

  • 神经网络输出层有 \(C\) 个神经元,每个神经元的输出 \(a_i^{[L]}\) 依次对应属于该类的概率。

    \[a_i^{[L]} = \frac{e^{z_i^{[L]}}}{\sum_{i=1}^{[L]}e^{z_i^{[L]}}} \]

  • 所有的 \(a_i^{[L]}\) 组成 \(\hat y\)\(\hat y\) 维度为 \((C, 1)\)

训练一个 Softmax 分类器:

  • 对于 \(C=4\) 的多分类,损失函数为:

    \[L(\hat y, y)= -\sum_{j=1}^4 y_j \cdot \log \hat y_j \]

    代价函数为:

    \[J = \frac{1}{m}\sum_{i=1}^m L(\hat y, y) \]

    输出层反向传播的计算:

    \[dZ^{[L]} = A^{[L]} - Y \]


编程框架

编程框架:

  • PaddlePaddle / Tensorflow / Torch

Tensorflow:

import numpy as np
import tensorflow as tf

cofficients = np.array([[1.],[-10.],[25.]])
w = tf.Variable(0,dtype=tf.float32)
x = tf.placeholder(tf.float32,[3,1])
cost = x[0][0]*w**2 + x[1][0]*w + x[2][0]
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)

init = tf.global_variables_initializer()
session = tf.Session()
session.run(init)
print(session.run(w))

for i in range(1000):
    session.run(train, feed_dict=(x:coefficients))
print(session.run(w))

'''
# 另一种写法
with tf.Session() as session:
    session.run(init)
    print(session.run(w))
'''

参考

posted @ 2022-07-16 22:48  空白4869  阅读(128)  评论(0编辑  收藏  举报