神经网络的SGD、Momentum、AdaGrad、Adam最优化方法及其python实现
神經(jīng)網(wǎng)絡(luò)的SGD、Momentum、AdaGrad、Adam最優(yōu)化方法及其python實(shí)現(xiàn)
- 一、SGD
- 二、Momentum-動(dòng)量
- 三、AdaGrad
- 四、Adam
一、SGD
右邊的值更新左邊的值,每次更新朝著梯度方向前進(jìn)一小步。
class SGD:"""隨機(jī)梯度下降法(Stochastic Gradient Descent)"""def __init__(self, lr=0.01):self.lr = lrdef update(self, params, grads):for key in params.keys():params[key] -= self.lr * grads[key]二、Momentum-動(dòng)量
SGD實(shí)現(xiàn)簡單,有些問題可能沒有效果,比如f(x,y)=(1/20)x^ 2 +y ^2
SGD低效的根本原因:梯度的方向沒有指向最小值的方向。如果函數(shù)形狀非均向,如呈現(xiàn)延伸狀,搜索路徑就非常低效,有可能呈現(xiàn)z字形移動(dòng)。
Momentum-動(dòng)量方法公式:
v表示物體在梯度方向受的力,αv作用是讓物體逐漸減速(α小于1,常數(shù),如0.9之類的數(shù))。
動(dòng)量法的好處,x軸方向受力小,但是每一次梯度變化的方向不變,速度方向不變,一直在這個(gè)方向受力,往那個(gè)方向走的速度會(huì)加速。但是y軸受到正反方向的力,他們會(huì)抵消,讓y不穩(wěn)定,因此和SGD相比,能更快的向x軸方向靠近。
簡的來說,SGD的話就是他y方向梯度大,步子跨的猛的話就z形了,動(dòng)量的目的是梯度大的那塊,邁步子時(shí)候讓它考慮到上一次的步子是往哪走的。如果相反方向走的話,其實(shí)是抵消了一部分v,這樣的話如果步子跨得猛,他也得少一點(diǎn)步子。如下圖所示,對(duì)于f(x,y)=(1/20)x^ 2 +y ^2用SGD的話,m想走到y(tǒng),它在y軸搖擺的厲害,但是,用動(dòng)量,y軸搖擺抵消了,而且x軸速度還增加了,多好。
class Momentum:"""Momentum SGD"""def __init__(self, lr=0.01, momentum=0.9):self.lr = lrself.momentum = momentumself.v = Nonedef update(self, params, grads):if self.v is None:self.v = {}for key, val in params.items(): self.v[key] = np.zeros_like(val)for key in params.keys():self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] params[key] += self.v[key]三、AdaGrad
h保存了梯度的平方和,圓圈就表示矩陣相乘。
由于乘上根號(hào)h分之1,參數(shù)的元素中,變動(dòng)較大的元素的學(xué)習(xí)率將變小。
這是一種學(xué)習(xí)率衰減的手法,梯度下降太快了,山谷太陡峭了,那我就讓你走的步子減小,這樣一來,你不容易直接一步跨倆山峰(山峰是啥懂得都懂,嘿嘿)。
class AdaGrad:"""AdaGrad"""def __init__(self, lr=0.01):self.lr = lrself.h = Nonedef update(self, params, grads):if self.h is None:self.h = {}for key, val in params.items():self.h[key] = np.zeros_like(val)for key in params.keys():self.h[key] += grads[key] * grads[key]params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)四、Adam
結(jié)合了Momentum和AdaGrad方法。
看代碼去吧
很多人喜歡用Adam哦
class Adam:"""Adam (http://arxiv.org/abs/1412.6980v8)"""def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):self.lr = lrself.beta1 = beta1self.beta2 = beta2self.iter = 0self.m = Noneself.v = Nonedef update(self, params, grads):if self.m is None:self.m, self.v = {}, {}for key, val in params.items():self.m[key] = np.zeros_like(val)self.v[key] = np.zeros_like(val)self.iter += 1lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter) for key in params.keys():#self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)總結(jié)
以上是生活随笔為你收集整理的神经网络的SGD、Momentum、AdaGrad、Adam最优化方法及其python实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10 和 Ubuntu 20.04
- 下一篇: PostgreSQL 视图、子查询