學習資料:從零設計并訓練一個神經網絡,你就能真正理解它了_嗶哩嗶哩_bilibili
這個視頻講得相當清楚。本文是學習筆記,不是原創,圖都是從視頻上截圖的。
1. 神經網絡
2. 案例說明
具體來說,設計一個三層的神經網絡。以數字圖像作為輸入,經過神經網絡的計算,識別出圖像中的數字是幾,從而實現數字圖像的分類。
3. 視頻講解內容的提綱
4. 神經網絡的設計和實現
我們要處理的數據是28*28像素的灰色通道圖像。
這樣的灰色圖像包括了28*28=784個數據點。需要先將他展平為1*784大小的向量。然后將這個向量輸入到神經網絡中。
用一個三層神經網絡處理圖片對應的向量X。輸入成需要接收784維的圖片向量X。X里面每個維度的數據都有一個神經元來接收。因此輸入層要包含784個神經元。
隱藏成用于特征提取特征向量,將輸入的特征向量處理成更高級的特征向量。
因為手寫數字圖像識別并不復雜,所以將隱藏層的神經元個數設置為256。這樣,輸入層和隱藏層之間就會有個784*256的線性層。它可以將一個784維的輸入向量轉換為256維的輸出向量。
該輸出向量會繼續向前傳播到達輸出層。
由于最終要將數字圖像識別為0~9,十種可能的數字。因此,輸出層需要定義10個神經元,對應這十種數字。
256維的向量在經過隱藏層和輸出層之間的線性層計算后,就得到了10維的輸出結果。這個10維的向量就代表了10個數字的預測得分。
為了繼續得到輸出層的預測概率,還要將輸出層的輸出輸入到softmax層。softmax層會將10維的向量轉換為10個概率值p0~p9。p0~p9相加的總和等于1.
5. 神經網絡的Pytorch實現
import torch
from torch import nn# 定義神經網絡Network
class Network(nn.Module):def __init__(self):super().__init__()# 線性層1,輸入層和隱藏層之間的線性層self.layer1 = nn.Linear(784, 258)# 線性層2,隱藏層和輸出層之間的線性層self.layer2 = nn.Linear(256, 10)# 在前向傳播,forward函數中,輸入為圖像xdef forward(self, x):x = x.view(-1, 28 * 28) # 使用view函數,將x展平x = self.layer1(x) # 將x輸入到layer1x = torch.relu(x) # 使用relu激活return self.layer2(x) # 輸入至layer2計算結果# 這里沒有直接定義softmax層,因為后面會使用CrossEntropyLoss損失函數# 在這個損失函數中,會實現softmax的計算
6. 訓練數據的準備和處理
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader# 初學只要知道大致的數據處理流程即可
if __name__ == '__main__'# 實現圖像的預處理pipelinetransform = trnasforms.Compose([# 轉換成單通道灰度圖transforms.Grayscale(num_output_channels=1),# 轉換為張量transforms.ToTensor()])# 使用ImageFolder函數,讀取數據文件夾,構建數據集dataset# 這個函數會將保持數據的文件夾的名字,作為數據的標簽,組織數據train_dataset = datasets.ImageFolder(root='./mnist_images/train', transform=transform)test_dataset = datasets.ImageFolder(root='./mnist_images/test', transform=transform)# 打印他們的長度print("train_dataset length: ", len(train_dataset))print("test_dataset length: ", len(test_dataset))# 使用train_loader, 實現小批量的數據讀取# 這里設置小批量的大小,batch_size=64. 也就是每個批次,包括64個數據train_loader = DataLoader(train_datase, batch_size=64, shuffle=True)# 打印train_loader的長度print("train_loader length: ", len(train_loader))# 6000個訓練數據,如果每個小批量,讀入64個樣本,那么60000個數據會被分成938組# 938*64=60032,說明最后一組不夠64個數據# 循環遍歷train_loader# 每一次循環,都會取出64個圖像數據,作為一個小批量batchfor batch_idx, (data, label) in enumerate(train_loader)if batch_idx == 3:breakprint("batch_idx: ", batch_idx)print("data.shape: ", data.shape) # 數據的尺寸print("label: ", label.shape) # 圖像中的數字print(label)
7. 模型的訓練和測試
import torch
from torch import nn
from torch import optim
from model import Network
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoaderif __name__ == '__main__'# 圖像的預處理transform = transforms.Compose([transforms.Grayscale(num_output_channels=1),transforms.ToTensor()])# 讀入并構造數據集train_dataset = datasets.ImageFolder(root='./mnist_images/train', transform=transform)print("train_dataset length: ", len(train_dataset))# 小批量的數據讀入train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)print("train_loader length: ", len(train_loader))# 在使用Pytorch訓練模型時,需要創建三個對象:model = Network() # 1.模型本身,就是我們設計的神經網絡optimizer = optim.Adam(model.parameters()) #2.優化器,優化模型中的參數criterion = nn.CrossEntropyLoss() #3.損失函數,分類問題,使用交叉熵損失誤差# 進入模型的循環迭代# 外層循環,代表了整個訓練數據集的遍歷次數for epoch in range(10):# 內層循環使用train_loader, 進行小批量的數據讀取for batch_idx, (data, label) in enumerate(train_loader):# 內層每循環一次,就會進行一次梯度下降算法# 包括了5個步驟# 這5個步驟是使用pytorch框架訓練模型的定式,初學時先記住即可# 1. 計算神經網絡的前向傳播結果output = model(data)# 2. 計算output和標簽label之間的損失lossloss = criterion(output, label)# 3. 使用backward計算梯度loss.backward()# 4. 使用optimizer.step更新參數optimizer.step()# 5.將梯度清零optimizer.zero_grad()if batch_idx % 100 == 0:print(f"Epoch {epoch + 1}/10"f"| Batch {batch_idx}/{len(train_loader)}"f"| Loss: {loss.item():.4f}")torch.save(model.state_dict(), 'mnist.pth')
from model import Network
from torchvision import transforms
from torchvision import datasets
import torchif __name__ == '__main__'transform = transforms.Compose([transforms.Grayscale(num_output_channels=1),transforms.ToTensor()])# 讀取測試數據集test_dataset = datasets.ImageFolder(root='./mnist_images/test', transform=transform)print("test_dataset length: ", len(test_dataset))model = Network() # 定義神經網絡模型model.load_state_dict(torch.load('mnist.pth')) # 加載剛剛訓練好的模型文件rigth = 0 # 保存正確識別的數量for i, (x, y) in enumerate(test_dataset):output = model(x) # 將其中的數據x輸入到模型predict = output.argmax(1).item() # 選擇概率最大標簽的作為預測結果# 對比預測值predict和真實標簽yif predict == y:right += 1else:# 將識別錯誤的樣例打印出來img_path = test_dataset.samples[i][0]print(f"wrong case: predict = {predict} y = {y} img_path = {img_path}")# 計算出測試效果sample_num = len(test_dataset)acc = right * 1.0 / sample_numprint("test accuracy = %d / %d = %.3lf" % (right, sample_num, acc))