深度學習:正則化-權重衰減-(1). 原理及實現

摘要:介紹權重衰減的基本原理,及其和L2L_2正則化的不同,並分別給出L2L_2正則化和權重衰減的Tensorflow實現方式。使用兩者能夠等效的隨機梯度下降作爲例子說明兩者的不同。在使用一些自適應優化算法時最好使用解耦的權重衰減而不是L2L_2正則化。

目錄

  1. 基本原理

  2. L2L_2正則化實現

  3. 解耦權重衰減實現

  4. 小結

主要參考文獻

【1】“Comparing biases for minimal network construction with back-propagation

【2】“Decoupled Weight Decay Regularization

【3】“Dive into Deep Learning

1. 基本原理

由參考文獻【1】,權重衰減的表示形式爲:
θt+1=(1λ)θtαft(θt), \theta_{t+1}=(1-\lambda)\theta_{t}-\alpha\nabla f_t(\theta_t),
其中λ\lambda爲權重衰減的比率,α\alpha爲學習率。

一般深度學習框架及很多書本中將權重衰減等效爲L2L_2正則化。這在隨機梯度下降中是成立的,只要在代價函數中增加一項:λ2αθ22\frac{\lambda}{2\alpha}||\theta||_2^2,兩者在數學上就是等價的。

但在其他自適應學習率的方法中,其實不能簡單地將L2L_2正則化當成權重衰減來使用,這就導致在實際使用中自適應優化算法通常會比隨機梯度下降的泛化精度差很多。

參考文獻【2】提出一種解耦的權重衰減方式,能在自適應方法中實現權重衰減。本質就是迴歸權重衰減的最初形式,在權重更新的步驟中進行衰減,而不是在代價函數中加上L2L_2正則化。

下圖爲文獻【2】給出的權重衰減以及L2L_2正則化下的隨機梯度下降算法,下文給出具體實現。
在這裏插入圖片描述

2. L2L_2正則化實現

使用Tensorflow框架,底層設計隨機梯度下降算法,並計算代價函數和L2L_2範數。

下面按照準備數據——選擇模型——計算代價函數、梯度,進行訓練的順序進行實現。

首先準備高維迴歸數據集,特徵數量遠高於訓練樣本數,十分容易過擬合。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

num_train, num_test = 20, 100
num_features = 200

true_w, true_b = tf.ones((num_features, 1)) * 0.01, 0.05

features = tf.random.normal((num_train + num_test, num_features))
noises = tf.random.normal((num_train + num_test, 1)) * 0.01
labels = tf.matmul(features, true_w) + tf.convert_to_tensor(true_b) + noises

train_data, test_data = features[:num_train, :], features[num_train:, :]
train_labels, test_labels = labels[:num_train], labels[num_train:]

其次選擇模型類型,這裏使用線性模型。

class Model(object):
    def __init__(self):
        self.W = tf.Variable(np.random.random((200, 1)), dtype=tf.float32)
        self.b = tf.Variable(0.0)
        
    def __call__(self, x):
        return tf.matmul(x, self.W) + self.b

然後定義代價函數和梯度,對模型進行訓練。代價函數採用均方誤差。

這部分是L2L_2正則化和權重衰減的主要區別所在。

首先我們使用比率爲0的L2L_2正則化,觀察一下過擬合。

def loss(y_true, y_pred):
    return tf.reduce_mean(tf.square(y_true - y_pred))

def l2_reg(ws):
    return tf.norm(ws) ** 2

def train(model, inputs, outputs, lr):
    
    with tf.GradientTape() as g:
        current_loss = loss(outputs, model(inputs)) + 0 * l2_reg(model.W)
        grad_w, grad_b = g.gradient(current_loss, [model.W, model.b])
        model.W.assign_sub(lr * grad_w)
        model.b.assign_sub(lr * grad_b)
        
model = Model()
ws, bs = [], []
train_losses, test_losses = [], []
epochs = range(120)
for epoch in epochs:
    ws.append(model.W.numpy())
    bs.append(model.b.numpy())
    train(model, train_data, train_labels, 0.01)
    
    train_losses.append(loss(train_labels, model(train_data)))
    test_losses.append(loss(test_labels, model(test_data)))

觀察過擬合時的訓練損失和驗證損失之間的變化。可以看出,訓練損失較小但驗證損失一直很大,明顯的過擬合現象。
在這裏插入圖片描述
下面將L2L_2正則化的比率調爲1,觀察訓練損失和驗證損失。此時隨着訓練的進行,驗證損失慢慢也和訓練損失一樣小。L2L_2正則化確實能有效緩解過擬合。

current_loss = loss(outputs, model(inputs)) + 1 * l2_reg(model.W) 

在這裏插入圖片描述

3. 解耦權重衰減實現

權重衰減的比率和L2L_2正則化比率之間的關係如下,因此比率爲1的的L2L_2正則化對應0.02的權重衰減。
λL2=λwd2α \lambda_{L_2}=\frac{\lambda_{wd}}{2\alpha}
程序大體相同,改動如下,即將代價函數中的L2L_2範數刪除,然後在權重更新時減去權重衰減項。

current_loss = loss(outputs, model(inputs))
# ...
model.W.assign_sub(lr * grad_w + 0.02 * model.W)

此時的訓練和驗證損失如下圖,和L2L_2正則化起的效果基本相同。
在這裏插入圖片描述

4. 小結

  • 權重衰減,以及L2L_2正則化均能有效緩解過擬合。

  • 隨機梯度下降中L2L_2正則化和權重衰減等價。

  • 其他自適應算法中兩者不等價,要實現權重衰減只能用原始定義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章