# 5.2 參數偵錯 ## 5.2.1 權重初始化 對於回歸問題,模型的權重通常被初始化為0。對神經網路而言,權重參數若都被初始化為0,會使一個層中的神經元學習的是同樣的參數,使神經網路退化成每層只有一個層的線性序列。 這會導致神經網路每層包含多個神經元失去意義。 解決方法: 對權重參數做平均為0標準差為0.01的高斯分布,並將權重參數除以輸入數目的平方根 ## 5.2.2 最佳化參數 最佳化參數的方法,需要長期實踐、探索、體會,並參考前人的經驗。 https://arxiv.org/ftp/arxiv/papers/2212/2212.12279.pdf # 5.3 批次規範化 ## 5.3.1 什麼是批次規範化 對中間輸出進行規範化。先對加權和進行規範化,再由啟動函數$\phi$產生啟動值。批次規範化引入了兩個可學習的參數,即縮放參數(scale)和偏移參數(shift)。這允許模型學習更複雜的變換,而不僅僅是簡單的標準化。 主要目的:減緩梯度消失和梯度爆炸,使訓練更加穩定。 ## 5.3.2 批次規範化的反向求導 ![](https://hackmd.io/_uploads/Hk1HPjSgT.jpg) ![](https://hackmd.io/_uploads/rkn8PoSe6.jpg) ```python= import torch import torch.nn as nn import torch.optim as optim import matplotlib.pyplot as plt import numpy as np from tqdm import tqdm # 引入 tqdm # 設定隨機種子以確保結果可重複 torch.manual_seed(42) np.random.seed(42) # 模擬資料生成 def generate_data(samples=1000, channels=1, height=32, width=32): data = np.random.randn(samples, channels, height, width) labels = np.random.randint(0, 2, samples) # 二元分類,0 或 1 return torch.tensor(data, dtype=torch.float32), torch.tensor(labels, dtype=torch.long) # 定義 CNN 模型,包括批次規範化 class CNNWithBN(nn.Module): def __init__(self): super(CNNWithBN, self).__init__() self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1) self.bn1 = nn.BatchNorm2d(32) self.relu = nn.ReLU() self.pool = nn.MaxPool2d(kernel_size=2, stride=2) self.fc1 = nn.Linear(32 * 16 * 16, 2) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.pool(x) x = x.view(-1, 32 * 16 * 16) x = self.fc1(x) return x # 模型、損失函數和優化器初始化 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = CNNWithBN().to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 模擬資料生成 data, labels = generate_data(samples=1000) # 將 samples 設置為較小的值 # 將資料移至 GPU data, labels = data.to(device), labels.to(device) # 訓練模型 num_epochs = 10 losses = [] accuracies = [] # 使用 tqdm 顯示訓練進度 for epoch in range(num_epochs): model.train() optimizer.zero_grad() outputs = model(data) loss = criterion(outputs, labels) loss.backward() optimizer.step() losses.append(loss.item()) # 計算訓練集準確度 _, predicted = torch.max(outputs, 1) accuracy = (predicted == labels).float().mean().item() accuracies.append(accuracy) tqdm.write(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item()}, Accuracy: {accuracy}") # 清理 GPU 記憶體 del outputs torch.cuda.empty_cache() # 繪製損失曲線和學習曲線 plt.figure(figsize=(12, 4)) plt.subplot(1, 2, 1) plt.plot(losses, label='Training Loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.subplot(1, 2, 2) plt.plot(accuracies, label='Training Accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.show() ``` 問題:舉出一種初始化不會使神經網路失去意義(整層神經網路輸出一樣的值)?