概念

梯度下降法是一种寻找函数最小值的一阶最优化算法,为找到函数的局部最小值,需要采用与当前点处函数的梯度(或者是近似梯度)的反方向成比例的步长进行迭代搜索。直观地来看,假如我们处于一座山的顶端,想要寻找最快的下山方法。从几何意义上讲,梯度的方向是函数值增加最快的方向,所以梯度的反方向就是函数值下降最快的方向。我们在每一点反复求取梯度,最后到达局部的最小值,就可以下山了。

![](/img/Gradient Descent.png)

算法

我们首先需要确认模型的假设函数和代价函数。以线性回归为例,假设函数表示为: $$ h_{\theta}(x_0, x_1, …, x_n) = \theta_0 + \theta_1x_1 + … +\theta_nx_n $$ 代价函数为,这里选用均方误差,其中m指的是模型的样本容量: $$ J(\theta_0, \theta_1, …, \theta_n) = \frac{1}{2m}\sum_{j=0}^{m}(h_{\theta}(x_0^{(j)}, x_1^{(j)}, …, x_n^{(j)}) - y_j)^2 $$

我们的目标就是找出一个最佳的假设函数,使得这个函数对于给定数据集的预测产生的误差最小。具体来说,就是找出这些假设函数中的$\theta$,寻找使函数误差最小的$\theta$, 就需要用到梯度下降法,公式如下: $$ \theta_i = \theta_i - \alpha\frac{\partial}{\partial\theta_i}J(\theta_0, \theta_1, …, \theta_n) $$ 其中$\alpha$是步长或称学习率,我们可以通过$\alpha$来控制每一步走的距离,$\alpha$不能太大也不能太小,太小的话,可能一直走不到最低点,太大的话,会导致越过最低点。每一次计算,同时更新所有的$\theta$,重复迭代,最终求得结果。

TensorFlow实现

接下来,我们用TensorFlow来模拟一下梯度下降算法的过程。首先初始化需要的参数:

def fun(a, b): # 假设函数y=a*x+b
    return a * x + b

LR = 0.1  # 学习率
REAL_PARAMS = [1.2, 2.5]  # 需要拟合的真实参数
INIT_PARAMS = [2, 4.5]  # 初始化参数

x = np.linspace(0, 5, 100, dtype=np.float32)   # 从0到5的100组浮点数据
y = fun(*REAL_PARAMS) + np.random.randn(100)   # 构建(x,y)离散数据

接下来初始化a、b两个参数,然后进行预测,计算误差,最后优化。

a, b = [tf.Variable(initial_value=p, dtype=tf.float32) for p in INIT_PARAMS] # 使用Variable方法初始化
predict = fun(a, b)  # 根据参数预测y值
mse = tf.reduce_mean(tf.square(y - predict))  # 均方误差,预测值与真实值相比较
train_op = tf.train.GradientDescentOptimizer(LR).minimize(mse)  # 载入学习率和代价函数训练

下一步开始训练,记录两个参数和误差的变化。

a_pram, b_pram, cost = [], [], []
with tf.Session() as sess:  # 开启TensorFlow会话
    sess.run(tf.global_variables_initializer())  # 初始化参数
    for _ in range(1000):  # 进行1000次训练
        a_, b_, mse_ = sess.run([a, b, mse])  # 计算a,b和误差
        a_pram.append(a_)
        b_pram.append(b_)
        cost.append(mse_)  
        result, _ = sess.run([predict, train_op])  # 记录

最后一步进行可视化,最终训练出来的预测线见下图:

plt.figure(1)
plt.scatter(x, y, c='b')    # 离散数据,颜色为蓝色
plt.plot(x, result, 'r-', lw=2)   # 最终拟合线,红色直线
plt.show()

![](/img/Gradient Descent_plot.png) 输出的两个参数为:a = 1.1968814, b = 2.532204,与真实参数1.2和2.5已经很接近了。

参考资料: 梯度的方向为什么是函数值增加最快的方向? 梯度下降(Gradient Descent)小结 用 Tensorflow 可视化梯度下降