从机器学习到无人驾驶
上QQ阅读APP看书,第一时间看更新

3.5 梯度下降模型实例

实例1:使用Python实现线性回归梯度下降模型

在3.3节中我们使用最小二乘法完成了一元线性回归的参数求解过程,本节的第一个例子就使用Python完成梯度下降算法对3.3节数据集合对应的一元线性回归模型进行求解。代码如下:

   import numpy as np
   from numpy import dot
   from numpy import mat

   #y=2x
   X = mat([1,2,3]).reshape(3, 1)
   Y = 2*X
   theta = 1.
   alpha = 0.1
   for i in range(100):
      theta = theta + np.sum(alpha * (Y- dot(X, theta))*X.reshape(1,3))/3.
   print(theta)

数据准备部分与3.3节完全相同,在这里就不赘述了。接下来的代码是模型参数的初始化,我们人为设定起始参数为1.0,也可以使用随机算法生成随机参数。另外,我们还需要指定学习速率,在本例中使用0.1。

theta = 1

alpha = 0.1

然后指定梯度下降的学习速率,学习速率在这里指定为0.1。一般来说,梯度下降学习速率太快(α过大)容易导致算法无法收敛,梯度下降学习速率太慢(α过小)容易造成计算资源的浪费和模型运行时间过长。

   for i in range(100):
      theta = theta + np.sum(alpha * (Y- dot(X, theta))*X.reshape(1,3))/3.

接下来的代码进行参数更新,即梯度下降的实际运行过程通过NumPy矩阵运算,我们很容易就可以完成更新量的计算,通过循环更新参数集合100次。整个过程比较清晰,但是有一点需要特别注意,如果是多元线性回归模型,就需要在一次计算中同步更新参数矩阵的所有要素。

例如下面的三元线性回归模型中,每次循环中需要对参数矩阵的4个要素同时进行更新。

   for i in range(10000):
      temp[0] = theta[0] + alpha*np.sum((Y-dot(X, theta))*X0)/150.
      temp[1] = theta[1] + alpha*np.sum((Y-dot(X, theta))*X1)/150.
      temp[2] = theta[2] + alpha*np.sum((Y-dot(X, theta))*X2)/150.
      temp[3] = theta[3] + alpha*np.sum((Y-dot(X, theta))*X3)/150.
      theta = temp

实例2:使用TensorFlow框架实现线性回归梯度下降模型

本例介绍使用TensoFlow进行线性回归的过程。

   import tensorflow as tf

   x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)
   y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32)

   linear_model = tf.layers.Dense(units=1)

   y_pred = linear_model(x)
   loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)

   optimizer = tf.train.GradientDescentOptimizer(0.01)
   train = optimizer.minimize(loss)

   init = tf.global_variables_initializer()

   sess = tf.Session()
   sess.run(init)
   for i in range(100):
     _, loss_value = sess.run((train, loss))
     print(loss_value)

   print(sess.run(y_pred))

虽然使用TensorFlow看起来代码量比使用Python的NumPy框架进行数学运算时多不少,但是本实例代码完美地体现了TensorFlow的设计思想,具有平滑的学习曲线这样一个内在优势。因此,线性回归过程完成机器学习代数化向语义的进化,这样一套代码完全遵守TensorFlow机器学习的标准流程(模型构建、模型初始化、模型训练),而且将复杂的数学表达式封装成了mean_squared_error等方法,也使初级开发者更加容易掌握,而高级开发者可以聚焦模型构建本身。

首先是框架的引入和数据的准备,为了能够聚焦到线性回归模型本身,我们依然使用非常简单的数据集合,使用TensorFlow中的常量来直接存储。

   x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)
   y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32)

接下来的部分是模型的构建过程,也是我们要重点讲解的内容。

   linear_model = tf.layers.Dense(units=1)

此处建立一个一元线性模型,units=1表示输入一个参数。这里我们使用了TensorFlow自己的层模型,也可以用Keras模块中的层模型进行替换。

   y_pred = linear_model(x)
   loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)
   optimizer = tf.train.GradientDescentOptimizer(0.01)
   train = optimizer.minimize(loss)

通过mean_squared_error告知了TensorFlow在框架运行时计算预测值和标签值的偏差平方和,并以最小化这个值作为训练目的(optimizer.minimize(loss))。

   init = tf.global_variables_initializer()

   sess = tf.Session()
   sess.run(init)
   for i in range(100):
     _, loss_value = sess.run((train, loss))
     print(loss_value)

   print(sess.run(y_pred))

上面的代码是训练过程的详细实现,我们惊喜地发现,训练过程(包含参数初始化)和第2章例子的流程完全一致,因此在学习过程中只要聚焦于模型构建本身就可以了。