1. 程式人生 > 實用技巧 >Dive into DL 閱讀筆記 1

Dive into DL 閱讀筆記 1

Dive into DL 閱讀筆記 1

目錄

線性迴歸

https://zh.d2l.ai/chapter_deep-learning-basics/linear-regression.html#

  • Linear Regression解決迴歸問題,Softmax Regression解決分類問題

  • 線性迴歸模型:\(\hat{y} = x_1 w_1 + x_2 w_2 + b\)

  • 線性迴歸損失函式(單樣本誤差):\(\ell^{(i)}(w_1, w_2, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2\)

    • 常數1/2使對平方項求導後的常數係數為1,這樣在形式上稍微簡單一些
  • 在求數值解的優化演算法中,小批量隨機梯度下降(mini-batch stochastic gradient descent)在深度學習中被廣泛使用

  • 引數迭代公式:

    • 這裡大Beta代表batch size
  • pytorch中的廣播機制:當對兩個形狀不同的Tensor按元素運算時,可能會觸發廣播(broadcasting)機制:先適當複製元素使這兩個Tensor形狀相同後再按元素運算

    • 例如:
    x = torch.arange(1, 3).view(1, 2)
    print(x)
    y = torch.arange(1, 4).view(3, 1)
    print(y)
    print(x + y)
    
    • 輸出:
    tensor([[1, 2]])
    tensor([[1],
            [2],
            [3]])
    tensor([[2, 3],
            [3, 4],
            [4, 5]])
    
  • 注意在使用批梯度下降更新引數時,要把梯度除以batch_size:param.data -= lr * param.grad / batch_size

  • 使用pytorch提供的data包來讀取資料:

import torch.utils.data as Data  # 由於data常用作變數名,因此這裡將匯入的data模組用Data代替

batch_size = 10
# 將訓練資料的特徵和標籤組合
dataset = Data.TensorDataset(features, labels)
# 隨機讀取小批量
data_iter = Data.DataLoader(dataset, batch_size, shuffle=True)
  • 利用pytorch簡潔地定義模型:
    • 完整定義:
    class LinearNet(nn.Module):
        def __init__(self, n_feature):
            super(LinearNet, self).__init__()
            self.linear = nn.Linear(n_feature, 1)
    # forward 定義前向傳播
    def forward(self, x):
        y = self.linear(x)
        return y
    
    net = LinearNet(num_inputs)
    print(net) # 使用print可以打印出網路的結構
    
    • 利用nn.Sequential快速定義:
    # 寫法一
    net = nn.Sequential(
        nn.Linear(num_inputs, 1)
        # 此處還可以傳入其他層
        )
    
    # 寫法二
    net = nn.Sequential()
    net.add_module('linear', nn.Linear(num_inputs, 1))
    # net.add_module ......
    
    # 寫法三
    from collections import OrderedDict
    net = nn.Sequential(OrderedDict([
              ('linear', nn.Linear(num_inputs, 1))
              # ......
            ]))
    
    
  • torch.utils.data模組提供了有關資料處理的工具,torch.nn模組定義了大量神經網路的層,torch.nn.init模組定義了各種初始化方法,torch.optim模組提供了很多常用的優化演算法

softmax迴歸

  • softmax迴歸同線性迴歸一樣,也是一個單層神經網路。由於每個輸出o1,o2,o3o1​,o2​,o3​的計算都要依賴於所有的輸入x1,x2,x3,x4x1​,x2​,x3​,x4​,softmax迴歸的輸出層也是一個全連線層:
  • 最後通過softmax運算子(softmax operator)來把節點的值轉換成值大等於0且和為1的概率分佈:\(\hat{y}_1, \hat{y}_2, \hat{y}_3 = \text{softmax}(o_1, o_2, o_3)\)
  • 其中:\(\hat{y}_1 = \frac{ \exp(o_1)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}_2 = \frac{ \exp(o_2)}{\sum_{i=1}^3 \exp(o_i)},\quad \hat{y}_3 = \frac{ \exp(o_3)}{\sum_{i=1}^3 \exp(o_i)}\)
  • 由於softmax的輸出只需要比較大小即可獲得類別預測結果,因此平方損失函式對它來說太嚴格了。在分類問題下,通常使用交叉熵作為損失函式。如果每個樣本只有一個標籤,那麼交叉熵損失可以簡寫成:\(\ell(\boldsymbol{\Theta}) = -(1/n) \sum_{i=1}^n \log \hat y_{y^{(i)}}^{(i)}\)
  • 從另一個角度來看,我們知道最小化\(\ell(\boldsymbol{\Theta})\)等價於最大化\(\exp(-n\ell(\boldsymbol{\Theta}))=\prod_{i=1}^n \hat y_{y^{(i)}}^{(i)}\),即最小化交叉熵損失函式等價於最大化訓練資料集所有標籤類別的聯合預測概率
  • torchvision包服務於pytorch框架,主要用來構建計算機視覺模型。torchvision主要由以下幾部分構成:
    • torchvision.datasets: 一些載入資料的函式及常用的資料集介面;
    • torchvision.models: 包含常用的模型結構(含預訓練模型),例如AlexNet、VGG、ResNet等;
    • torchvision.transforms: 常用的圖片變換,例如裁剪、旋轉等;
    • torchvision.utils: 其他的一些有用的方法。
  • Softmax數值不穩定問題:
    • 計算機通過有限數量的位模式來表示無限多的實數,總會引入一些近似誤差。如果涉及時沒有考慮最小化舍入誤差的累積,在實踐時可能會導致演算法實效:
      • 當接近零的數被四捨五入為零時發生下溢
      • 大量級的數被近似為無窮時發生上溢

深度學習訓練技巧

應對過擬合問題的常用方法:權重衰減(weight decay)

  • 權重衰減等價於 \(L_2\) 範數正則化(regularization)
  • L2範數正則化在模型原損失函式基礎上新增L2範數懲罰項,從而得到訓練所需要最小化的函式。L2範數懲罰項指的是模型權重引數每個元素的平方和與一個正的常數的乘積
  • 有了L2範數懲罰項後,在小批量隨機梯度下降中,我們將線性迴歸一節中權重w1和w2的迭代方式更改為:
\begin{aligned}
w_1 &\leftarrow \left(1- \eta\lambda \right)w_1 -   \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_1^{(i)} \left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right),\\
w_2 &\leftarrow \left(1- \eta\lambda \right)w_2 -   \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_2^{(i)} \left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right).
\end{aligned}
  • 可見,L2範數正則化令權重w1和w2先自乘小於1的數,再減去不含懲罰項的梯度。因此,L2範數正則化又叫權重衰減

  • 權重衰減在pytorch中的使用方式:


# 直接在構造優化器例項時通過weight_decay引數來指定權重衰減超引數

def fit_and_plot_pytorch(wd):
    # 對權重引數衰減。權重名稱一般是以weight結尾
    net = nn.Linear(num_inputs, 1)
    nn.init.normal_(net.weight, mean=0, std=1)
    nn.init.normal_(net.bias, mean=0, std=1)
    optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr, weight_decay=wd) # 對權重引數衰減
    optimizer_b = torch.optim.SGD(params=[net.bias], lr=lr)  # 不對偏差引數衰減

    train_ls, test_ls = [], []
    for _ in range(num_epochs):
        for X, y in train_iter:
            l = loss(net(X), y).mean()
            optimizer_w.zero_grad()
            optimizer_b.zero_grad()

            l.backward()

            # 對兩個optimizer例項分別呼叫step函式,從而分別更新權重和偏差
            optimizer_w.step()
            optimizer_b.step()
        train_ls.append(loss(net(train_features), train_labels).mean().item())
        test_ls.append(loss(net(test_features), test_labels).mean().item())
    d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
                 range(1, num_epochs + 1), test_ls, ['train', 'test'])
    print('L2 norm of w:', net.weight.data.norm().item())