在這個教程中,我們將使用 PyTorch 訓練一個簡單的多層感知機(MLP)模型來解決 MNIST 手寫數字分類問題,并且使用 TensorBoard 來可視化訓練過程中的不同信息,如損失、準確度、圖像、參數分布和學習率變化。
步驟 1:安裝必要的庫
首先,確保你已經安裝了必要的 Python 庫。如果尚未安裝,可以通過以下命令進行安裝:
pip install torch torchvision tensorboard
torch
和 torchvision
是 PyTorch 中的核心庫,而 tensorboard
是用于在瀏覽器中可視化訓練過程的工具。
步驟 2:導入庫
導入 PyTorch 及相關的庫:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
from torch.utils.tensorboard import SummaryWriter
import os
這些庫分別用于:
torch
:PyTorch 核心庫,包含各種模型和優化工具。torchvision
:包含數據集和預訓練模型。SummaryWriter
:用于將訓練過程中的數據寫入 TensorBoard。os
:文件系統操作,用于創建日志目錄。
步驟 3:加載和預處理數據
我們將使用 MNIST 數據集,它包含手寫數字的圖像。使用 torchvision
來加載并應用預處理:
# 數據預處理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,)) # 歸一化
])# 下載訓練集和測試集
train_set = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)test_set = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=1000, shuffle=False)
transforms.ToTensor()
:將圖像數據從PIL
圖像轉換為 PyTorch 張量。transforms.Normalize()
:對圖像進行歸一化處理,將數據標準化為均值為 0,標準差為 1。
train_loader
和 test_loader
分別是用于訓練和測試的 PyTorch 數據加載器。
步驟 4:定義模型
我們將創建一個簡單的 多層感知機(MLP),包含兩個全連接層,使用 ReLU 激活函數。
# 簡單的多層感知機 (MLP)
class SimpleMLP(nn.Module):def __init__(self):super(SimpleMLP, self).__init__()self.fc1 = nn.Linear(28*28, 128)self.fc2 = nn.Linear(128, 64)self.fc3 = nn.Linear(64, 10) # 10個輸出類def forward(self, x):x = x.view(-1, 28*28) # 展平圖像x = F.relu(self.fc1(x)) # 激活函數x = F.relu(self.fc2(x)) # 激活函數return self.fc3(x) # 輸出層
fc1
, fc2
, fc3
分別是模型的全連接層,每一層的輸入和輸出維度通過 Linear
層來定義。
步驟 5:設置損失函數和優化器
選擇適當的損失函數和優化器來訓練模型:
# 實例化模型
model = SimpleMLP()# 使用 GPU 或 CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)# 損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
CrossEntropyLoss
是用于分類問題的標準損失函數。Adam
優化器是一種自適應學習率的優化方法,適用于大多數任務。
步驟 6:設置 TensorBoard Writer
為 TensorBoard 創建一個日志目錄,并初始化 SummaryWriter
:
# TensorBoard 日志保存路徑
log_dir = "./runs/mnist_example"
if not os.path.exists(log_dir):os.makedirs(log_dir)# 初始化 TensorBoard Writer
writer = SummaryWriter(log_dir)# 添加模型的計算圖 (graph)
sample_data, _ = next(iter(train_loader))
writer.add_graph(model, sample_data.to(device))
log_dir
是 TensorBoard 保存日志文件的目錄。SummaryWriter
用于記錄訓練過程中的數據。add_graph
用于將模型結構寫入 TensorBoard。
步驟 7:訓練模型
接下來,我們定義訓練過程。在每 100 步記錄一次損失和準確度,每 1000 步記錄一次訓練圖像。
# 訓練周期
epochs = 10
global_step = 0
for epoch in range(epochs):running_loss = 0.0correct = 0total = 0# 訓練階段model.train()for i, (inputs, labels) in enumerate(train_loader):inputs, labels = inputs.to(device), labels.to(device)# 清空梯度optimizer.zero_grad()# 前向傳播outputs = model(inputs)# 計算損失loss = criterion(outputs, labels)loss.backward() # 反向傳播optimizer.step() # 更新參數# 累積損失和精度running_loss += loss.item()_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()# 每 100 步記錄一次if (i + 1) % 100 == 0:avg_loss = running_loss / 100acc = correct / totalprint(f"[Epoch {epoch+1}, Step {i+1}] Loss: {avg_loss:.4f} | Accuracy: {acc:.4f}")# 記錄損失和準確度writer.add_scalar("Loss/train", avg_loss, global_step)writer.add_scalar("Accuracy/train", acc, global_step)# 記錄每層的權重分布for name, param in model.named_parameters():writer.add_histogram(name, param, global_step)running_loss = 0.0correct = 0total = 0# 記錄每1000步的圖像(展示輸入圖像)if (i + 1) % 1000 == 0:img_grid = torchvision.utils.make_grid(inputs[:16]) # 取16個樣本writer.add_image(f"Train_Images/{epoch+1}_{i+1}", img_grid, global_step)global_step += 1
writer.add_scalar
用于記錄訓練中的損失和準確度。writer.add_histogram
用于記錄每層參數的權重分布。writer.add_image
用于記錄訓練樣本的圖像。
步驟 8:測試模型
測試模型并記錄測試集的損失和準確度。
# 測試階段
model.eval()
test_loss = 0.0
correct = 0
total = 0
with torch.no_grad():for inputs, labels in test_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()# 記錄測試集的損失和準確率
test_accuracy = correct / total
test_loss /= len(test_loader)
writer.add_scalar("Loss/test", test_loss, global_step)
writer.add_scalar("Accuracy/test", test_accuracy, global_step)# 測試集的圖像展示
test_images, _ = next(iter(test_loader))
img_grid = torchvision.utils.make_grid(test_images[:16])
writer.add_image('Test_Images', img_grid)
步驟 9:關閉 TensorBoard Writer
完成訓練和測試后,關閉 TensorBoard 寫入器:
# 關閉 TensorBoard 寫入器
writer.close()
步驟 10:啟動 TensorBoard
-
在終端中運行以下命令啟動 TensorBoard:
tensorboard --logdir=./runs/mnist_example
-
打開瀏覽器,訪問 http://localhost:6006 即可查看:
- 損失和精度曲線
- 每層權重分布
- 訓練/測試圖像樣本
- 學習率的變化
總結
在本教程中,我們展示了如何使用 PyTorch 訓練一個簡單的 MLP 模型,利用 TensorBoard 記錄并實時可視化以下內容:
- 損失和準確度曲線
- 每層的權重和梯度分布
- 訓練過程中的圖像
- 學習率的變化
TensorBoard 提供了一種強大的可視化方式,可以幫助你深入了解模型的訓練過程,并有效地進行調優。
好的!以下是 完整的代碼,包括每個部分的實現。每個代碼塊的功能都是按步驟分開的,確保你可以從頭到尾順利運行。
完整代碼:PyTorch + TensorBoard
# 導入所需的庫
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
from torch.utils.tensorboard import SummaryWriter
import os# tensorboard --logdir=./runs/mnist_example# 設置隨機種子(可選)
torch.manual_seed(0)# 數據預處理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,)) # 歸一化
])# 下載訓練集和測試集
train_set = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)test_set = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=1000, shuffle=False)# 定義簡單的多層感知機 (MLP) 模型
class SimpleMLP(nn.Module):def __init__(self):super(SimpleMLP, self).__init__()self.fc1 = nn.Linear(28*28, 128)self.fc2 = nn.Linear(128, 64)self.fc3 = nn.Linear(64, 10) # 10個輸出類def forward(self, x):x = x.view(-1, 28*28) # 展平圖像x = F.relu(self.fc1(x)) # 激活函數x = F.relu(self.fc2(x)) # 激活函數return self.fc3(x) # 輸出層# 實例化模型
model = SimpleMLP()# 使用 GPU 或 CPU
# 設置設備并打印詳細信息
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
if device.type == "cuda":device_name = torch.cuda.get_device_name(device)
else:device_name = "CPU"print("=" * 90)
print(f"Device set to : {device_name}")
print("=" * 90)model.to(device)# 損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)# 設置 TensorBoard Writer
log_dir = "./runs/mnist_example"
if not os.path.exists(log_dir):os.makedirs(log_dir)# 初始化 TensorBoard Writer
writer = SummaryWriter(log_dir)# 添加模型的計算圖 (graph)
sample_data, _ = next(iter(train_loader))
writer.add_graph(model, sample_data.to(device))# 設置學習率調度器(可選)
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)# 訓練模型
epochs = 10
global_step = 0
for epoch in range(epochs):running_loss = 0.0correct = 0total = 0# 訓練階段model.train()for i, (inputs, labels) in enumerate(train_loader):inputs, labels = inputs.to(device), labels.to(device)# 清空梯度optimizer.zero_grad()# 前向傳播outputs = model(inputs)# 計算損失loss = criterion(outputs, labels)loss.backward() # 反向傳播optimizer.step() # 更新參數# 累積損失和精度running_loss += loss.item()_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()# 每 100 步記錄一次if (i + 1) % 100 == 0:avg_loss = running_loss / 100acc = correct / totalprint(f"[Epoch {epoch+1}, Step {i+1}] Loss: {avg_loss:.4f} | Accuracy: {acc:.4f}")# 記錄損失和準確度writer.add_scalar("Loss/train", avg_loss, global_step)writer.add_scalar("Accuracy/train", acc, global_step)# 記錄每層的權重分布for name, param in model.named_parameters():writer.add_histogram(name, param, global_step)running_loss = 0.0correct = 0total = 0# 記錄每1000步的圖像(展示輸入圖像)if (i + 1) % 1000 == 0:img_grid = torchvision.utils.make_grid(inputs[:16]) # 取16個樣本writer.add_image(f"Train_Images/{epoch+1}_{i+1}", img_grid, global_step)global_step += 1# 更新學習率lr_scheduler.step()# 每個epoch記錄學習率變化writer.add_scalar("Learning_Rate", optimizer.param_groups[0]['lr'], epoch)# 測試模型
model.eval()
test_loss = 0.0
correct = 0
total = 0
with torch.no_grad():for inputs, labels in test_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)loss = criterion(outputs, labels)test_loss += loss.item()_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()# 記錄測試集的損失和準確率
test_accuracy = correct / total
test_loss /= len(test_loader)
writer.add_scalar("Loss/test", test_loss, global_step)
writer.add_scalar("Accuracy/test", test_accuracy, global_step)# 測試集的圖像展示
test_images, _ = next(iter(test_loader))
img_grid = torchvision.utils.make_grid(test_images[:16])
writer.add_image('Test_Images', img_grid)# 關閉 TensorBoard 寫入器
writer.close()
解釋與步驟
-
導入庫:我們首先導入了
torch
,torchvision
, 和SummaryWriter
來處理模型的定義、數據加載和 TensorBoard 寫入。 -
數據加載:使用
torchvision.datasets.MNIST
下載并加載 MNIST 數據集,使用DataLoader
進行批量加載。 -
模型定義:定義了一個簡單的多層感知機(MLP)模型,包括兩層全連接層和一個輸出層。每層使用 ReLU 激活函數。
-
損失函數和優化器:使用交叉熵損失函數 (
CrossEntropyLoss
) 和 Adam 優化器。Adam 是一種常見的自適應優化算法,能有效優化深度學習模型。 -
TensorBoard 設置:
- 創建一個
SummaryWriter
來將訓練過程中的各種信息寫入日志。 - 使用
writer.add_graph(model, sample_data)
記錄模型結構。 - 記錄每個訓練步驟中的損失、準確度和模型參數(權重)分布。
- 創建一個
-
訓練過程:
- 每 100 步記錄一次當前損失和準確度。
- 每 1000 步展示當前批次的圖像樣本。
-
學習率調度器:使用
StepLR
學習率調度器,每訓練 5 個 epoch,學習率降低 10 倍。 -
測試過程:在訓練結束后,評估模型在測試集上的表現,并記錄測試集的損失和準確度。
-
關閉 TensorBoard:訓練和測試結束后,關閉
SummaryWriter
以保存日志。
啟動 TensorBoard
- 運行上面的代碼后,終端會生成 TensorBoard 日志。
- 打開終端,使用以下命令啟動 TensorBoard:
tensorboard --logdir=./runs/mnist_example
- 然后,打開瀏覽器,訪問 http://localhost:6006,即可看到訓練過程的可視化界面。
在 TensorBoard 中可視化的內容
- Scalars:損失和準確度曲線。
- Histograms:每層權重的分布情況。
- Images:訓練圖像和測試圖像樣本。
- Learning Rate:學習率隨訓練過程的變化。