学习率优化(一)

上节介绍了反向传播时权值更新方法,更新隐含层:\omega _{ho}^{N+1}=\omega _{ho}^{N}-\eta\frac{\partial e}{\partial \omega _{ho}^{N+1}};更新输出层:\omega _{ih}^{N+1}=\omega _{ih}^{N}-\eta\frac{\partial e}{\partial \omega _{ih}^{N+1}}。看似已经完美的解决了问题,但是\eta怎么取值呢?

我们把问题转化到求二次函数极值问题,例如f(x)=x^{2},如果用梯度下降法求函数极值,每一次x的取值为x^{n+1}=x^{n}-\eta \frac{\partial f(x)}{\partial x},一步步趋近极小值。

如果采用固定学习率:f(x)=x^{2},初始值取x=1.5,学习率使用0.01:

 

分析:经过200次迭代,x=0.0258543;经过1000次迭代,x=2.52445\times 10^{-9}

效果还可以,但这个学习率只使用于f(x)=x^{2},如果改变函数还可以这个效果吗?还采用学习率0.01,f(x)=x^{4},初始值取:x=1.5

 

分析:经过200次迭代,x=0.24436;经过1000次迭代,x=0.111275;效果不好,学习率不再适用。附上固定学习率的python代码:

import matplotlib.pyplot as plt

def g(x): 
	return 4.0*x**3
def f(x):
	return x**4

if __name__ == '__main__':
	x =1.5
	a = 0.01
	# 固定学习率
	for i in range(1000):
		d = g(x)
		x -= d * a
		if i == 200:
			print(x)
		plt.scatter(i,x)
	print(x)
	plt.show()
	

回溯线性搜索

基于Armijo准则计算搜素方向上的最大步长,其基本思想是沿着搜索方向移动一个较大的步长估计值,然后以迭代形式不断缩减步长,直到该步长使得函数值f(x_{k}+\alpha d_{k})相对与当前函数值f(x_{k})的减小程度大于预设的期望值(即满足Armijo准则)为止。

f(x_{k}+\alpha d_{k})< f(x_{k})+c_{1}\alpha \triangledown f(x_{k})^{T}d_{k}

意思就是说,f(x_{k})按学习率缩小一次后得到新值f(x_{k+1})=f(x_{k}+\alpha d_{k}),如果f(x_{k+1})设定为我们的期望值,如果经过学习\eta后可以达到f(x_{k+1}),那么这个学习率就是符合要求的学习率;f(x_{k+1})<=f(x_{k})+c_{1}\alpha \triangledown f(x_{k})^{T}d_{k}

分析:经过12次迭代后,x=0.0001035,经过1000次迭代后x=3.4222\times 10^{-6},效果不错。

import matplotlib.pyplot as plt

def g(x): 
	return 4.0*x**3
def f(x):
	return x**4

def armijo(x,d,a):
	c1 = 0.3
	now = f(x)
	next = f(x - a*d)

	count =30
	while next < now:
		a *= 2
		next = f(x - a*d)
		count-=1
		if count == 0:
			break
	count = 50
	while next > now-c1*a*d*d:
		a /=2
		next = f(x - a*d)
		count -=1
		if count == 0:
			break
	return a

if __name__ == '__main__':
	x =1.5
	a = 0.01

	#回溯线性搜索
	for i in range(1000):
		d = g(x)
		a1 = armijo(x,d,a)
		x -= d * a1
		if i == 12:
			print(x,a1)
		plt.scatter(i,x)
	print(x,a1)
	plt.show()


二次插值法

如上述代码,第一个循环,如果沿负梯度方向下降微小的值,f(x_{k+1})<f(x_{k}))会恒成立,但我们每一次都增大学习率,当某一次步子迈的太大,就会不满足,Armijo准则则是再减小学习率,那么二次插值法则是构造一个二次近似函数:h_{q}(\alpha )=\frac{h(\alpha _{0})-h^{'}(0)\alpha _{0}-h(0) }{\alpha _{0}^{2}}\alpha ^{2}+h^{'}(0)\alpha _{0}+h(0);那么导数为0的最优值为:\alpha_{1} =\frac{h^{'}(0)\alpha _{0}^{2} }{2[h^{'}(0)\alpha_{0}+h(0)-h(\alpha _{0})]},若\alpha _{1}满足Armijo准则,则输出该学习率,否则继续迭代。

分析,经过12次迭代x=0.0003169,,经过1000次迭代,x=3.426001\times 10^{-6},效果和回溯法差不多,么有提升。

import matplotlib.pyplot as plt

def g(x): 
	return 4.0*x**3
def f(x):
	return x**4

def getA_quad(x,d,a):
	c1 = 0.3
	now = f(x)
	next = f(x - a*d)

	count =30
	while next < now:
		a *= 2
		next = f(x - a*d)
		count-=1
		if count == 0:
			break
	count = 50
	while next > now-c1*a*d*d:
		b=d*a*a/(now+d*a-next)
		b /=2
		if b<0:
			a /=2
		else:
			a = b
		next = f(x - a*d)
		count -=1
		if count == 0:
			break
	return a
if __name__ == '__main__':
	x =1.5
	a = 0.01
	
	#插值法
	for i in range(1000):
		d = g(x)
		a1 = getA_quad(x, d, a)
		x -= d * a1
		if i == 12:
			print(x)
		plt.scatter(i, x)
	print(x)
	plt.show()

总结

[一阶方法] 随机梯度

SGD(Stochastic Gradient Descent)是相对于BGD(Batch Gradient Descent)而生的。BGD要求每次正反向传播,计算所有Examples的Error,这在大数据情况下是不现实的。最初的使用的SGD,每次正反向传播,只计算一个Example,串行太明显,硬件利用率不高。后续SGD衍生出Mini-Batch Gradient Descent,每次大概推进100个Example,介于BGD和SGD之间。现在,SGD通常是指Mini-Batch方法,而不是早期单Example的方法。

一次梯度更新,可视为:x_{t+1}=x_{t}+\triangle x_{t} \, \, where \, \, \triangle x_{t}=-\eta g_{t}

x为参数,t为时序,\triangle为更新量,\eta为学习率,g为梯度。

以上介绍的回溯法和插值法都属于基于一阶随机梯度的方法,还有基于二阶随机梯度的方法;后续章节再介绍几种常规优化方法。

[二阶方法] 牛顿法

二阶牛顿法替换梯度更新量:\triangle x_{t}=H_{t}^{-1} \cdot g_{t}

H为参数的二阶导矩阵,称为Hessian矩阵。

牛顿法,用Hessian矩阵替代人工设置的学习率,在梯度下降的时候,可以完美的找出下降方向,不会陷入局部最小值当中,是理想的方法。但是,求逆矩阵的时间复杂度近似O(n^{3}),计算代价太高,不适合大数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值