iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
AI & Data

從0開始:傳統圖像處理到深度學習模型系列 第 12

Day 12 - 深度學習初探

  • 分享至 

  • xImage
  •  

深度學習是機器學習的一個分支,它試圖模仿人類大腦中神經網路的結構和功能來進行學習。所謂的「深 (Deep)」,通常指的就是神經網路的「層數」很多。這些層層堆疊的神經元,能夠自動地、層級化地從數據中學習特徵——淺層的網路學習簡單的特徵(如邊緣、顏色),深層的網路則將這些簡單特徵組合起來,形成更複雜、更抽象的概念(從物體的部件到整個物體)。

感知器

感知器是由 Frank Rosenblatt 發明的一種演算法,它可以被看作是史上最簡單的、單層的人工神經元模型。運作流程如下

  1. 接收輸入:接收一個或多個輸入值 x_1, x_2, ..., x_n。

  2. 加權求和:每個輸入 x_i 都被乘以一個對應的權重 w_i。權重代表了這個輸入的重要性。然後,將所有的加權輸入求和,並加上一個偏置 b。

https://ithelp.ithome.com.tw/upload/images/20250822/20178100SLa0XJjsng.png

  1. 激勵函數:將加權總和 z 傳入一個激勵函數 (activation function)。最原始的感知器使用一個簡單的階梯函數 (step function):如果 z 大於某個閾值則輸出1,否則輸出0。

感知器的學習過程,就是透過不斷地調整權重 w 和偏置 b,來使得其輸出結果與真實標籤盡可能一致。然而,單個的感知器有一個致命的缺陷:它只能解決線性可分 (linearly separable) 的問題。

ANN

人工神經網路 (Artificial Neural Network, ANN),也常被稱為多層感知器 (Multi-Layer Perceptron, MLP),就是由多個神經元層組成的網路結構。一個典型的 ANN 包含三個部分:

  1. 輸入層 (input layer): 接收原始數據。神經元的數量等於輸入數據的維度。

  2. 隱藏層 (hidden layers): 介於輸入層和輸出層之間,可以有一層或多層。這些層是真正進行大部分計算和特徵提取的地方。

  3. 輸出層 (output layer): 產生最終的預測結果。神經元的數量等於類別的數量。

為了能學習非線性關係,現代神經網路中的激勵函數,也從簡單的階梯函數,演變成了更平滑、更適合梯度計算的函數,例如 sigmoid、tanh、ReLU (Rectified Linear Unit)。

使用 PyTorch 搭建 ANN

PyTorch 安裝

如果像我一樣是 AMD 的用戶,目前仍需要在 Linux 環境下下載 ROCm ,或使用 ZLUDA 才能使用 GPU 進行 PyTorch 的訓練。ROCm 的安裝方式可參考這裡 https://rocm.docs.amd.com/projects/install-on-linux/en/latest/

安裝完相關前置後,可到 PyTorch 官網,依照使用的環境在終端輸入、下載 PyTorch。

搭建 ANN

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# --- 1. 設定超參數與設備 ---
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"將使用設備: {device}")

input_size = 784  # 28x28
hidden_size = 128 # 隱藏層的神經元數量
num_classes = 10  # 0-9 共 10 個類別
learning_rate = 0.001
batch_size = 64
num_epochs = 5

# --- 2. 載入並預處理 MNIST 數據集 ---
# 定義數據轉換
transform = transforms.Compose([
    transforms.ToTensor(), # 將圖片轉換為 Tensor
    transforms.Normalize((0.1307,), (0.3081,)) # 標準化 (使用 MNIST 的均值和標準差)
])

# 下載訓練集和測試集
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)

# 建立數據載入器
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

# --- 3. 定義神經網路模型 ---
class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet, self).__init__()
        # 定義網路的層
        self.fc1 = nn.Linear(input_size, hidden_size) # 輸入層 -> 隱藏層
        self.relu = nn.ReLU()                         # ReLU 激活函數
        self.fc2 = nn.Linear(hidden_size, num_classes) # 隱藏層 -> 輸出層
    
    def forward(self, x):
        # 定義數據的前向傳播路徑
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

# 建立模型實例並移至指定設備
model = NeuralNet(input_size, hidden_size, num_classes).to(device)

# --- 4. 定義損失函數與優化器 ---
criterion = nn.CrossEntropyLoss() # 交叉熵損失,適用於多分類問題
optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Adam 優化器

# --- 5. 訓練模型 ---
print("開始訓練...")
for epoch in range(num_epochs):
    for i, (images, labels) in enumerate(train_loader):
        # 將數據攤平成 (batch_size, 784) 並移至設備
        images = images.reshape(-1, 28*28).to(device)
        labels = labels.to(device)
        
        # 前向傳播
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # 反向傳播與優化
        optimizer.zero_grad() # 清除之前的梯度
        loss.backward()       # 計算梯度
        optimizer.step()      # 更新權重
        
        if (i+1) % 100 == 0:
            print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {loss.item():.4f}')
print("訓練完成!")

# --- 6. 評估模型 ---
# 將模型設為評估模式 (這會關閉 Dropout 等層)
model.eval()
with torch.no_grad(): # 在此區塊中,不計算梯度,節省記憶體
    correct = 0
    total = 0
    for images, labels in test_loader:
        images = images.reshape(-1, 28*28).to(device)
        labels = labels.to(device)
        outputs = model(images)
        # torch.max 會回傳最大值和其索引
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    print(f'模型在 10000 張測試圖片上的準確率: {100 * correct / total:.2f} %')

結果

模型在 10000 張測試圖片上的準確率: 97.44 %

上一篇
Day 11 - 機器學習初探(二) HOG 與 SVM
下一篇
Day 13 - 卷積神經網路(一) CNN 入門
系列文
從0開始:傳統圖像處理到深度學習模型23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言