侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

python实现梯度下降算法

Python  /  管理员 发布于 7年前   189

梯度下降(Gradient Descent)算法是机器学习中使用非常广泛的优化算法。当前流行的机器学习库或者深度学习库都会包括梯度下降算法的不同变种实现。

本文主要以线性回归算法损失函数求极小值来说明如何使用梯度下降算法并给出python实现。若有不正确的地方,希望读者能指出。 

梯度下降

梯度下降原理:将函数比作一座山,我们站在某个山坡上,往四周看,从哪个方向向下走一小步,能够下降的最快。

在线性回归算法中,损失函数为

在求极小值时,在数据量很小的时候,可以使用矩阵求逆的方式求最优的θ值。但当数据量和特征值非常大,例如几万甚至上亿时,使用矩阵求逆根本就不现实。而梯度下降法就是很好的一个选择了。

使用梯度下降算法的步骤:

1)对θ赋初始值,这个值可以是随机的,也可以让θ是一个全零的向量。

2)改变θ的值,使得目标损失函数J(θ)按梯度下降的方向进行减少。

其中为学习率或步长,需要人为指定,若过大会导致震荡即不收敛,若过小收敛速度会很慢。

3)当下降的高度小于某个定义的值,则停止下降。

另外,对上面线性回归算法损失函数求梯度,结果如下:

在实际应用的过程中,梯度下降算法有三类,它们不同之处在于每次学习(更新模型参数)使用的样本个数,每次更新使用不同的样本会导致每次学习的准确性和学习时间不同。下面将分别介绍原理及python实现。

 批量梯度下降(Batch gradient descent)   

每次使用全量的训练集样本来更新模型参数,即给定一个步长,然后对所有的样本的梯度的和进行迭代: 

梯度下降算法最终得到的是局部极小值。而线性回归的损失函数为凸函数,有且只有一个局部最小,则这个局部最小一定是全局最小。所以线性回归中使用批量梯度下降算法,一定可以找到一个全局最优解。

优点:全局最优解;易于并行实现;总体迭代次数不多
缺点:当样本数目很多时,训练过程会很慢,每次迭代需要耗费大量的时间。

随机梯度下降(Stochastic gradient descent) 

随机梯度下降算法每次从训练集中随机选择一个样本来进行迭代,即:

随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。 

随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进行,因此可以带来优化波动(扰动)。不过从另一个方面来看,随机梯度下降所带来的波动有个好处就是,对于类似盆地区域(即很多局部极小值点)那么这个波动的特点可能会使得优化的方向从当前的局部极小值点跳到另一个更好的局部极小值点,这样便可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。 

优点:训练速度快,每次迭代计算量不大
缺点:准确度下降,并不是全局最优;不易于并行实现;总体迭代次数比较多。

Mini-batch梯度下降算法

 Mini-batch梯度下降综合了batch梯度下降与stochastic梯度下降,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择b,b<m个样本进行学习,即:

python代码实现

批量梯度下降算法

#!/usr/bin/python#coding=utf-8import numpy as npfrom scipy import statsimport matplotlib.pyplot as plt # 构造训练数据x = np.arange(0., 10., 0.2)m = len(x) # 训练数据点数目print mx0 = np.full(m, 1.0)input_data = np.vstack([x0, x]).T # 将偏置b作为权向量的第一个分量target_data = 2 * x + 5 + np.random.randn(m) # 两种终止条件loop_max = 10000 # 最大迭代次数(防止死循环)epsilon = 1e-3 # 初始化权值np.random.seed(0)theta = np.random.randn(2) alpha = 0.001 # 步长(注意取值过大会导致振荡即不收敛,过小收敛速度变慢)diff = 0.error = np.zeros(2)count = 0 # 循环次数finish = 0 # 终止标志 while count < loop_max: count += 1  # 标准梯度下降是在权值更新前对所有样例汇总误差,而随机梯度下降的权值是通过考查某个训练样例来更新的 # 在标准梯度下降中,权值更新的每一步对多个样例求和,需要更多的计算 sum_m = np.zeros(2) for i in range(m):  dif = (np.dot(theta, input_data[i]) - target_data[i]) * input_data[i]  sum_m = sum_m + dif # 当alpha取值过大时,sum_m会在迭代过程中会溢出  theta = theta - alpha * sum_m # 注意步长alpha的取值,过大会导致振荡 # theta = theta - 0.005 * sum_m  # alpha取0.005时产生振荡,需要将alpha调小  # 判断是否已收敛 if np.linalg.norm(theta - error) < epsilon:  finish = 1  break else:  error = theta print 'loop count = %d' % count, '\tw:',thetaprint 'loop count = %d' % count, '\tw:',theta # check with scipy linear regressionslope, intercept, r_value, p_value, slope_std_error = stats.linregress(x, target_data)print 'intercept = %s slope = %s' % (intercept, slope) plt.plot(x, target_data, 'g*')plt.plot(x, theta[1] * x + theta[0], 'r')plt.show()

运行结果截图:

随机梯度下降算法

#!/usr/bin/python#coding=utf-8import numpy as npfrom scipy import statsimport matplotlib.pyplot as plt # 构造训练数据x = np.arange(0., 10., 0.2)m = len(x) # 训练数据点数目x0 = np.full(m, 1.0)input_data = np.vstack([x0, x]).T # 将偏置b作为权向量的第一个分量target_data = 2 * x + 5 + np.random.randn(m) # 两种终止条件loop_max = 10000 # 最大迭代次数(防止死循环)epsilon = 1e-3 # 初始化权值np.random.seed(0)theta = np.random.randn(2)# w = np.zeros(2) alpha = 0.001 # 步长(注意取值过大会导致振荡,过小收敛速度变慢)diff = 0.error = np.zeros(2)count = 0 # 循环次数finish = 0 # 终止标志######-随机梯度下降算法while count < loop_max: count += 1  # 遍历训练数据集,不断更新权值 for i in range(m):  diff = np.dot(theta, input_data[i]) - target_data[i] # 训练集代入,计算误差值   # 采用随机梯度下降算法,更新一次权值只使用一组训练数据  theta = theta - alpha * diff * input_data[i]   # ------------------------------终止条件判断-----------------------------------------  # 若没终止,则继续读取样本进行处理,如果所有样本都读取完毕了,则循环重新从头开始读取样本进行处理。  # ----------------------------------终止条件判断----------------------------------------- # 注意:有多种迭代终止条件,和判断语句的位置。终止判断可以放在权值向量更新一次后,也可以放在更新m次后。 if np.linalg.norm(theta - error) < epsilon:  # 终止条件:前后两次计算出的权向量的绝对误差充分小  finish = 1  break else:  error = thetaprint 'loop count = %d' % count, '\tw:',theta  # check with scipy linear regressionslope, intercept, r_value, p_value, slope_std_error = stats.linregress(x, target_data)print 'intercept = %s slope = %s' % (intercept, slope) plt.plot(x, target_data, 'g*')plt.plot(x, theta[1] * x + theta[0], 'r')plt.show()

运行结果截图:

Mini-batch梯度下降

#!/usr/bin/python#coding=utf-8import numpy as npfrom scipy importstatsimport matplotlib.pyplot as plt # 构造训练数据x = np.arange(0.,10.,0.2)m = len(x) # 训练数据点数目print mx0 = np.full(m, 1.0)input_data = np.vstack([x0, x]).T # 将偏置b作为权向量的第一个分量target_data = 2 *x + 5 +np.random.randn(m) # 两种终止条件loop_max = 10000 #最大迭代次数(防止死循环)epsilon = 1e-3 # 初始化权值np.random.seed(0)theta = np.random.randn(2) alpha = 0.001 #步长(注意取值过大会导致振荡即不收敛,过小收敛速度变慢)diff = 0.error = np.zeros(2)count = 0 #循环次数finish = 0 #终止标志minibatch_size = 5 #每次更新的样本数while count < loop_max: count += 1  # minibatch梯度下降是在权值更新前对所有样例汇总误差,而随机梯度下降的权值是通过考查某个训练样例来更新的 # 在minibatch梯度下降中,权值更新的每一步对多个样例求和,需要更多的计算  for i inrange(1,m,minibatch_size):  sum_m = np.zeros(2)  for k inrange(i-1,i+minibatch_size-1,1):   dif = (np.dot(theta, input_data[k]) - target_data[k]) *input_data[k]   sum_m = sum_m + dif #当alpha取值过大时,sum_m会在迭代过程中会溢出   theta = theta- alpha * (1.0/minibatch_size) * sum_m #注意步长alpha的取值,过大会导致振荡  # 判断是否已收敛 if np.linalg.norm(theta- error) < epsilon:  finish = 1  break else:  error = theta print 'loopcount = %d'% count, '\tw:',thetaprint 'loop count = %d'% count, '\tw:',theta # check with scipy linear regressionslope, intercept, r_value, p_value,slope_std_error = stats.linregress(x, target_data)print 'intercept = %s slope = %s'% (intercept, slope) plt.plot(x, target_data, 'g*')plt.plot(x, theta[1]* x +theta[0],'r')plt.show()

运行结果:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    基于随机梯度下降的矩阵分解推荐算法(python)
    下一条:
    wtfPython―Python中一组有趣微妙的代码【收藏】
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客