1 參數的更新
四種方法:見圖
01 隨機梯度下降法:SGD
使用參數的梯度,沿着梯度方向更新參數,並且重複這個步驟多次,從而逐漸靠近最優參數,這個過程稱爲隨機梯度下降法
# 源代碼
class SGD:
def _init_(self,lr=0.01):
self.lr=lr
def update(self,params,grads): # params,和grads是字典型變量
# 代碼段的update(params,grads),會被反覆調用按照params['W1']、grads['W1'],
#分別保存了權重參數和他們的梯度。
for k inparams.keys():
params(key)-=self.lr*grads[key]
見圖:SGD呈之字形移動, 這是一個相當低效的路徑。
SGD的缺陷就是,如果函數的形狀非均向,比如延伸狀,搜索的路徑就會非常抵消。
低效率的最根本原因是,梯度的方向沒有指向最小的方向。
02 Momentum 方法
Mnmentum是“動量”的意思,和物理有關。
源代碼程序實現
class Momentum:
def _init_(self,lr=0.01,momentum=0.9):
self.lr=lr
self.momentum=momentum
self.v=None
def 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[keys]
params[key]+=self.v[key]
實例變量v會保存物體的速度,初始化時候,v中什麼都不保存,但是當第一次調用update()的時候
v會以字典型變量的形式保存與參數結構相同的數據
和SGD相比,可以更快地朝x軸方向靠近,減弱“之”字形的變動程度。
03 AdaGrad方法
在神經網絡的學習中,學習率(數學式中記爲y)的值很重要,學習率過小,會導致學習花費過多時間,反過來
學習率過大,則回到自學習發散而不能正確進行
學習率衰減(learning rate decay)
隨着學習的進行,使學習率逐漸減小。
AdaGrad:會爲每個元素適當地調整學習率,與此同時進行學習
源代碼:
class AdaGrad:
def _init_(self,lr=0.01):
self.lr=lr
self.h=None
def 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]
paras[key]-=self.lr*grads[key]/(np.sqrt(self.h[key])+le-7)
注意:最後一行加上了微小值le-7.這是爲了防止當self.h[key]中有0的時候,
將0用做除數的情況。在很多深度學習的框架中,這個微小值也可以設定爲參數。這裏選擇固定值
04 Adam
Momentum 參照小球在碗中滾動的物理規則進行移動,AdaGrad爲參數的每個元素適當地調整更新不發。
Adam結合了前面兩種方法的優點,有望實現參數空間的高效搜索。
Adam會設置3個參數,一個是學習率(a),另外兩個是一次momentum係數B1爲0.9,B2爲0.999
現在多數的研究人員都喜歡Adam
2、權重初始值
01 權重初始值不能是0
02 隱藏層激活值得選擇
# coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def ReLU(x):
return np.maximum(0, x)
def tanh(x):
return np.tanh(x)
input_data = np.random.randn(1000, 100) # 高斯分佈隨機生成1000個數據
node_num = 100 # 各隱藏層的節點(神經元)數
hidden_layer_size = 5 # 隱藏層有5層
activations = {} # 激活值的結果保存在這裏
x = input_data
for i in range(hidden_layer_size):
if i != 0:
x = activations[i-1]
# 改變初始值進行實驗!
# w = np.random.randn(node_num, node_num) * 1
# w = np.random.randn(node_num, node_num) * 0.01
# w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)
a = np.dot(x, w)
# 將激活函數的種類也改變,來進行實驗!
z = sigmoid(a)
# z = ReLU(a)
# z = tanh(a)
activations[i] = z
# 繪製直方圖
for i, a in activations.items():
plt.subplot(1, len(activations), i+1)
plt.title(str(i+1) + "-layer")
if i != 0: plt.yticks([], [])
# plt.xlim(0.1, 1)
# plt.ylim(0, 7000)
plt.hist(a.flatten(), 30, range=(0,1))
plt.show()
03 relu的權重初始值
總結:
當激活函數使用relu時候,權重初始值使用He初始值,當激活函數爲sigmoid或者tanh等S型曲線函數時候,初始值使用Xavier初始值。