# 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 批次規範化的反向求導


```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()
```
問題:舉出一種初始化不會使神經網路失去意義(整層神經網路輸出一樣的值)?