当前位置:   article > 正文

梯度下降算法Python代码实现--批量梯度下降+随机梯度下降+小批量梯度下降法_在给定数据集上使用随机梯度下降方法或者小批量梯度下降方法编程实现线性回归模型

在给定数据集上使用随机梯度下降方法或者小批量梯度下降方法编程实现线性回归模型

     

 

        在学习线性回归的时候很多课程都会讲到用梯度下降法求解参数,对于梯度下降算法怎么求出这个解讲的较少,自己实现一遍算法比较有助于理解算法,也能注意到比较细节的东西。具体的数学推导可以参照这一篇博客(梯度下降(Gradient Descent)小结 - 刘建平Pinard - 博客园

一、       首先,我们用一个简单的二元函数用梯度下降法看下算法收敛的过程

              也可以改一下eta,看一下步长如果大一点,算法的收敛过程

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. plot_x = np.linspace(-1,6,140)
  4. plot_y = (plot_x-2.5)**2-1
  5. #先算出来当前函数的导数
  6. def dJ(theta):
  7. return 2*(theta-2.5)
  8. #梯度函数
  9. def J(theta):
  10. return (theta-2.5)**2-1
  11. #初始化theta=0
  12. #步长eta设置为0.1
  13. eta = 0.1
  14. theta_history = []
  15. theta = 0
  16. epsilon = 1e-8
  17. while True:
  18. gredient = dJ(theta)
  19. last_theta = theta
  20. theta = theta - eta*gredient
  21. theta_history.append(theta)
  22. if(abs(J(theta) - J(last_theta)) < epsilon):
  23. break
  24. print(theta)
  25. print(J(theta))
  26. plt.plot(plot_x, J(plot_x))
  27. plt.plot(np.array(theta_history),J(np.array(theta_history)),color='r',marker='+')
  28. plt.show()

出来的结果如下:

二、在线性回归模型中训练算法--批量梯度下降Batch Gradient Descent

首先,构建一个函数

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. np.random.seed(666)
  4. x = 2 * np.random.random(size=100)
  5. y = x*3. + 4. + np.random.normal(size=100)
  6. #然后改成向量的形式
  7. X = x.reshape(-1,1)
  8. plt.scatter(x,y)
  9. plt.show()

然后写实现梯度下降法求解我们构建的这个函数:

  1. def J(theta , X_b , y):
  2. try:
  3. return sum((y-X_b.dot(theta))**2)/len(X_b)
  4. except:
  5. return float('inf')
  6. #这里使用的是每次求一个参数,然后组合在了一起成了res
  7. def dJ(theta, X_b ,y):
  8. res = np.empty(len(theta))
  9. res[0] = np.sum(X_b.dot(theta) - y)
  10. for i in range(1, len(theta)):
  11. res[i] = (X_b.dot(theta) - y).dot(X_b[:,i])
  12. return res * 2 / len(X_b)
  13. #这里也可以直接用矩阵运算求出所有的参数,效率更高
  14. #return X_b.T.dot(X_b.dot(theta)-y)*2. / len(y)

然后把上面的过程封装成函数形式:

  1. #把整个算法写成函数的形式
  2. def gradient_descent(X_b, y ,inital_theta, eta ,n_inters = 1e4, epsilon = 1e-8):
  3. theta = initial_theta
  4. i_inter = 0
  5. while i_inter < n_inters:
  6. gradient = dJ(theta, X_b, y)
  7. last_theta = theta
  8. theta = theta - eta*gradient
  9. if(abs(J(theta,X_b,y) - J(last_theta,X_b,y)) < epsilon):
  10. break
  11. i_inter += 1
  12. return theta

然后用我们实现的算法求解上面那个函数:

  1. #这里加一列1
  2. X_b = np.hstack([np.ones((len(x),1)), x.reshape(-1,1)])
  3. #初始theta设置为0
  4. initial_theta = np.zeros(X_b.shape[1])
  5. eta = 0.01
  6. theta = gradient_descent(X_b, y, initial_theta, eta)
  7. theta

输出结果如下:

array([4.02145786, 3.00706277])

使用梯度下降法时,由于不同维度之间的值大小不一,最好将数据进行归一化,否则容易造成不收敛

、在线性回归模型中训练算法--随机梯度下降Stochastic Gradient Descent

   随机梯度下降法可以训练更少的样本就得到比较好的效果,下面用两段代码比较下。

这个就是之前的批量梯度下降,不过换了一个数据集

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. m = 100000
  4. x = np.random.normal(size = m)
  5. X = x.reshape(-1,1)
  6. y = 4. * x + 3. +np.random.normal(0,3,size = m)
  7. def J(theta , X_b , y):
  8. try:
  9. return sum((y-X_b.dot(theta))**2)/len(X_b)
  10. except:
  11. return float('inf')
  12. def dJ(theta, X_b ,y):
  13. return X_b.T.dot(X_b.dot(theta)-y)*2. / len(y)
  14. def gradient_descent(X_b, y ,inital_theta, eta ,n_inters = 1e4, epsilon = 1e-8):
  15. theta = initial_theta
  16. i_inter = 0
  17. while i_inter < n_inters:
  18. gradient = dJ(theta, X_b, y)
  19. last_theta = theta
  20. theta = theta - eta*gradient
  21. if(abs(J(theta,X_b,y) - J(last_theta,X_b,y)) < epsilon):
  22. break
  23. i_inter += 1
  24. return theta
  1. %%time
  2. X_b = np.hstack([np.ones((len(x),1)), X])
  3. initial_theta = np.zeros(X_b.shape[1])
  4. eta = 0.01
  5. theta = gradient_descent(X_b, y, initial_theta, eta)
  6. theta

结果如下:

Wall time: 37.2 s

theta:

array([3.00590902, 4.00776602])

下面我们用随机梯度下降:

  1. #这里每次求一行数据的梯度,所以后面不用除以m
  2. def dJ_sgd(theta, X_b_i, y_i):
  3. return X_b_i.T.dot(X_b_i.dot(theta) - y_i)* 2.
  4. #随机梯度下降法学习率设置t0/(t+t1)这种形式
  5. #由于梯度下降法随机性,设置最后的结果的时候只设置最大迭代次数
  6. def sgd(X_b, y, initial_theta, n_iters):
  7. t0 = 5
  8. t1 = 50
  9. def learning_rate(t):
  10. return t0/(t+t1)
  11. theta = initial_theta
  12. for cur_iter in range(n_iters):
  13. #下面是设置每次随机取一个样本
  14. rand_i = np.random.randint(len(X_b))
  15. gradient = dJ_sgd(theta, X_b[rand_i], y[rand_i])
  16. theta = theta - learning_rate(cur_iter) * gradient
  17. return theta
  18. %%time
  19. X_b = np.hstack([np.ones((len(x),1)), X])
  20. initial_theta = np.zeros(X_b.shape[1])
  21. theta = sgd(X_b, y, initial_theta, n_iters=len(X_b)//3)

结果如下:

Wall time: 481 ms

theta:

array([2.93906903, 3.99764075])

对比下两者的运行时间,随机梯度下降法计算量更小,时间也大大减少。

四、小批量梯度下降法-Mini-Batch Gradient Descent

这个完全按照自己理解写下,如果有大牛指点下不胜感激。

小批量梯度下降法主要在于每次训练的数据量不同,随机梯度下降是有一个样本就训练一次,小批量梯度下降是有一批样本训练一次,这里默认参数我给100

  1. #这里每次求一行数据的梯度,所以后面不用除以m
  2. def dJ_sgd(theta, X_b_i, y_i):
  3. return X_b_i.T.dot(X_b_i.dot(theta) - y_i)* 2.
  4. def sgd(X_b, y, initial_theta, n_iters,n=100):
  5. t0 = 5
  6. t1 = 50
  7. def learning_rate(t):
  8. return t0/(t+t1)
  9. theta = initial_theta
  10. for cur_iter in range(n_iters):
  11. #下面是设置每次随机取一个样本
  12. for i in range(n):
  13. rand_i = []
  14. rand_i_1 = np.random.randint(len(X_b))
  15. rand_i.append(rand_i_1)
  16. gradient = dJ_sgd(theta, X_b[rand_i], y[rand_i])
  17. theta = theta - learning_rate(cur_iter) * gradient
  18. return theta

然后还是用之前的数据集测试下:

  1. %%time
  2. import numpy as np
  3. X_b = np.hstack([np.ones((len(x),1)), X])
  4. initial_theta = np.zeros(X_b.shape[1])
  5. theta = sgd(X_b, y, initial_theta,n=5, n_iters=len(X_b)//3)

结果如下:

Wall time: 643 ms

这里每次给5个样本,耗费的时间还是很长的,不知道是不是代码写的有问题。

结果来看是对的:

array([2.96785569, 4.00405719])
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/319155?site
推荐阅读
相关标签
  

闽ICP备14008679号