神经网路的训练
Activation Function
输入经线性变换后需经过非线性激活才能作为下一层的输入。
Sigmoid
σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1+e^{-x}} σ(x)=1+e−x1,取值范围为 ( 0 , 1 ) (0,1) (0,1) ,该激活函数存在一些问题:
- 神经元的激活值大小在1或者-1时会杀死梯度;
- 输出不以0为均值,这样使得 W W W 的允许更新方向要不全为正的,要不全为负的(从整个神经网络框架来看,这里可以这么理解,由于更新权重的方向只与 ∂ L ∂ W \frac{\partial L}{\partial W} ∂W∂L 与 输入 X X X 有关,前边一项不由 W W W 决定,后边一项由于 s i g m o i d sigmoid sigmoid 的输出符号不以0为中心,因此符号一致,因此所有参数只能按照全正或全反两个方向更新),使得不能很好的遍历参数空间
- 指数元素的计算复杂度很高
tanh
解决了输出不以0为中心的问题,但是另外两个问题仍然存在。
ReLU
f
(
x
)
=
max
(
0
,
x
)
f(x) = \max(0, x)
f(x)=max(0,x)
优点:
- 不存在饱和点(梯度很小)
- 计算迅速
- 实际应用中比tanh和sigmoid收敛快
- 从生物学的角度更加合理
缺点:
- 输出不以0为均值
- 对于小于0的值没有激活
基于上述原因,人们更喜欢以一个稍微正的偏差来初始化ReLU(如偏差为0.01的高斯模型初始化)。
Leaky ReLU
f
(
x
)
=
max
(
0.01
x
,
x
)
f(x) = \max(0.01x, x)
f(x)=max(0.01x,x)
输入为负数时也会被激活,但是在实际实现时的表现性能不一定比ReLU更好
Parametric Rectifier(PReLU)
f
(
x
)
=
max
(
α
x
,
x
)
f(x) = \max(\alpha x, x)
f(x)=max(αx,x)
通过神经网络的学习决定参数
α
\alpha
α
ELU
f
(
x
)
=
x
if
  
x
>
0
f(x) = x\quad\text{if} \; x > 0
f(x)=xifx>0
f
(
x
)
=
α
(
exp
(
x
)
−
1
)
if
  
x
≤
0
f(x) = \alpha (\exp(x) - 1) \quad\text{if}\;x \le 0
f(x)=α(exp(x)−1)ifx≤0
相较于Leaky ReLU,对于负值输入添加了更多对噪声的鲁棒性。
Maxout Neuron
max
(
ω
1
T
x
+
b
1
,
ω
2
T
x
+
b
2
)
\max(\omega_1^Tx + b_1, \omega_2^Tx + b_2)
max(ω1Tx+b1,ω2Tx+b2)
通过训练求解
ω
1
\omega_1
ω1,
b
1
b_1
b1,
ω
2
\omega_2
ω2,
b
2
b_2
b2
ReLU和Leaky ReLU是其一般形式,缺点也很明显成倍增大了参数的数目
TLDR
先用ReLU测试,同时注意learning rate的调节
尝试Leaky ReLU/Maxout/ELU
尝试tanh,但一般没有提升
sigmoid不需要尝试
Data Preprocessing
为什么要对输入做均值零化:如果全为正(负),那么在backward时,对
ω
\omega
ω 的梯度也只有正和负,那么更新方向只有zigzag,不能充分遍历参数空间
为什要做normalization:保证每个特征在相同的值域内且贡献相同,对于图像问题,通常会进行均值归0,但不尽兴normalization,因为对于图像我们认为每个位置已经得到了可比较的范围和分布。
除了mean-zero和normalization,通常使用的预处理方法还有PCA和whitening。
对图像而言,我们的mean-zero需要针对每个channel独立归零,通常也不尽兴PCA,normalization,whitening。
Weight initialization
若所有的参数初始0,那么在更新过程中不会打破对称性,无法遍历参数空间。
Small random numbers
W = 0.01 * np.ramdom.randn(D, H)
对于小网络符合要求,对于深层网络会存在很多问题
深层网络在后边层的激活值会全部变成0,由于后边层的输入在0附近,所以参数更新的权重都很小,优化速度很慢。
W = np.random.randn(D,H)*1
我们的分析是基于tanh激活函数的,如果用此办法进行激活,输出的值很大,每个神经元接近饱和,梯度的更新为0
W = np.random.randn(D,W)/np.sqrt(D)
解决了后层输出的过小或过大的问题,但是当使用ReLU时,破坏了本身的非线性性质,后边层的输出会越来越倾向于0,且神经元会失活
W = np.random.randn(D,W)/np.sqrt(D/2)
Batch Normalization
x
^
(
k
)
=
x
(
k
)
−
E
[
x
(
k
)
]
Var
[
x
(
k
)
]
\hat{x}^{(k)} = \frac{x^(k) - E[x^{(k)}]}{\sqrt{\text{Var}[x^{(k)}]}}
x^(k)=Var[x(k)]x(k)−E[x(k)]
batch normalization中的batch是与SGD中的batch对应,对于batch normalization,均值和方差的计算有两种方法:将一层所有数据来计算均值和方差;只选取SGD中的batch来计算均值和方差。均值和方差的计算是基于每一层而言的。
batch normalization通常在全连接层和非线性激活函数之间,为了使网络中有更灵活的均值和方差,batch normalization最后需要进行均值和方差的调节
y
(
k
)
=
γ
(
k
)
x
^
(
k
)
+
β
(
k
)
y^{(k)} = \gamma^{(k)}\hat{x}^{(k)} + \beta^{(k)}
y(k)=γ(k)x^(k)+β(k)
batch normalization的优点:
- 提高了网络中的gradient
- 允许更高的学习率
- 降低了对初始化值的强依赖
- 也是一种正则化的方法,可以减少对drop out的需求
在测试阶段,batch normalization的均值方差是基于训练时的均值方差得到的(一种方法是对训练时用到的均值和方差取平均)。
Babysitting the learning rate
首先对数据做预处理,再选择网络结构,在运行之前对loss检测添加regularization之后loss是否会提高,同时检测是否能对很小的训练值过拟合(准确度达到很高)。
开始训练时可以从很小的regularization开始找到可以使loss下降的learning rate。如果loss不下降,那么learning rate可能太小(这种情况下可能出现loss没什么变化但是准确度提高,因为loss的梯度虽然弥散,但是权重一直在更新);如果更新过程中出现NaN,则说明learning rate太大。在实际调试时,我们可以选择不同的learning rate进行交叉验证。
Hyperparameter Optimization
交叉验证
首先用几个小epoch来获取可以使用的参数,然后再对这些参数进行调试(finer search)。
最终选择的参数不能只考虑准确度,如果该准确度所对应的学习率很大,那么要担心该超参下的参数是否很好遍历了整个参数空间。
finer search 选择参数时最好使用random layout(随机选择),而不是使用gird layout。
参数选择时最好在log空间内选择。