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文件比较示例分享
Jan 10 Python
django模板加载静态文件的方法步骤
Mar 01 Python
python实现植物大战僵尸游戏实例代码
Jun 10 Python
Flask框架 CSRF 保护实现方法详解
Oct 30 Python
python不使用for计算两组、多个矩形两两间的iou方式
Jan 18 Python
python pandas.DataFrame.loc函数使用详解
Mar 26 Python
解决jupyter运行pyqt代码内核重启的问题
Apr 16 Python
python和JavaScript哪个容易上手
Jun 23 Python
快速解释如何使用pandas的inplace参数的使用
Jul 23 Python
Pycharm自动添加文件头注释和函数注释参数的方法
Oct 23 Python
python基于exchange函数发送邮件过程详解
Nov 06 Python
pygame面向对象的飞行小鸟实现(Flappy bird)
Apr 01 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
晶体管单管来复再生式收音机
2021/03/02 无线电
无数据库的详细域名查询程序PHP版(4)
2006/10/09 PHP
PHP file_get_contents 函数超时的几种解决方法
2009/07/30 PHP
Session服务器配置指南与使用经验的深入解析
2013/06/17 PHP
ThinkPHP实现一键清除缓存方法
2014/06/26 PHP
必须收藏的php实用代码片段
2016/02/02 PHP
PHP 常用时间函数资料整理
2016/10/22 PHP
HR vs CL BO3 第一场 2.13
2021/03/10 DOTA
EasyUi tabs的高度与宽度根据IE窗口的变化自适应代码
2010/10/26 Javascript
再次分享18个非常棒的jQuery表格插件
2011/04/10 Javascript
js数组中如何随机取出一个值
2014/06/13 Javascript
jquery任意位置浮动固定层插件用法实例
2015/05/29 Javascript
iOS和Android用同一个二维码实现跳转下载链接的方法
2016/09/28 Javascript
AngularJS  双向数据绑定详解简单实例
2016/10/20 Javascript
vue 中swiper的使用教程
2018/05/22 Javascript
javascript实现评分功能
2020/06/24 Javascript
Vue常用API、高级API的相关总结
2021/02/02 Vue.js
[01:15]PWL S2开团时刻第二期——他们杀 我就白给
2020/11/25 DOTA
Python获取Linux系统下的本机IP地址代码分享
2014/11/07 Python
Python3.7 新特性之dataclass装饰器
2019/05/27 Python
python如果快速判断数字奇数偶数
2019/11/13 Python
python几种常用功能实现代码实例
2019/12/25 Python
pytorch实现onehot编码转为普通label标签
2020/01/02 Python
浅谈图像处理中掩膜(mask)的意义
2020/02/19 Python
windows10环境下用anaconda和VScode配置的图文教程
2020/03/30 Python
Python代码覆盖率统计工具coverage.py用法详解
2020/11/25 Python
python 多线程爬取壁纸网站的示例
2021/02/20 Python
德国排名第一的主题公园门票网站:Attraction Tickets Direct
2019/09/09 全球购物
端午节粽子促销活动方案
2014/02/02 职场文书
慈善捐赠倡议书
2014/08/30 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
火烧圆明园的观后感
2015/06/03 职场文书
六年级作文之预言作文
2019/10/25 职场文书
python munch库的使用解析
2021/05/25 Python
Nginx反向代理配置的全过程记录
2021/06/22 Servers
SpringBoot+VUE实现数据表格的实战
2021/08/02 Java/Android