• 梯度下降


    梯度下降是不同于Normal Equals的方式;梯度本质是一个试错过程,不断的尝试一个个theta,寻找能够使的成本函数值最小的可能性。所谓下降是指不断的theat的取值是不断小步减少的;梯度,是指这个减少是逐渐,非线性的。

    梯度下降有三种常见的函数:批量梯度下降,随机梯度下降以及最小化梯度下降。

    先来看批量梯度下降,在Normal Equal里面我们接触了函数MSE,那么在梯度下降里面我们还是要接触这个MSE,但是因为theta值有多个,所以,每个theta都是一个维度,对于某个指定维度求最小值,我们对其进行求导:

    如果想要同时对多个theta求向量,可以放置到一个向量中进行,公式如下:

    这样对于多个theta的最小成本函数的求值转变为了矩阵公式(上图右侧部分)。因为线性的成本函数是凸函数,所以我们不用安心拐点问题,只要theta值不断减少,cost值就会不断减少。通常的做法是定义一个迭代的次数,即梯度的台阶数,向下的每个台阶都比之前的台阶要小,小的程度就是上面公式的计算值;这样获取到的theta就是某种程度上满足了的成本函数的最小值。

    实现的python代码如下:

    theta_path_bgd = []

    def plot_gradient_descent(theta, eta, theta_path=None):

    m = len(X_b)

    plt.plot(X, y, "b.")

    n_iterations = 1000 # 定义迭代的次数

    for iteration in range(n_iterations):

        #为了更加直观,前10个数据(线段)将会被打印出来

    if iteration < 10:

    y_predict = X_new_b.dot(theta)

    style = "b-" if iteration > 0 else "r--"

    plt.plot(X_new, y_predict, style)

    gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y) #核心的公式计算,计算下降的梯度

    theta = theta - eta * gradients #theta值

    if theta_path is not None:

    theta_path.append(theta)

    plt.xlabel("$x_1$", fontsize=18)

    plt.axis([0, 2, 0, 15])

    plt.title(r"$eta = {}$".format(eta), fontsize=16)

     

    rnd.seed(42)

    theta = rnd.randn(2,1) # random initialization

     

    plt.figure(figsize=(10,4))

    plt.subplot(131); plot_gradient_descent(theta, eta=0.02)

    plt.ylabel("$y$", rotation=0, fontsize=18)

    plt.subplot(132); plot_gradient_descent(theta, eta=0.1, theta_path=theta_path_bgd)

    plt.subplot(133); plot_gradient_descent(theta, eta=0.5)

    plt.show()

     

    划线的部分就是公式计算部分,也是整个计算过程的核心;在真实调用中,分别通过学习率0.02,0.1以及0.5进行学习,学习的效果如下图所示,可见学习率在0.1的时候是最好的,但是在0.5则有些过,而且现象是线段在点集的上下乱窜,说明这个学习率是不可取的。0.02则学习的结果则是总在点集的下方。

    批量的梯度下降已经比normal equals快很多了为什么快?因为NE的算法中用一个矩阵的inverse(求逆矩阵),对NE算法而言将会导致一个N*N矩阵的一次求逆矩阵的操作,非常耗时,这一点在属性(feature)很大的时候,将会非常明显,所以如果万级别的,NE操作比较合适,但是超过万级别的,梯度下降的算法将会更优,当然这个说法有待验证。

    但是每次梯度计算都是要全集计算,仍然开销很大;有一种方法开销非常小,而且得到的效果和全量计算差不多的,那就是随机梯度下降。他的算法就是随机抽取m个X,y值,然后根据这个X,y值来计算梯度,注意此X非彼X,只是X全集中的一个元素,矩阵中的一列(一行),y其实只是一个值,这样你在来通过公式来算梯度,那可就小的多了。

    Python实现如下:

    theta_path_sgd = []

    n_iterations = 50

    t0, t1 = 5, 50 # learning schedule hyperparameters

    rnd.seed(42)

    theta = rnd.randn(2,1) # random initialization

    def learning_schedule(t):

    return t0 / (t + t1)

    m = len(X_b)

    for epoch in range(n_iterations): #迭代n次(N个台阶下降)

    for i in range(m): #每次取m个值进行梯度下降

    if epoch == 0 and i < 20:

    y_predict = X_new_b.dot(theta)

    style = "b-" if i > 0 else "r--"

    plt.plot(X_new, y_predict, style)

    random_index = rnd.randint(m)

    xi = X_b[random_index:random_index+1] #取出X值,一个向量

    yi = y[random_index:random_index+1] #取出y值,单个值

    gradients = 2 * xi.T.dot(xi.dot(theta) - yi) #梯度值

    eta = learning_schedule(epoch * m + i) #学习率,这个公式什么用意,其实没懂

    theta = theta - eta * gradients

    theta_path_sgd.append(theta)

     

    plt.plot(X, y, "b.")

    plt.xlabel("$x_1$", fontsize=18)

    plt.ylabel("$y$", rotation=0, fontsize=18)

    plt.axis([0, 2, 0, 15])

    plt.show()

    theta

    array([[3.90754833] ,[3.1762325 ]])

    然后用ski内置的梯度下降SGDRegression来求解,注意:SGDRegression内部封装的就是随机梯度下降的算法:

    from sklearn.linear_model import SGDRegressor

    sgd_reg = SGDRegressor(max_iter=50, penalty=None, eta0=0.1)

    sgd_reg.fit(X, y.ravel())

    sgd_reg.intercept_, sgd_reg.coef_

    输出:

    (array([3.87605957]), array([3.08965292]))

    基本是一样的,SGD里面的算法就是酱紫的(上面的上面的代码)。

    最后一种就是mini-batch,其实和随机梯度下降非常类似,只不过SGD每次取出一个X,y,mini-batch则是每次取出一批来,差别就在这里,下面是实现:

    theta_path_mgd = []

     

    n_iterations = 50

    minibatch_size = 20

     

    rnd.seed(42)

    theta = rnd.randn(2,1) # random initialization

     

    t0, t1 = 10, 1000

    def learning_schedule(t):

    return t0 / (t + t1)

     

    t = 0

    for epoch in range(n_iterations):

    shuffled_indices = rnd.permutation(m)

    X_b_shuffled = X_b[shuffled_indices]

    y_shuffled = y[shuffled_indices]

    for i in range(0, m, minibatch_size): # 遍历m次,每次增长minibatch_size

    t += 1

    xi = X_b_shuffled[i:i+minibatch_size]

    yi = y_shuffled[i:i+minibatch_size]

    gradients = 2 * xi.T.dot(xi.dot(theta) - yi)

    eta = learning_schedule(t)

    theta = theta - eta * gradients

    theta_path_mgd.append(theta)

  • 相关阅读:
    UNIX网络编程(转载)
    cin、cin.get()、cin.getline()、getline()、gets()等函数的用法(转)
    GSL GNU Scientific Library
    为人处事很有意义
    上海老大杜月笙——教你看穿一个人
    超实用的Linux/Unix快捷键大汇总(开发、管理)(2)(转)
    STL map常用操作简介(转)
    使用ifstream和getline读取文件内容[c++]
    VIM Tips
    超实用的Linux/Unix快捷键大汇总(开发、管理)(1)(转)
  • 原文地址:https://www.cnblogs.com/xiashiwendao/p/9470684.html
Copyright © 2020-2023  润新知