文章目录
- 卷积神经网络调参
- optimizer 优化器
- SGD
- momentum
- AdaGrad
- RMSProp
- adam
- 学习率自适应
- 经验之谈
- 激活函数
- Sigmoid
- Tanh
- ReLU
- Leaky-ReLU
- 指数线性单元(ELU)
- Maxout(基本不用)
- 经验之谈
- 初始化
- 全部为 0
- 判断初始化好不好
- 批归一化(BN)
- 数据增强
- 更多的调参方法
- 保存模型后调用或再次训练
卷积神经网络调参
optimizer 优化器
SGD
SGD就是我们常说的随机梯度下降算法。
这边应该根据之前的学习,理解这个公式不难。
momentum
momentum 这个单词的意思就是动量,个人理解可以把这个更偏向理解成惯性,具体的含义就是在上面的更新公式上加上一个惯性,也就是说我们每次更新w的时候还要加上上一次运动的效果。
当使用动量时,则把每次 x的更新量v考虑为本次的梯度下降量 −ηdw与上次 w的更新量v乘上一个介于[0, 1]的因子momentum的和,即 v为
如果这一时刻更新度 vt与上一时刻更新度 vt−1的方向相同,则会加速。反之,则会减速。加动量的优势有两点:
- 加速收敛
- 提高精度(减少收敛过程中的振荡)
AdaGrad
调整学习率:学习率随着训练次数的增加越来越小。
这边也可以看一下代码实现:
AdaGrad 算法
前期,regularizer 较小,放大梯度
后期,regularizer 较大,缩小梯度
梯度随训练次数降低,每个分量有不同的学习率。
AdaGrad 算法缺点
学习率设置太大,导致 regularizer 影响过于敏感
后期,regularizer 累积值太大,提前结束训练
RMSProp
Adagrad 的变种
由累积平方梯度变为平均平方梯度
解决了后期提前结束的问题
adam
又加入了一个校准,校准的目的是一开始时,让 first_moment 和second_moment 都变的稍微大一些。
学习率自适应
K 是一个系数,t 是迭代次数,也就是 epoch
经验之谈
对于稀疏数据,使用学习率可自适应方法。
SGD 通常训练时间更长,最终效果比较好,但需要好的初始化和 learning rate。
需要训练较深较复杂的网络且需要快速收敛时,推荐使用 adam。设定一个比较小的 learning rate 值,Adagrad,RMSprop ,Adam 是比较相近的算法,在相似的情况下表现差不多。
激活函数
常见的激活函数:
Sigmoid
特点:
- 输入非常大或非常小时没有梯度
- 输出均值非 0(但是在归一化后,我们得到的是均值为零,方差为 1 的分布,sigmoid 会造成均值为非 0,又改变了分布)
- Exp 计算复杂导致计算机计算会更慢
- 梯度消失Sigmoid 1/1+e-x求导 df(x)/dx = f(x)(1-f(x)) 因为 f(x)是 0 到 1 之间的值,1-f(x)也是零到 1 之间的,因此随着层数的增加,梯度就变为 10 的-n 次方,会越乘越小。
Tanh
- 依旧没有梯度
- 输出均值是 0—相对于 sigmoid 的好处
- 计算复杂
ReLU
优点:
1.使用 ReLU 的 SGD 算法的收敛速度比 sigmoid 和 tanh 快。
2. 在 x>0 区域上,不会出现梯度饱和、梯度消失的问题。
3. 计算复杂度低,不需要进行指数运算,只要一个阈值就可以得到激活值。
缺点:
- ReLU 的输出不是 0 均值的。
- Dead ReLU Problem(神经元坏死现象):ReLU 在负数区域被 kill 的现象叫做 dead relu。ReLU在训练的时很“脆弱”。在 x<0 时,梯度为 0。这个神经元及之后的神经元梯度永远为 0,不再对任何数据有所响应,导致相应参数永远不会被更新。一个非常大的梯度流过神经元,不会再对数据有激活现象了,”很大的梯度流过神经元" 的意思就是指 该神经元相关的参数被梯度下降算法更新了一次。
比如原来的参数可能是:[-10, 5, 7], 然后突然来了一个梯度是[-100, -100, -100], 这样参数就更新成了 [-110, -95, -93]。 然后如果接下来的收到的数据都是[a, b, c], 其中 a, b, c >=0, 这个时候神经元的输出恒为 0,于是不会再有梯度传回来。因而参数得不到更新,也就变成了 dead cell 了。
产生这种现象的两个原因:参数初始化问题;learning rate 太高导致在训练过程中参数更新太大。
解决方法:采用 Xavier 初始化方法,以及避免将 learning rate 设置太大或使用 adagrad 等自动调节 learning rate 的算法。
Leaky-ReLU
渗漏整流线性单元(Leaky ReLU),为了解决 dead ReLU 现象。用一个类似 0.01 的小值来初始化神经元,从而使得 ReLU 在负数区域更偏向于激活而不是死掉。这里的斜率都是确定的。
指数线性单元(ELU)
具有 relu 的优势,没有 Dead ReLU 问题,输出均值接近 0,实际上 PReLU 和 Leaky ReLU 都有这一优点。有负数饱和区域,从而对噪声有一些鲁棒性。可以看做是介于 ReLU 和 Leaky ReLU 之间的一个函数。当然,这个函数小于零时也需要计算 exp,从而计算量大。
Maxout(基本不用)
ReLU 的泛化版本
没有 dead relu
但是参数翻倍,之前只有一个 w 和 b,现在有两个 w 和 b
优点:
- Maxout 的拟合能力非常强,可以拟合任意的凸函数。
- Maxout 具有 ReLU 的所有优点,线性、不饱和性。
- 不会出现神经元坏死的现象。
缺点:增加了参数量。显然。。。。这计算量太大了。。。常规的激活函数就只是单纯的函数而已。。而 maxout 还需要反向传播去更新它自身的权重系数。。。
经验之谈
Relu-小心设置 learning rate(初始值不要太大)
不要使用 sigmoid(relu 出现后,就不用它了,收敛太慢)
使用 Leaky Relu、maxout、ELU
可以试试 tanh,但不要抱太大期望(因为计算量大)
初始化
全部为 0
单层网络可以
多层网络会使梯度消失
判断初始化好不好
查看初始化后各层的激活值分布,激活值就是经过激活函数后的值,如果分布是固定的在-1到 1,或者 0 到 1 之间,那没问题,如果集中在某一个值,那就不太好。
均值为 0,方差为 0.02 的正态分布初始化—tanh
如下图所示(一次往后看是经过每一层后的效果):高层均值为 0,没有梯度
均值为 0,方差为 1 的正态分布初始化-tanh
如下图所示:高层均值为-1,1,已经饱和
可以看到 Xavier 分布在 tanh 上表现不错
如下图所示,可以看到 Xavier 分布在 ReLU 上表现并不好
Resnet 的何凯明发明了 He 的初始化,也就是变为 fan_in/2,从而对Relu效果好一些
批归一化(BN)
经过上面的一层层激活函数之后,我们会发现数据分明的效果会越来越差,那我们需要做的可能就是批归一化。
数据增强
之前介绍过图像的数据增强,这边略,知道有这种方法即可。
更多的调参方法
拿到更多的数据
给神经网络添加层次
紧跟最新进展,使用新方法
增大训练的迭代次数
尝试正则化 ||w||2 使用更多的 GPU 来加速训练
可视化工具来检查中间状态
保存模型后调用或再次训练
参考链接:
链接
例子:
# Include the epoch in the file name (uses `str.format`)
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
batch_size = 32
# Create a callback that saves the model's weights every 5 epochs
cp_callback = tf.keras.callbacks.ModelCheckpoint(
filepath=checkpoint_path,
verbose=1,
save_weights_only=True,
save_freq=5*batch_size)
# Create a new model instance
model = create_model()
# Save the weights using the `checkpoint_path` format
model.save_weights(checkpoint_path.format(epoch=0))
# Train the model with the new callback
model.fit(train_images,
train_labels,
epochs=50,
batch_size=batch_size,
callbacks=[cp_callback],
validation_data=(test_images, test_labels),
verbose=0)
输出:
Epoch 5: saving model to training_2/cp-0005.ckpt
Epoch 10: saving model to training_2/cp-0010.ckpt
Epoch 15: saving model to training_2/cp-0015.ckpt
Epoch 20: saving model to training_2/cp-0020.ckpt
Epoch 25: saving model to training_2/cp-0025.ckpt
Epoch 30: saving model to training_2/cp-0030.ckpt
Epoch 35: saving model to training_2/cp-0035.ckpt
Epoch 40: saving model to training_2/cp-0040.ckpt
Epoch 45: saving model to training_2/cp-0045.ckpt
Epoch 50: saving model to training_2/cp-0050.ckpt
<keras.callbacks.History at 0x7f56e00d5ee0>
现在,检查生成的检查点并选择最新检查点:
os.listdir(checkpoint_dir)
输出:
['cp-0020.ckpt.data-00000-of-00001',
'cp-0005.ckpt.index',
'cp-0025.ckpt.data-00000-of-00001',
'cp-0005.ckpt.data-00000-of-00001',
'cp-0000.ckpt.data-00000-of-00001',
'cp-0035.ckpt.index',
'cp-0045.ckpt.data-00000-of-00001',
'cp-0015.ckpt.data-00000-of-00001',
'cp-0040.ckpt.data-00000-of-00001',
'cp-0050.ckpt.index',
'cp-0020.ckpt.index',
'cp-0045.ckpt.index',
'cp-0025.ckpt.index',
'cp-0030.ckpt.index',
'cp-0000.ckpt.index',
'cp-0030.ckpt.data-00000-of-00001',
'cp-0040.ckpt.index',
'cp-0050.ckpt.data-00000-of-00001',
'cp-0010.ckpt.data-00000-of-00001',
'cp-0035.ckpt.data-00000-of-00001',
'checkpoint',
'cp-0010.ckpt.index',
'cp-0015.ckpt.index']
latest = tf.train.latest_checkpoint(checkpoint_dir)
latest
输出:
'training_2/cp-0050.ckpt'
要进行测试,请重置模型并加载最新检查点
# Create a new model instance
model = create_model()
# Load the previously saved weights
model.load_weights(latest)
# Re-evaluate the model
loss, acc = model.evaluate(test_images, test_labels, verbose=2)
print("Restored model, accuracy: {:5.2f}%".format(100 * acc))
输出:
32/32 - 0s - loss: 0.4798 - sparse_categorical_accuracy: 0.8800 - 156ms/epoch - 5ms/step
Restored model, accuracy: 88.00%
相同的还有保存整个模型的,这个就看那个链接吧,这边不细说。