如何通过反向传播算法(backprogapation)和梯度下降算法(gradient decent)调整神经网络中参数的取值。
梯度下降算法: 主要用于优化单个参数的取值。
反向传播算法: 根据定义好的损失函数(梯度下降算法)优化神经网络中参数的取值,从而使神经网络模型在训练数据集上的损失函数达到一个较小值。
梯度下降算法
假设用 θ \theta θ 表示神经网络中的参数, J ( θ ) J(\theta) J(θ) 表示在给定的参数取值下,训练数据集中损失函数的大小。
优化过程抽象为:
寻找一个参数
θ
\theta
θ,使得
J
(
θ
)
J(\theta)
J(θ) 最小。
目前没有一个通用的方法对任意损失函数直接求解最佳的参数取值。
在实践中,梯度下降算法是最常用的神经网络优化方法。
梯度下降算法会迭代式更新参数 θ \theta θ,不断沿着梯度的反方向让参数朝着总损失更小的方向更新。
图像解释
下面的曲线表示了在参数 θ \theta θ 取不同值时,对应损失函数 J ( θ ) J(\theta) J(θ) 的大小。
- x 轴表示参数 θ \theta θ 的取值;
- y 轴表示损失函数
J
(
θ
)
J(\theta)
J(θ) 的值。
假设当前参数和损失值对应上图中小圆点的位置,那么梯度下降算法会将参数向 x 轴左侧移动,从而使得小圆点朝着箭头的方向移动。
- 参数的梯度用求偏导的方式计算:
对 于 参 数 θ , 其 梯 度 为 δ δ θ J ( θ ) 。 对于参数 \theta ,其梯度为 \frac{\delta}{\delta \theta}J(\theta)。 对于参数θ,其梯度为δθδJ(θ)。 - 定义一个学习率 η \eta η (learning rate)来定义每次参数更新的幅度。——(从图像上看,学习率定义的就是每次参数移动的幅度)
- 通过参数的梯度和学习率,参数更新的公式为:
θ n + 1 = θ n − η δ δ θ n J ( θ n ) \theta_{n+1}=\theta_n - \eta \frac{\delta}{\delta\theta_n}J(\theta_n) θn+1=θn−ηδθnδJ(θn)
具体例子
梯度下降算法的步骤:
随机产生一个参数
x
x
x 的初始值,通过梯度和学习率来更新参数
x
x
x 的取值。
假设要通过梯度下降算法来优化参数
x
x
x,使得损失函数
J
(
x
)
=
x
2
J(x)=x^2
J(x)=x2 的值尽可能的小。
参
数
x
的
梯
度
为
∇
=
δ
J
(
x
)
δ
x
=
2
x
参数\ x\ 的梯度为\ \nabla=\frac{\delta J(x)}{\delta x} = 2x
参数 x 的梯度为 ∇=δxδJ(x)=2x
则,梯度下降算法每次对参数
x
x
x 的更新公式为:
x
n
+
q
=
x
n
−
η
∇
n
x_{n+q} = x_n - \eta \nabla_n
xn+q=xn−η∇n
假设参数的初始值为 5,学习率为 0.3,则整个优化过程如下表所示:
可以看出,经过 5 次迭代之后,参数
x
x
x 的值变成了 0.0512,这个和参数最优值 0 已经比较接近了。
神经网络的优化过程
神经网络的优化过程可以分为两个阶段:
- 第一个阶段通过前向传播算法计算得到预测值,并将预测值和真实值做对比得出两者之间的差距;
- 第二个阶段通过反向传播算法计算损失函数对每一个参数的梯度,再根据梯度和学习率使用梯度下降算法更新每一个参数。
梯度下降算法的问题
- 梯度下降算法并不能保证被优化的函数达到全局最优解。
如下图,图中给出的函数就有可能只能得到局部最优解。
在小黑点处,损失函数的偏导为 0,于是参数就不会再进一步更新。
- 梯度下降算法的另一个问题就是计算时间太长。
因为要在全部训练数据上最小化损失,所以损失函数 J ( θ ) J(\theta) J(θ) 是在所有训练数据上的损失和。
这样在每一轮迭代中都需要计算在全部训练数据上的损失函数。
在海量训练数据下,要计算所有训练数据的损失函数时非常消耗时间的。
梯度下降算法的优化
随机梯度下降算法(stochastic gradient descent)
目的: 加速优化过程。
优化: 在每一轮迭代中,随机优化某一条训练数据上的损失函数。
问题: 因为每次优化的只是某一条数据上的损失函数,而在某一条数据上损失函数更小并不代表在全部数据上损失函数更小,所以使用随机梯度下降优化得到的神经网络甚至可能无法达到局部最优。
实际应用中的优化方案
采用折中方法: 每次计算一小部分(一个 batch)训练数据的损失函数。
原因:
- 通过矩阵运算,每次在一个 batch 上优化神经网络的参数并不会比单个数据慢太多。
- 每次使用一个 batch 可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的结果。
# 在 TensorFlow 中实现神经网络的训练过程。
batch_size = n
#每次读取一小部分数据作为当前的训练数据来执行反向传播算法
x = tf.placeholder(tf.float32, shape=(batch_size, 2), name='x-input')
y_ = tf.placeholder(tf.float32, shape=(batch_size, 1), name='y-input')
# 定义盛景网络结构和优化算法
loss = ,,,
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
# 训练神经网络
with tf.Session() as sess:
# 参数初始化
...
# 迭代的更新参数
for i in range(STEPS):
# 准备 batch_size 个训练数据。一般将所有训练数据随机打乱之后再选取可以得到。
# 更好的优化效果
current_X, current_Y = ...
sess.run(train_step, feed_dict=(x: current_X, y_: current_Y))