python实现梯度下降算法


Posted in Python onMarch 24, 2020

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

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

梯度下降

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

python实现梯度下降算法

在线性回归算法中,损失函数为python实现梯度下降算法

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

使用梯度下降算法的步骤

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

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

python实现梯度下降算法

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

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

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

python实现梯度下降算法

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

 批量梯度下降(Batch gradient descent)   

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

python实现梯度下降算法

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

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

随机梯度下降(Stochastic gradient descent) 

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

python实现梯度下降算法

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

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

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

Mini-batch梯度下降算法

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

python实现梯度下降算法

python代码实现

批量梯度下降算法

#!/usr/bin/python
#coding=utf-8
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
 
# 构造训练数据
x = np.arange(0., 10., 0.2)
m = len(x) # 训练数据点数目
print m
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)
 
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:',theta
print 'loop count = %d' % count, '\tw:',theta
 
# check with scipy linear regression
slope, 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实现梯度下降算法

随机梯度下降算法

#!/usr/bin/python
#coding=utf-8
import numpy as np
from scipy import stats
import 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 = theta
print 'loop count = %d' % count, '\tw:',theta
 
 
# check with scipy linear regression
slope, 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实现梯度下降算法

Mini-batch梯度下降

#!/usr/bin/python
#coding=utf-8
import numpy as np
from scipy importstats
import matplotlib.pyplot as plt
 
# 构造训练数据
x = np.arange(0.,10.,0.2)
m = len(x) # 训练数据点数目
print m
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)
 
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:',theta
print 'loop count = %d'% count, '\tw:',theta
 
# check with scipy linear regression
slope, 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实现梯度下降算法

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

Python 相关文章推荐
Python 连连看连接算法
Nov 22 Python
深入解读Python解析XML的几种方式
Feb 16 Python
Python动刷新抢12306火车票的代码(附源码)
Jan 24 Python
Python随机函数random()使用方法小结
Apr 29 Python
python中redis查看剩余过期时间及用正则通配符批量删除key的方法
Jul 30 Python
python flask解析json数据不完整的解决方法
May 26 Python
使用python将excel数据导入数据库过程详解
Aug 27 Python
python列表推导式入门学习解析
Dec 02 Python
Python和Sublime整合过程图示
Dec 25 Python
Python字符串hashlib加密模块使用案例
Mar 10 Python
详解Django中的FBV和CBV对比分析
Mar 01 Python
十个Python自动化常用操作,即拿即用
May 10 Python
wtfPython—Python中一组有趣微妙的代码【收藏】
Aug 31 #Python
opencv python 图像去噪的实现方法
Aug 31 #Python
python+numpy+matplotalib实现梯度下降法
Aug 31 #Python
python实现随机梯度下降法
Mar 24 #Python
python实现决策树分类(2)
Aug 30 #Python
python实现决策树分类
Aug 30 #Python
python实现多人聊天室
Mar 31 #Python
You might like
通过PHP自带的服务器来查看正则匹配结果的方法
2015/12/24 PHP
深入理解PHP原理之执行周期分析
2016/06/01 PHP
thinkphp5框架实现数据库读取的数据转换成json格式示例
2019/10/10 PHP
javascript 动态调整图片尺寸实现代码
2009/12/28 Javascript
使用JQUERY Tabs插件宿主IFRAMES
2010/01/01 Javascript
Javascript 网页水印(非图片水印)实现代码
2010/03/01 Javascript
javascript alert乱码的解决方法
2013/11/05 Javascript
JS小游戏之极速快跑源码详解
2014/09/25 Javascript
把普通对象转换成json格式的对象的简单实例
2016/07/04 Javascript
D3.js实现文本的换行详解
2016/10/14 Javascript
Bootstrap面板学习使用
2017/02/09 Javascript
详解ElementUI之表单验证、数据绑定、路由跳转
2017/06/21 Javascript
详解封装基础的angular4的request请求方法
2018/06/05 Javascript
vue项目刷新当前页面的三种方法
2018/12/04 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
vue路由传参页面刷新参数丢失问题解决方案
2019/10/08 Javascript
vue $set 给数据赋值的实例
2019/11/09 Javascript
Vue 样式切换及三元判断样式关联操作
2020/08/09 Javascript
[01:25]DOTA2超级联赛专访iG 将调整状态找回自己
2013/06/05 DOTA
python实现的一只从百度开始不断搜索的小爬虫
2013/08/13 Python
Python中实现对list做减法操作介绍
2015/01/09 Python
Python3实现并发检验代理池地址的方法
2016/09/18 Python
Python探索之修改Python搜索路径
2017/10/25 Python
python3+PyQt5泛型委托详解
2018/04/24 Python
Python3.6实现连接mysql或mariadb的方法分析
2018/05/18 Python
Python3爬虫爬取英雄联盟高清桌面壁纸功能示例【基于Scrapy框架】
2018/12/05 Python
Python实现的各种常见分布算法示例
2018/12/13 Python
Python实现简单石头剪刀布游戏
2021/01/20 Python
对python中arange()和linspace()的区别说明
2020/05/03 Python
HTML5实现音频和视频嵌入的方法
2018/08/22 HTML / CSS
Book Depository亚太地区:一家领先的国际图书零售商
2019/05/05 全球购物
Ajax和javascript的区别
2013/07/20 面试题
财务总监管理岗位职责
2014/03/08 职场文书
交通事故私了协议书
2014/04/16 职场文书
CentOS7环境下MySQL8常用命令小结
2022/06/10 Servers
postgresql如何找到表中重复数据的行并删除
2023/05/08 MySQL