聊聊神經網絡的優化算法

優化算法主要用於調整神經網絡中的超參數,使得訓練數據集上的損失函數儘可能小。其核心邏輯是通過計算損失函數對參數的梯度(導數)來確定參數更新方向。

SGD

Stochastic Gradient Descent(隨機梯度下降法):隨機梯度下降算法是一種改進的梯度下降方法,它在每次更新參數時,只隨機選擇一個樣本來計算梯度。這樣可以大大減少計算量,提高訓練速度。隨機梯度下降算法在訓練大規模數據集時非常有效。

其Python實現是

class SGD:
    """隨機梯度下降法(Stochastic Gradient Descent)"""
    def __init__(self, lr=0.01):
        self.lr = lr
    # 更新超參數
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]

參數lr表示學習率,參數params和grads是字典變量,保存了權重參數(prams['W1'])與梯度(grads['W1']),update方法執行的是超參數的梯度更新。
使用這個SGD類,可以按如下僞代碼進行神經網絡的參數更新:

network = nn.layernet()
optimizer = SGD()

for i in range(10000):
    x_batch, t_batch = get_batch(..)
    # 獲取參數的梯度信息
    grads = network.gradient(x_batch, t_batch)
    # 獲取參數
    params = network.params
    optimizer.update(params,grads)

Momentum

Momentum是"動量"的意思,是物理學的概念。其數學表達式如下:


這裏新出現的參數,對應物理上的速度。類似小球在斜面上的滾動。
image.png
可以使物體逐漸減速,對應物理上的地面磨擦與空氣阻力。其Python實現如下

class Momentum:

    """Momentum SGD"""

    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[key] 
            params[key] += self.v[key]

AdaGrad

在神經網絡中,學習率的值很重要。學習率過小會導致學習花費過多的時間;反之,學習率過大會導致學習發散,不能正確進行。
AdaGrad會爲參數的每個元素適當的(Adaptive)調整學習率,與此同時進行學習。其數學表達式如下:


參數 保存了以前的所有參數的梯度值的平方和(表示對應矩陣元素的乘法)。更新參數時,通過乘以,調整學習的尺度。即按參數的元素進行學習率衰減,使得變動大的參數的學習率逐漸減小。
其python實現如下:

class AdaGrad:

    """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]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

Adam

Momentum參照小球在碗中滾動的物理規則進行移動,AdaGrad爲參數的每個元素適當的調整更新步伐。將兩者融合就是Adam方法的基本思路。
Adam算法的公式如下,流程比較複雜,簡單的理解就是其基本思路。

  1. 初始化:設 ( t = 0 ),初始化模型參數,學習率,以及超參數 。爲每個參數 初始化一階矩估計 和二階矩估計
  2. 在第 ( t ) 步,計算目標函數 對參數 的梯度
  3. 更新一階矩估計:
  4. 更新二階矩估計:
  5. 校正一階矩估計和二階矩估計中的偏差:
  6. 計算自適應學習率:
  7. 使用自適應學習率更新模型參數:
  8. ( t = t + 1 ),重複步驟 2-7 直到收斂。
    通過上述公式,Adam算法能夠自適應地調整每個參數的學習率,從而在訓練過程中加速收斂。

其Python實現:

class Adam:

    """Adam (http://arxiv.org/abs/1412.6980v8)"""

    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None
        
    def 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 += 1
        lr_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] += (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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章