目錄
一、數據預處理:為模型打下堅實基礎
二、模型構建:多層感知機的實現
三、訓練過程:迭代優化與性能評估
四、測試結果:模型性能的最終檢驗
五、總結與展望
在深度學習的旅程中,多層感知機(MLP)作為最基礎的神經網絡結構,是每位初學者的必經之路。最近,我通過實現和訓練MLP模型,對圖像識別任務有了更深入的理解。本文將從數據預處理、模型構建、訓練過程到最終的測試結果,詳細記錄我的學習過程,并總結MLP在圖像識別任務中的優勢與局限。
一、數據預處理:為模型打下堅實基礎
在任何機器學習任務中,數據預處理都是至關重要的第一步。對于圖像數據,我們需要將其轉換為適合模型處理的格式。以MNIST手寫數字數據集為例,我使用了torchvision.transforms
庫對圖像進行了標準化處理:
transform = transforms.Compose([transforms.ToTensor(), # 轉換為張量并歸一化到[0,1]transforms.Normalize((0.1307,), (0.3081,)) # MNIST數據集的均值和標準差
])
通過ToTensor()
操作,圖像被轉換為張量格式,并且像素值被歸一化到[0,1]區間。Normalize()
操作則進一步對圖像進行標準化,使其均值為0,標準差為1。這有助于加速模型的收斂。
對于彩色圖像數據集(如CIFAR-10),處理方式類似,只是需要對每個通道分別進行標準化:
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 標準化處理
])
數據加載器DataLoader
的使用也非常關鍵,它能夠高效地批量加載數據,并支持多線程加速數據讀取:
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
通過設置shuffle=True
,訓練數據會在每個epoch開始時被打亂,這有助于模型更好地泛化。
二、模型構建:多層感知機的實現
多層感知機(MLP)是一種經典的神經網絡結構,由多個全連接層組成。在MNIST數據集上,我構建了一個簡單的MLP模型:
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten() # 將28x28的圖像展平為784維向量self.layer1 = nn.Linear(784, 128) # 第一層:784個輸入,128個神經元self.relu = nn.ReLU() # 激活函數self.layer2 = nn.Linear(128, 10) # 第二層:128個輸入,10個輸出(對應10個數字類別)def forward(self, x):x = self.flatten(x) # 展平圖像x = self.layer1(x) # 第一層線性變換x = self.relu(x) # 應用ReLU激活函數x = self.layer2(x) # 第二層線性變換,輸出logitsreturn x
在CIFAR-10數據集上,我將模型進行了擴展,增加了層數和神經元數量,并引入了Dropout來防止過擬合:
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.flatten = nn.Flatten() # 將3x32x32的圖像展平為3072維向量self.layer1 = nn.Linear(3072, 512) # 第一層:3072個輸入,512個神經元self.relu1 = nn.ReLU()self.dropout1 = nn.Dropout(0.2) # 添加Dropout防止過擬合self.layer2 = nn.Linear(512, 256) # 第二層:512個輸入,256個神經元self.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(0.2)self.layer3 = nn.Linear(256, 10) # 輸出層:10個類別def forward(self, x):x = self.flatten(x) # 輸入尺寸: [batch_size, 3, 32, 32] → [batch_size, 3072]x = self.layer1(x) # 線性變換: [batch_size, 3072] → [batch_size, 512]x = self.relu1(x) # 應用ReLU激活函數x = self.dropout1(x) # 訓練時隨機丟棄部分神經元輸出x = self.layer2(x) # 線性變換: [batch_size, 512] → [batch_size, 256]x = self.relu2(x) # 應用ReLU激活函數x = self.dropout2(x) # 訓練時隨機丟棄部分神經元輸出x = self.layer3(x) # 線性變換: [batch_size, 256] → [batch_size, 10]return x # 返回未經過Softmax的logits
Dropout是一種有效的正則化技術,它在訓練階段隨機丟棄部分神經元的輸出,從而防止模型對訓練數據過度擬合。
三、訓練過程:迭代優化與性能評估
訓練過程是模型學習數據特征的關鍵階段。我使用了Adam優化器和交叉熵損失函數,這是分類任務中常用的組合:
criterion = nn.CrossEntropyLoss() # 交叉熵損失函數,適用于多分類問題
optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam優化器
在訓練過程中,我記錄了每個iteration的損失,并繪制了損失曲線,以便直觀地觀察模型的收斂情況:
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):model.train() # 設置為訓練模式all_iter_losses = [] # 存儲所有 batch 的損失iter_indices = [] # 存儲 iteration 序號for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device) # 移至GPUoptimizer.zero_grad() # 梯度清零output = model(data) # 前向傳播loss = criterion(output, target) # 計算損失loss.backward() # 反向傳播optimizer.step() # 更新參數iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 單Batch損失: {iter_loss:.4f} | 累計平均損失: {running_loss/(batch_idx+1):.4f}')epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totalepoch_test_loss, epoch_test_acc = test(model, test_loader, criterion, device)print(f'Epoch {epoch+1}/{epochs} 完成 | 訓練準確率: {epoch_train_acc:.2f}% | 測試準確率: {epoch_test_acc:.2f}%')plot_iter_losses(all_iter_losses, iter_indices)return epoch_test_acc
通過每100個批次打印一次訓練信息,我可以實時監控模型的訓練進度。同時,每個epoch結束后,我會對模型進行測試,評估其在測試集上的性能。
四、測試結果:模型性能的最終檢驗
經過多次實驗,我發現在MNIST數據集上,MLP模型能夠達到較高的準確率(約96.75%)。然而,在更具挑戰性的CIFAR-10數據集上,即使增加了模型的深度和訓練輪次,最終測試準確率也僅能達到約52.40%。這表明MLP在處理復雜圖像數據時存在明顯的局限性。
五、總結與展望
通過這次學習,我深刻認識到MLP在圖像識別任務中的優勢與不足。MLP結構簡單,易于理解和實現,但在處理圖像數據時,它無法有效利用圖像的空間結構信息,導致在復雜任務上性能受限。此外,深層MLP的參數規模呈指數級增長,容易過擬合,訓練成本也較高。未來,我將深入學習卷積神經網絡(CNN),它專門針對圖像數據設計,能夠自動提取圖像的空間特征,具有更少的參數和更快的訓練速度,是解決圖像識別問題的更優選擇。
@浙大疏錦行