机器学习实战-训练模型

  有了前面的基础,现在可以训练模型了。前面的讨论基本上把模型当成了以黑匣子,但是,如果我们不能对模型有进一步的认识,就不能快速地理解我们的使用的系统的运行原理。不仅如此,对模型的理论认知,有助于我们快速地选择模型、模型地训练方法以及一套适当的超参数,在后期还有助于执行错误分析和改善。因此,对模型地理论认知是非常必要。首先让我们从最简单地模型之一--线性回归 - 开始。
  

  线性回归:

  线性回归就是对输入的特征进行加权求和,再加上一个偏置项(也称为截距)来进行预测。模型训练就是设置或者说寻找参数是的模型在训练集上的成本函数最小的过程。那么如何来评价模型对训练集的拟合程度呢?一般来说有MES和RMSE指标,实际应用中,计算MSE比计算RMSE更简单,而且两者的效果一样,因为使得函数最小化的条件同样使得函数的平方根最小化。MSE成本函数形式如下:

  

  模型训练也就是求解theta使得该函数 最小化。这个问题有两种非常不同的解决方法:

  1.通过“闭式”方程,直接求解theta;

  2.通过迭代优化的方法,逐渐改变theta的值使得函数趋于最小化,最后与方法1的结果相近。

      首先试试方法1.

  生成一些线性数据来测试上面的theta求解公式:

  import numpy as npX = 2 * np.random.rand(100, 1)

  y = 4 + 3 * X + np.random.randn(100,1)

  用标准方程求解theta

  X_b = np.c_[np.ones((100, 1)), X] # add x0 = 1 to each instance

  theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)

  生成数据的函数是 y=4 + 3*x +高斯噪声

     求解得到的theta为:

  theta_best
  array([[ 4.21509616],
  [ 2.77011339]])

  噪声的存在使其不可能完全还原为原本的函数。

  现在可以用theta进行预测了:

  >>> X_new = np.array([[0], [2]])

  >>> X_new_b = np.c_[np.ones((2, 1)), X_new] # add x0 = 1 to each instance

  >>> y_predict = X_new_b.dot(theta_best)

  >>> y_predictarray([[ 4.21509616],[ 9.75532293]

  直接用sklearn的话就更简单了:

  >> from sklearn.linear_model import LinearRegression
  >>> lin_reg = LinearRegression()
  >>> lin_reg.fit(X, y)
  >>> lin_reg.intercept_, lin_reg.coef_
  (array([ 4.21509616]), array([[ 2.77011339]]))
  >>> lin_reg.predict(X_new)
  array([[ 4.21509616],
  [ 9.75532293]])

  也就是说sklearn的LinearRegression()函数用的就是标准方程来求解。

   标准方程求解的局限在于,矩阵求逆比较复杂,当特征维数比较大时,方程的求解非常缓慢。但是,一旦线性回归模型训练好了,其预测速度是非常快的,而且预测的计算复杂度对于实例数和特征维数都是线性的 。

  迭代优化

  1. 梯度下降

  注意这里是梯度下降而不是函数下降。梯度是函数的方向导数中最大的一个,在这个方向上函数变化率最大,因此梯度下降也就意味着函数在这个方向上下降的速率最快。比如说你站在山顶,现在要以最快的速度下山,那么最好的办法就是沿着最陡峭的地方行进,最后到底山底,梯度也就趋于最小。使用SG的挑战在于,并非所有成本函数都很规则,这时使用GD就可能会陷入局最小值。好消息是线性模型的成本函数MSE是一个凸函数,就是说连接曲线上的任意两个点,与曲线不会有其他的交点,这也就意味着它只有一个极值,因此,对于线性回归模型,即使乱走,也就是说从任意的初始点开始,只要一直往下走,就一定会到达一个极值点,而这个极值点是全局最值。对于一些成本函数可不是这样,初始值可能会导致收敛速度非常慢,甚至陷入局部极值。

  ·使用GD方法来训练线性回归模型需要保证所有特征的大小是差不多的,这是因为,虽然MSE成本函数虽然是碗状的,但是,如果一个特征数值很小,那么在训练过程中就需要很大的系数来影响成本函数,而这个迭代过程会占去很多的迭代时间。前面我们有提到当特征值的数量级相差太大是甚至会影响输出结果,现在我们有看到它的另一个影响。

  批量梯度下降

  梯度下降是一种理论方法,具体怎样实现梯度下降呢?由于多维特征对应着多元函数,所以这里要用到偏导数,直接得到梯度向量如下:

  

  可以看到计算梯度下降的每一次迭代是都是在整个训练集上进行的,所有当实例数目很大时,算法训练会很慢。不过GD随特征数量的扩展表现比较好,就是说同样多的实例数目,特征维数增加是,训练速度变化不是很大。

  一旦有了梯度向量,那个点方向向上,就往反方向下坡。注意这里当梯度为正是,当theta变大时,成本函数值是增加的,而我们要下坡,要往下走,就是说当梯度为正是,我们要调整theta,使其变小,这样成本函数才会减小,往下走:

              

   这里有一个学习参数,用来控制步长,步长太小,收敛速度慢,步长太大可能会直接跳过最优值。要找到合适的学习率,可以使用网格法,这可能需要设置迭代次数,如何设置迭代次数能,迭代次数也可能导致无法达到最优值就停止了,迭代次数太高又可能在到底最优值后继续迭代,浪费时间。一个窍门是开始时设置一个很高的迭代次数,当梯度梯度向量变化(注意不是成本函数)低于容差时,中断算法。

  随机梯度下降(SGD)

  批量梯度下降每次迭代都要使用整个训练集的数据,而SGD在每次迭代是只使用一个实例,这使得它的速度大大提升,因此可以用来训练海量数据 ,对于非常不规则的成本函数也有助于逃离局部最小值,这种情况下它比批量梯度下降更有优势。但是,在迭代过程中成本函数不是缓缓地趋于最小值,而是不断波动,但整体还是下降的,也就是螺旋式地下降。即使到了最小值附近,这种波动也永远不会停止。它的不足在于无法找到最小值,为了尽可能地接近最小值,可以使用模拟退火法:在开始步长比较大(有助于快速接近最小值和跳出局部陷阱),然后逐渐减小学习速率。这里有一点,在迭代过程中,可能有的实例使用了几次,而有的实例一次都没有用到,如果想避免这种情况可以在每次迭代后将训练集洗牌,这通常导致收敛速度更慢。

  小批量梯度下降

  小批量梯度下降方法每次迭代只使用训练集小批量的实例,它比GD在速度上有优势,同时也往往比SGD更接近最小值,尤其是批量比较大时。

  

  

   

猜你喜欢

转载自www.cnblogs.com/gadflyWZQ/p/10779860.html