PyTorch 作為主流深度學習框架,提供豐富的功能與彈性的設計,讓開發者能更有效率地建構和訓練模型。本文將深入探討 PyTorch 的核心概念,並以建構神經網路模型的流程為主軸,逐步講解每個環節的實務技巧。

在 PyTorch 中,TensorAutograd 機制是進行深度學習的基本。Tensor 類別似 NumPy 的多維陣列,用於儲存和運算資料,而 Autograd 則負責自動計算梯度,簡化模型訓練的過程。理解這兩個核心概念對於使用 PyTorch 至關重要。

PyTorch 基礎:Tensor 與 Autograd

Tensor 是 PyTorch 中的核心資料結構,用於儲存和處理多維資料。而 Autograd 機制則能自動計算 Tensor 運算的梯度,這對於神經網路的訓練至關重要,因為我們需要梯度來更新模型的引數。

import torch

# 建立一個 Tensor 並設定 requires_grad=True 以追蹤梯度
x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)

# 進行一些運算
y = x * 2
z = y.mean()

# 計算梯度
z.backward()

# 顯示 x 的梯度
print(x.grad)

內容解密

  • 我們建立了一個 2x2 的 Tensor x,並設定 requires_grad=True,這讓 PyTorch 追蹤 x 的所有運算,以便之後計算梯度。
  • 接著,我們進行了兩個運算:y = x * 2z = y.mean()
  • z.backward() 啟動反向傳播,計算 z 對 x 的梯度。
  • 最後,print(x.grad) 顯示 x 的梯度。

圖表翻譯

  graph LR
    A[x] --> B[y = x * 2]
    B --> C[z = y.mean()]
    C --> D[z.backward()]
  • 此圖展示了計算流程:從 x 開始,經過乘法運算得到 y,再計算平均值得到 z,最後進行反向傳播計算梯度。

模型建構與層級設計

在 PyTorch 中,我們使用 nn.Module 來定義模型和層。模型通常由多個層組成,每個層執行特定的運算,例如線性變換、卷積、啟用函式等。

import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super().__init__()
        self.linear1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = self.linear1(x)
        x = self.relu(x)
        x = self.linear2(x)
        return x

內容解密

  • MyModel 繼承自 nn.Module,表示它是一個 PyTorch 模型。
  • __init__ 方法初始化了模型的層:兩個線性層 (nn.Linear) 和一個 ReLU 啟用函式 (nn.ReLU)。
  • forward 方法定義了模型的前向傳播邏輯。

圖表翻譯

  graph LR
    A[輸入 x] --> B(Linear 1)
    B --> C(ReLU)
    C --> D(Linear 2)
    D --> E[輸出]
  • 此圖展示了 MyModel 的前向傳播流程:輸入 x 經過兩個線性層和一個 ReLU 啟用函式,最終得到輸出。

損失函式與最佳化器

損失函式用於衡量模型預測與真實值之間的差異,而最佳化器則負責根據損失函式的梯度更新模型的引數。

import torch.optim as optim

# 建立模型例項
model = MyModel(input_size=10, hidden_size=20, output_size=5)

# 定義損失函式和最佳化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

內容解密

  • criterion = nn.MSELoss() 建立了一個均方誤差損失函式。
  • optimizer = optim.Adam(model.parameters(), lr=0.01) 建立了一個 Adam 最佳化器,學習率設定為 0.01。

圖表翻譯

  graph LR
    A[模型引數] --> B{計算損失}
    B --> C[計算梯度]
    C --> D[更新引數]
  • 此圖展示了模型訓練的流程:計算損失、計算梯度、更新引數。

模型訓練流程

模型訓練的流程通常包含以下步驟:前向傳播、計算損失、反向傳播、更新引數。

# 訓練迴圈
for epoch in range(num_epochs):
    # 前向傳播
    outputs = model(inputs)
    loss = criterion(outputs, targets)

    # 反向傳播和最佳化
    optimizer.zero_grad()  # 清零梯度
    loss.backward()  # 計算梯度
    optimizer.step()  # 更新引數

內容解密

  • 在每個 epoch 中,我們先進行前向傳播,計算模型的輸出和損失。
  • 接著,我們使用 optimizer.zero_grad() 清零梯度,然後使用 loss.backward() 計算梯度,最後使用 optimizer.step() 更新模型的引數。

圖表翻譯

  graph LR
    A[輸入資料] --> B{前向傳播}
    B --> C{計算損失}
    C --> D{反向傳播}
    D --> E{更新引數}
  • 此圖展示了模型訓練的流程:輸入資料、前向傳播、計算損失、反向傳播、更新引數。

結語

本文介紹了 PyTorch 的核心概念和實務技巧,包括 Tensor、Autograd、模型建構、層級設計、損失函式、最佳化器設定以及模型訓練流程。透過這些技巧,讀者可以更有效率地使用 PyTorch 建構和訓練深度學習模型。在實務應用上,PyTorch 的彈性和豐富的功能使其成為深度學習開發的利器。

圖表翻譯

下面是 LSTMNode 的圖表:

  graph LR
    X_in -->|輸入|> Input_Gate
    H_in -->|隱藏狀態|> Input_Gate
    Input_Gate -->|輸入門|> Cell_State
    Cell_State -->|細胞狀態|> Forget_Gate
    Forget_Gate -->|忘記門|> Cell_State
    Cell_State -->|細胞狀態|> Output_Gate
    Output_Gate -->|輸出門|> Hidden_State
    Hidden_State -->|隱藏狀態|> Output

這個圖表展示了 LSTMNode 的前向傳播過程,包括輸入門、忘記門、細胞狀態和輸出門的計算。

長短期記憶單元(LSTM)節點的實作

長短期記憶(LSTM)是一種特殊的迴圈神經網路(RNN),用於處理序列資料。它的設計目的是為了克服傳統RNN的梯度消失問題,從而能夠學習到長距離的依賴關係。

LSTM 節點的結構

一個LSTM節點由多個門控元件組成,包括輸入門、遺忘門、細胞狀態和輸出門。這些門控元件共同控制著細胞狀態的更新和輸出的計算。

LSTM 節點的前向傳播

LSTM節點的前向傳播可以透過以下步驟實作:

  1. 輸入門: 計算輸入門的啟用值,決定哪些新資訊被新增到細胞狀態中。
  2. 遺忘門: 計算遺忘門的啟用值,決定哪些舊資訊被遺忘。
  3. 細胞狀態更新: 更新細胞狀態,根據輸入門和遺忘門的啟用值。
  4. 輸出門: 計算輸出門的啟用值,決定哪些資訊被輸出。

實作LSTM節點的Python程式碼

import numpy as np

class LSTMNode:
    def __init__(self, input_size, hidden_size, output_size):
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        self.Z = np.random.rand(input_size, hidden_size)
        self.W_f = np.random.rand(hidden_size, hidden_size)
        self.B_f = np.random.rand(hidden_size)

    def forward(self, X_in, H_in, C_in, params_dict):
        '''
        前向傳播
        '''
        self.X_in = X_in
        self.C_in = C_in
        self.f_int = np.dot(self.Z, params_dict['W_f']['value']) + params_dict['B_f']['value']
        #... 其他門控元件的計算...
        return self.X_out, self.H, self.C

# 示例用法
lstm_node = LSTMNode(10, 20, 30)
X_in = np.random.rand(1, 10)
H_in = np.random.rand(1, 20)
C_in = np.random.rand(1, 20)
params_dict = {'W_f': {'value': np.random.rand(20, 20)}, 'B_f': {'value': np.random.rand(20)}}
X_out, H, C = lstm_node.forward(X_in, H_in, C_in, params_dict)
print(X_out.shape, H.shape, C.shape)

LSTM 神經網路之隱藏狀態與記憶單元更新

在長短期記憶(LSTM)神經網路中,隱藏狀態和記憶單元的更新是非常重要的步驟。以下是這些步驟的詳細解釋:

1. Forget Gate(遺忘門)

首先,我們需要計算遺忘門的輸出。遺忘門的輸出是根據前一時間步的隱藏狀態和當前輸入之間的點積,以及權重矩陣和偏差項之間的點積。

self.f_int = np.dot(self.Z, params_dict['W_f']['value']) + params_dict['B_f']['value']
self.f = sigmoid(self.f_int)

2. Input Gate(輸入門)

接下來,我們需要計算輸入門的輸出。輸入門的輸出是根據前一時間步的隱藏狀態和當前輸入之間的點積,以及權重矩陣和偏差項之間的點積。

self.i_int = np.dot(self.Z, params_dict['W_i']['value']) + params_dict['B_i']['value']
self.i = sigmoid(self.i_int)

3. Cell State(記憶單元)

然後,我們需要計算記憶單元的更新值。記憶單元的更新值是根據前一時間步的記憶單元、輸入門的輸出和遺忘門的輸出之間的運算。

self.C_bar_int = np.dot(self.Z, params_dict['W_c']['value']) + params_dict['B_c']['value']
self.C_bar = tanh(self.C_bar_int)
self.C_out = self.f * self.C_in + self.i * self.C_bar

4. Output Gate(輸出門)

最後,我們需要計算輸出門的輸出。輸出門的輸出是根據前一時間步的隱藏狀態和當前輸入之間的點積,以及權重矩陣和偏差項之間的點積。

self.o_int = np.dot(self.Z, params_dict['W_o']['value']) + params_dict['B_o']['value']
self.o = sigmoid(self.o_int)

內容解密

上述程式碼實作了LSTM神經網路中隱藏狀態和記憶單元的更新。其中,self.fself.iself.C_barself.o分別代表遺忘門、輸入門、記憶單元和輸出門的輸出。這些值是根據前一時間步的隱藏狀態和當前輸入之間的點積,以及權重矩陣和偏差項之間的點積計算而得。

圖表翻譯

以下是LSTM神經網路中隱藏狀態和記憶單元更新的流程圖:

  flowchart TD
    A[前一時間步隱藏狀態] --> B[遺忘門]
    B --> C[輸入門]
    C --> D[記憶單元更新]
    D --> E[輸出門]
    E --> F[最終輸出]

這個流程圖展示了LSTM神經網路中隱藏狀態和記憶單元更新的過程。其中,遺忘門、輸入門、記憶單元更新和輸出門是LSTM神經網路中的四個重要組成部分。

使用 PyTorch 進行深度學習

PyTorch 是一個流行的深度學習框架,提供了強大的工具和功能來進行神經網路的建構和訓練。在這篇文章中,我們將探討 PyTorch 的基礎知識和使用方法。

Tensor 和 Autograd

PyTorch 的核心是 Tensor 和 Autograd。Tensor 是一個多維陣列,可以用來表示神經網路的輸入、輸出和引數。Autograd 是 PyTorch 的自動微分系統,可以自動計算 Tensor 之間的梯度。

import torch

# 建立一個 Tensor
a = torch.tensor([[3., 3.], [3., 3.]], requires_grad=True)

# 進行計算
b = a * 4
c = b + 3
d = a + 2
e = c * d

# 計算梯度
e_sum = e.sum()
e_sum.backward()

# 印出梯度
print(a.grad)

Model、Layer、Optimizer 和 Loss

PyTorch 的 Model、Layer、Optimizer 和 Loss 是四個重要的概念。

  • Model:代表神經網路的模型,可以包含多個 Layer。
  • Layer:代表神經網路中的單一層,可以是全連線層、卷積層等。
  • Optimizer:代表最佳化器,可以用來更新模型的引數。
  • Loss:代表損失函式,可以用來評估模型的效能。
import torch
import torch.nn as nn

# 定義模型
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.fc1 = nn.Linear(5, 10)  # input layer (5) -> hidden layer (10)
        self.fc2 = nn.Linear(10, 5)  # hidden layer (10) -> output layer (5)

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # activation function for hidden layer
        x = self.fc2(x)
        return x

# 建立模型、最佳化器和損失函式
model = MyModel()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
loss_fn = nn.MSELoss()

# 進行訓練
for epoch in range(100):
    # 前向傳播
    inputs = torch.randn(100, 5)
    labels = torch.randn(100, 5)
    outputs = model(inputs)
    loss = loss_fn(outputs, labels)

    # 反向傳播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 印出損失
    print('epoch {}: loss = {:.4f}'.format(epoch+1, loss.item()))

第7章:使用PyTorch的神經網路函式庫

PyTorch是一個強大的深度學習框架,提供了豐富的工具和函式庫來建構和訓練神經網路。在這一章中,我們將探討如何使用PyTorch的神經網路函式庫來建立和訓練模型。

PyTorch的層和模型

在PyTorch中,層和模型都是從torch.nn.Module類別繼承而來的。層是神經網路中的基本單元,負責執行特定的運算,例如全連線層、卷積層等。模型則是多個層的組合,代表著整個神經網路。

以下是PyTorch層和模型的基本結構:

import torch
import torch.nn as nn

class PyTorchLayer(nn.Module):
    def __init__(self):
        super().__init__()
    
    def forward(self, x: torch.Tensor, inference: bool = False) -> torch.Tensor:
        raise NotImplementedError()

class PyTorchModel(nn.Module):
    def __init__(self):
        super().__init__()
    
    def forward(self, x: torch.Tensor, inference: bool = False) -> torch.Tensor:
        raise NotImplementedError()

在上述程式碼中,PyTorchLayerPyTorchModel都是從torch.nn.Module類別繼承而來的,且都實作了__init__forward方法。

推理模式

在訓練神經網路時,我們需要根據不同的模式(訓練或推理)調整模型的行為。PyTorch提供了一個方便的方式來切換模型的模式,即使用eval()方法。

def inference_mode(m: nn.Module):
    m.eval()

#...

if inference:
    self.apply(inference_mode)

在上述程式碼中,我們定義了一個inference_mode函式,該函式呼叫模型的eval()方法。然後,在模型的forward方法中,我們根據inference旗標呼叫inference_mode函式。

實作DenseLayer

現在,我們可以開始實作DenseLayer了。DenseLayer是一種全連線層,負責執行線性變換和啟用函式。

class DenseLayer(PyTorchLayer):
    def __init__(self, input_size: int, neurons: int, dropout: float = 1.0, activation: nn.Module = None):
        super().__init__()
        self.linear = nn.Linear(input_size, neurons)
        self.activation = activation
        if dropout < 1.0:
            self.dropout = nn.Dropout(1 - dropout)
    
    def forward(self, x: torch.Tensor, inference: bool = False) -> torch.Tensor:
        #...

在上述程式碼中,我們定義了DenseLayer類別,該類別繼承自PyTorchLayer。DenseLayer的__init__方法初始化了線性變換層、啟用函式和dropout層。forward方法則執行線性變換、啟用函式和dropout操作。

內容解密

  • DenseLayer類別繼承自PyTorchLayer,表示它是一種全連線層。
  • __init__方法初始化了線性變換層、啟用函式和dropout層。
  • forward方法執行線性變換、啟用函式和dropout操作。

圖表翻譯

  graph LR
    A[輸入] --> B[線性變換]
    B --> C[啟用函式]
    C --> D[dropout]
    D --> E[輸出]
  • 圖表表示DenseLayer的運算流程:輸入 -> 線性變換 -> 啟用函式 -> dropout -> 輸出。

PyTorch中的神經網路層實作

在PyTorch中,神經網路層可以透過nn.Module類別來實作。下面是一個簡單的神經網路層實作例子:

import torch
import torch.nn as nn

class DenseLayer(nn.Module):
    def __init__(self, input_size, output_size, activation=None, dropout=0.0):
        super(DenseLayer, self).__init__()
        self.linear = nn.Linear(input_size, output_size)
        self.activation = activation
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        x = self.linear(x)
        if self.activation:
            x = self.activation(x)
        if hasattr(self, "dropout"):
            x = self.dropout(x)
        return x

在這個例子中,DenseLayer類別繼承自nn.Module,並定義了一個密集連線層(Dense Layer)。該層包含一個線性變換(Linear Transformation)和一個啟用函式(Activation Function),以及一個dropout層。

實作波士頓房屋價格預測模型

使用上述的DenseLayer類別,可以實作一個簡單的波士頓房屋價格預測模型。下面是模型的實作程式碼:

class HousePricesModel(nn.Module):
    def __init__(self, hidden_size=13, hidden_dropout=0.0):
        super(HousePricesModel, self).__init__()
        self.dense1 = DenseLayer(13, hidden_size, activation=nn.Sigmoid(), dropout=hidden_dropout)
        self.dense2 = DenseLayer(hidden_size, 1)

    def forward(self, x):
        assert x.dim() == 2
        assert x.shape[1] == 13
        x = self.dense1(x)
        x = self.dense2(x)
        return x

在這個例子中,HousePricesModel類別繼承自nn.Module,並定義了一個具有兩個密集連線層的神經網路模型。第一個層使用Sigmoid啟用函式,第二個層輸出預測值。

使用PyTorch的自動梯度計算

PyTorch提供了自動梯度計算的功能,可以自動計算模型引數的梯度。下面是使用PyTorch自動梯度計算的例子:

# 建立模型例項
model = HousePricesModel()

# 建立輸入張量
x = torch.randn(1, 13)

# 計算輸出
output = model(x)

# 計算損失
loss = torch.mean((output - torch.randn(1, 1)) ** 2)

# 自動計算梯度
loss.backward()

在這個例子中,使用PyTorch的自動梯度計算功能,可以自動計算模型引數的梯度。這樣可以簡化模型訓練的過程。

PyTorch模型建立與最佳化器設定

PyTorch是一個強大的深度學習框架,提供了多種工具和功能來幫助使用者建立和訓練神經網路模型。下面是建立一個簡單的PyTorch模型和設定最佳化器的步驟:

深度學習模型建構與訓練:PyTorch實戰

PyTorch 作為一個廣泛使用的深度學習框架,提供豐富的工具和功能,簡化了神經網路的建構和訓練流程。本文將深入探討如何運用 PyTorch 建立和訓練深度學習模型,並結合實際案例進行說明。

張量與自動微分

PyTorch 的核心概念是張量 (Tensor) 和自動微分 (Autograd)。張量是一種多維陣列,用於表示神經網路的輸入、輸出和引數。Autograd 則能自動計算張量之間的梯度,簡化了反向傳播的過程。

import torch

# 建立一個張量,並設定 requires_grad=True 以追蹤梯度
x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)

# 進行運算
y = x * 2
z = y.mean()

# 計算梯度
z.backward()

# 顯示 x 的梯度
print(x.grad)

內容解密

  • 首先,我們建立一個張量 x 並設定 requires_grad=True,使其能夠追蹤梯度。
  • 接著,進行一系列運算,得到最終結果 z
  • 呼叫 z.backward() 啟動反向傳播,計算 zx 的梯度。
  • 最後,x.grad 儲存了 x 的梯度。

圖表翻譯

  graph LR
    X[張量 x] --> Y{x * 2}
    Y --> Z((y.mean()))
    Z --> G[計算梯度]

此圖示展示了計算流程:從張量 x 開始,經過乘法運算得到 y,再經平均值運算得到 z,最後計算 zx 的梯度。

模型、層、最佳化器與損失函式

建構神經網路模型涉及幾個關鍵組成:

  • 模型 (Model): 代表整個神經網路架構,由多個層組成。
  • 層 (Layer): 神經網路的基本單元,例如線性層、卷積層等,負責執行特定運算。
  • 最佳化器 (Optimizer): 負責更新模型引數,例如 SGD、Adam 等。
  • 損失函式 (Loss): 評估模型預測與真實值之間的差異,常用於指導模型訓練。
import torch.nn as nn
import torch.optim as optim

# 定義一個簡單的模型
class SimpleModel(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleModel, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# 建立模型例項、最佳化器和損失函式
model = SimpleModel(input_size=10, hidden_size=20, output_size=5)
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.MSELoss()

# 訓練迴圈 (示意)
for epoch in range(100):
    # ... 前向傳播、計算損失、反向傳播、更新引數 ...
    pass

內容解密

  • SimpleModel 繼承自 nn.Module,定義了包含兩個線性層和一個 ReLU 啟用函式的模型。
  • forward 方法定義了模型的前向傳播邏輯。
  • 使用 optim.Adam 建立最佳化器,並使用 nn.MSELoss 作為損失函式。

圖表翻譯

  graph LR
    I[輸入] --> FC1[線性層 1]
    FC1 --> ReLU[ReLU 啟用函式]
    ReLU --> FC2[線性層 2]
    FC2 --> O[輸出]

此圖示展現了 SimpleModel 的資料流向:輸入經過兩個線性層和一個 ReLU 啟用函式後得到輸出。

波士頓房價預測模型實作

以下展示如何使用 PyTorch 建立一個波士頓房價預測模型:

import torch.nn as nn

class BostonHousingModel(nn.Module):
    def __init__(self, input_size=13, hidden_size=32):
        super().__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x


# 建立模型例項
model = BostonHousingModel()

# 輸入範例 (13 個特徵)
input_data = torch.randn(1, 13)

# 進行預測
predictions = model(input_data)

print(predictions)

內容解密

此模型包含兩個線性層和一個 ReLU 啟用函式。輸入資料包含 13 個特徵,模型輸出房價的預測值。

圖表翻譯

  graph LR
    Input[輸入 (13 特徵)] --> FC1[線性層 1]
    FC1 --> ReLU[ReLU]
    ReLU --> FC2[線性層 2]
    FC2 --> Output[輸出 (房價預測)]

此圖示說明瞭波士頓房價預測模型的資料流程:輸入經過兩個線性層和 ReLU 啟用函式後,輸出房價預測值。

PyTorch 提供了簡潔而強大的工具,讓開發者能輕鬆建構和訓練深度學習模型。從張量和自動微分到模型、層、最佳化器和損失函式,PyTorch 的設計理念著重於靈活性和效率。透過理解這些核心概念,並結合實際案例的練習,開發者可以更有效地運用 PyTorch 解決各種深度學習問題。隨著深度學習技術的持續發展,PyTorch 也將持續演進,提供更豐富的功能和更優異的效能,賦能更多創新應用。對於臺灣的開發者而言,掌握 PyTorch 將有助於提升自身的技術競爭力,並在全球深度學習領域佔有一席之地。