目录
1. 什么是梯度消失
在梯度下降中,随着算法反向反馈到前面几层,梯度会越来越小,最终,没有变化,这时或许还没有收敛到比较好的解,这就是梯度消失问题,
梯度爆炸或者消失!!!
1,神经网络损失函数非凸的损失函数,逐步的减小步长,或者叫动态调整学习率
2,梯度爆炸的解决,使用梯度截断法,Gradient Clipping
3,L1、L2正则化,使得W变小,进一步反向传播的时候使得gradient变小
4,Batch Normalization,一种归一化的手段,主要作用或者发挥在Activations上面
5,激活函数也会影响,使用Relu优于tanh和sigmoid
6,W的初始化,如果一开始的W绝对值就比较大,更容易梯度爆炸或消失
7,网络Topology设计可以在一定程度上解决梯度消失或者爆炸
激活函数 再z比较大的时候梯度接近0
tanh
sigmoid
relu
step
Relu 比 Sigmoid 或 Tanh 等更优秀但是也会出现 dead neuron z<0的时候梯度为0
改进的relu
Leakly Relu
其他relu Elu
W初始化 避免梯度消失
已经训练好的在任务 A 上的模型(称为 pre-trained model),将其放在任务 B 上做模型调整(称为 fine-tuning)
参数的随机初始化
随机初始化是很多人目前经常使用的方法,然而这是有弊端的,一旦随机分布选择不当,就会导致网络优化陷入困境
下面以 tanh 神经网络为例,查看激活值的分布:
激活值的方差逐层递减
各层反向传播的梯度(关于状态的梯度)的分布情况:
状态的梯度在反向传播过程中越往下梯度越小(因为方差越来越小)越来越向0集中
import tensorflow as tf
import numpy as np
data = tf.constant(np.random.randn(2000, 800))
layer_sizes = [800 - 50 * i for i in range(0,10)]
num_layers = len(layer_sizes)
fcs = [] # To store fully connected layers' output
for i in range(0, num_layers - 1):
X = data if i == 0 else fcs[i - 1]
node_in = layer_sizes[i]
node_out = layer_sizes[i + 1]
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01
fc = tf.matmul(X, W)
fc = tf.nn.tanh(fc)
fcs.append(fc)
看到输出值迅速向 0 靠拢,在后几层中,几乎所有的输出值都很接近 0
修改上面的代码 W = tf.Variable(np.random.randn(node_in, node_out))
均值仍然为 0,标准差现在变为 1
几乎所有的值集中在-1 或 1 附近,神经元 saturated 了!注意到 tanh 在-1 和 1 附近的 gradient 都接近 0,这同样导致了 gradient 太小,参数难以被更新。
如何更科学的初始化?
Xavier initialization
Xavier 初始化的基本思想是保持输入和输出的方差一致,这样就避免了所有输出值都趋向于 0
继续修改代码 W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
输出值在很多层之后依然保持着良好的分布,这很有利于我们优化神经网络
继续修改代码 ReLU 神经元
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
fc = tf.nn.relu(fc)
前面看起来还不错,后面的趋势却是越来越接近 0
如何解决?
He initialization
在 ReLU 网络中,假定每一层有一半的神经元被激活,另一半为 0,所以,要保持 variance 不变,只需要在 Xavier 的基础上再除以 2
W = tf.Variable(np.random.randn(node_in,node_out)) / np.sqrt(node_in/2)
...... fc = tf.nn.relu(fc)
看起来效果非常好,推荐在 ReLU 网络中使用