深度学习-调参和优化(一)

点击量:347

从今天开始,我们总结Coursera深度学习第二课:Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization,主要是调参和优化,这一块儿的内容是非常重要的,里面讲解了很多深度学习应用的经验法则,非常有参考价值。今天我们主要覆盖week1的内容:Week1 Practical aspects of Deep Learning。

Setting up your Machine Learning Application

数据集的划分(Train/Dev/Test)

一般来说,完整地训练一个ML应用需要把数据集划分三块:

  • 训练集(train)
  • 交叉验证集(cross validation)
    Cross Validation又被称为Dev Set,这部分数据集用于确定最终的模型。在实际场景中,我们往往会去尝试多种不同的hyperparameters,那么如何评判这些不同hyperparameters配置的模型的性能优劣呢?我们把不同的模型放到CV上跑一边,选择性能最好的那个,这就是Cross Validation的主要作用(因为不同模型在training set上的性能肯定都是尽可能最优的,因此分辨不出哪个更好)
  • 测试集(test)

那么具体该如何划分?

在以前数据量不是很大时,最常见的划分比例大致是70-30或者60-20-20。但是,在大数据时代,这条经验法则不再适用。因为dev和test的主要作用是验证,因此绝对数据量并不需要很大。比如,假设给定的所有数据是100万条,通常dev和test的数据量各达到1万条就足够了,那么此时的划分比例就变成98-1-1了。Training set 和 CV/test set的数据来源分布是可以不一致的,但是为了保证验证的准确性,CV和test set的数据来源(data distribution)必须是一致。
什么是 data distribution?
举个简单的例子,比如数据集A的数据来自于爬虫从网页上抓取的图片,这部分图片分辨率较高。而数据集B的数据则来自于用户自己上传的图片,这部分的图片质量可能参差不齐。于是我们就可以说A和B的data distribution不一样。有时候没有test set也是可以接受的。

偏差和方差(Bias/Variance)

  • bias,中文译为偏差。high bias指的是欠拟合,模型在训练集上的表现很差。
  • variance,中文译为方差。high variance指的是过拟合,一般是指在训练集上表现很好,但是在CV上表现很差。

具体地,我们看如下表格:

Train set error 1% 15% 15% 0.5%
Dev set error 11% 16% 30% 1%
Diagnosis high variance high bias high bias & variance low bias & low variance

其实,在实际工程中很少会出现欠拟合的情况,大部分都是过拟合,那么过拟合该怎么办呢?主要有两种常见的方法

  • 增加数据集(当前数据集不大)
  • 正则化
    下面我们介绍一种最常见的避免过拟合的方法-正则化(regularization)。

Regularizing your neural network

Regularization

主要讲两种Regularization方法,分别是L1 Regularization和L2 Regularization。我们先以logistics regression为例,它的cost function是:

$$
J(w,b) = \frac{1}{m} \sum^{m}_{i=1} L(\hat{y}^{(i)},y^{(i)})
$$

其中,\(L\)表示的是loss。

  • L2 Regularization

    我们在此基础上加入L2正则项,就可以得到如下的cost function:

$$
J(w,b) = \frac{1}{m} \sum^{m}_{i=1} L(\hat{y}^{(i)},y^{(i)}) + \frac{\lambda}{2m} ||w||_2^2
$$

其中,\(\lambda\)被称为Regularization parameter,需要自己手动设定。\(||w||_2^2\) 就是L2 Regularization:

$$
||w||_2^2 = \sum^n_{j=1} w_{j}^{2} = w^{T}w
$$

简单点说,就是参数\(w\)的平方和。

  • L1 Regularization

    同样的,L1 Regularization的形式如下:

$$
J(w,b) = \frac{1}{m} \sum^{m}_{i=1} L(\hat{y}^{(i)},y^{(i)}) + \frac{\lambda}{2m} ||w||_1
$$

其中,\(||w||_1 = \sum_{j=1}^{n}w_j \)。最常用的还是L2,因为L1最终会导致参数\(w\)变得稀疏,在实际中很少被使用。

为什么正则化时只考虑参数\(w\),而不考虑\(b\)呢?

很简单,因为正则化参数\(w\) 会影响到多个特征(\(w\)其实是一个参数向量,有多个参数\(w_1,w_2,…,w_n\)),而参数\(b\)则是所有特征全局共享的参数(\(b\)只是一个实数),因此调整\(b\)的值对结果影响甚微。

为什么Regularization能减少过拟合?

这个问题在Machine Learning-逻辑回归(Logistic Regression)中被解释过了,只不过是从逻辑回归的角度,这次我们从神经网络的角度再次解释一遍,但其实原理都大同小异。假设\(\lambda\)值很大,那么要保证cost function足够小,参数\(w\)就必须趋近于0。那么就会使得神经网络中某一些神经元的值为0,也就是相当于是去掉了某一些神经元(跟之前的解释“去掉了复杂的多项次项”相似),这就使得神经网络的结构趋于简单,也因就此就可以减轻过拟合的情况。

Dropout Regularization

定义

Dropout Regularization指的是在每一次迭代的过程中,神经元有一定的概率被舍弃掉,不参与正向和反向传播,从而可以简化神经网络结构,以达到正则化的目的。

形象的解释可以看下图:

Imgur

然后我们把舍弃的神经元的输入和输出都去掉,就会得到如下更简洁的神经网络结构:

Imgur

实现

这里介绍一种被称为”Inverted Dropout“的实现方式,我们以第三层为例,Python代码的实现如下:

为什么在dropout之后,a_3还要除以keep_prob呢?这是为了使得a的值在dropout前后总体上保持不变。 为什么这样呢?因为每次迭代舍弃的神经元都不一样,如果每次都缩小20%,不做补偿,那么多次迭代之后每个神经元的值就会趋近于0了。因为dropout的不稳定性,测试的时候建议关闭。dropout主要应用在计算机视觉领域,因为图片像素的input size非常大,这就导致你很难收集到足够多的数据去训练它,因此可以适当dropout一些神经元。但不要忘了,dropout本质上是一种Regularization技术。

Many of the first successful implementations of drop outs were to computer vision. So in computer vision, the input size is so big, inputting all these pixels that you almost never have enough data. And so drop out is very frequently used by computer vision.

其他的正则化方法

  • 数据扩充(data augmentation)
    通常情况下,获取额外的数据是困难的。我们可以在原有数据的基础上做一些变换以达到扩充数据的目的。我们以图片为例,我们可以对图片进行旋转,剪裁,扭曲,从而增加数据量。

  • Early Stopping
    当我们发现dev error开始上升时,就停止训练,这说明在这一刻我们的模型性能是最好的。因为过分追求training error很容易造成过拟合。

    Imgur

总结下以上提及的Regularization方法:L1,L2,dropout,data augmentation和early stopping。

Setting up your optimization problem

归一化(normalization)

  • Normalizing Input Data
    第一步,先算均值:

    $$
    \mu = \frac{1}{m} \sum_{i=1}^{m}x^{(i)}
    $$

    第二步,再算方差:

    $$
    \sigma^{2} = \frac{1}{m}\sum_{i=1}^m(x^{(i)}-\mu)^2
    $$

    第三步,最后归一化:

    $$
    x = \frac{x-\mu}{\sigma^2}
    $$

    为什么要归一化?
    归一化的主要目的是为了使得不同特征变量的值大致在同一个范围里,这样有利于加速梯度下降。比如有两个特征变量\(x_1\)和\(x_2\),\(x_1\)的取值范围是[1-10000],而\(x_2\)的取值范围是[0-1],我们希望通过归一化的方法使得两者的取值范围接近。为什么取值范围差异很大会影响收敛的速度呢?根本原因是:在梯度下降时,对于不同的特征变量我们都使用同一个学习曲率\(\alpha\),如果不同特征变量的取值范围差异太大,则会导致同一个\(\alpha\)值对他们的收敛效果不同,从而影响整体的收敛效果。直观上就如下图所示:一个走曲折路线,另一个则近似于走垂直路线:
    Imgur

  • Normalizing Neurons
    除了对对输入数据(input data)的normalization,为了增强神经网络的鲁棒性(robust)我们也会对神经元\(z\)进行normalization,具体方式和上面的类似,公式如下:

$$
\mu = \frac{1}{m} \sum_{i=1}^{m}z^{(i)} \\
\sigma^{2} = \frac{1}{m}\sum_{i=1}^m(z^{(i)}-\mu)^2 \\
z^{(i)}_{norm} = \frac{z^{(i)}-\mu}{\sqrt{\sigma^2 + \varepsilon }}
$$

$$
\tilde{z}^{(i)} = \gamma z^{(i)}_{norm} + \beta
$$

归一化之后的\(z\)是由\(\gamma\)和\(\beta\)控制,这两个参数是需要学习(learnable parameter)得到的,学习的方法就是梯度下降。

为什么需要batch norm?
因为随着参数的变化调整,每一层神经元的数据会发生起伏,如果每一层不做normalization,训练时hidden layers变得不稳定。

梯度消失和梯度爆炸(Vanishing and Exploding gradients)

个人觉得这个讲得不好,不应该从计算神经元的值入手,而是直接从反向传播的梯度计算入手。反向传播采用的是链式求导法则,计算的过程会包含多个神经元的导数相乘,如果每一次相乘都小于1那么当神经网络的层数很大时就很可能导致求导为0,从而导致梯度消失,无法下降;梯度爆炸同理。

如何解决?

这个问题一般只有神经网络非常深(比如100层)时才有可能出现,它是由反向传播的先天性不足导致的,并不能完全从根本上解决。

  • 对于梯度消失问题,我们可以更换activation function,从sigmoid切换到ReLU
  • 对权重参数随机初始化要小心,使得它既不太大也不太小

权重初始化(Weight Initialization)

如果激活函数是ReLU,一般会采用如下的初始化方式:

$$
\sqrt{\frac{2}{n^{[l-1]}}}
$$

如果激活函数是Tanh,一般会采用如下的初始化方式:

$$
\sqrt{\frac{1}{n^{[l-1]}}}
$$

这种也被称为Xavier Initialization,这样能使得这个参数既不是很大于1也不是很小于1。

当然也有人这么使用:

$$
\sqrt{\frac{2}{n^{[l-1]}+ n^{[l]}}}
$$

深度学习-调参和优化(一)》上有4条评论

  1. bywuuu

    这是我看过的讲的最清楚明白的深度学习调节参数的文章,不止讲了怎么调,也说了为什么以及影响。

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注