- 生成式人工智能(基于PyTorch實現)
- (美)劉煥良
- 2293字
- 2025-06-19 18:35:04
2.3 二分類
本節將首先創建用于訓練的數據的批次,然后在PyTorch中構建一個深度神經網絡,并使用這些數據對模型進行訓練。最后使用訓練好的模型進行預測,并測試預測的準確性。二分類和多類別分類的步驟相似,但有幾個值得注意的例外,詳見下文介紹。
2.3.1 創建批次
我們將創建一個訓練集和一個測試集,訓練集和測試集只包含兩種類別的服裝:T恤和踝靴。在本章后面討論多類別分類時,我們還將創建驗證集,以確定何時停止訓練。為此所用的代碼如下所示:
binary_train_set=[x for x in train_set if x[1] in [0,9]] binary_test_set=[x for x in test_set if x[1] in [0,9]]
只保留數字標簽為0和9的樣本,以創建一個具有平衡訓練集的二分類問題。接下來,我們用清單2.4所示的代碼創建用于訓練深度神經網絡的批次。
清單2.4 創建用于訓練和測試的批次
batch_size=64 binary_train_loader=torch.utils.data.DataLoader( binary_train_set, ? batch_size=batch_size, ? shuffle=True) ? binary_test_loader=torch.utils.data.DataLoader( binary_test_set, ? batch_size=batch_size,shuffle=True)
? #為二分類訓練集創建批次
? #設置每個批次中的樣本數量
? #在創建批次時對樣本進行混洗
? #為二分類測試集創建批次
PyTorch utils包中的DataLoader類可以幫助我們創建成批的數據迭代器。我們將批次大小設置為64,隨后用清單2.4所示的代碼創建了兩個數據加載器:一個訓練集和一個測試集,它們都將用于二分類。在創建批次時,我們對樣本進行混洗(shuffle),這是為了避免原始數據集之間的相關性:如果不同標簽在數據加載器中均勻分布,訓練將會更加穩定。
2.3.2 構建并訓練二分類模型
我們首先要構建一個二分類模型,然后使用T恤和踝靴的圖像訓練該模型。訓練完成后,就可以測試看看該模型能否分辨出T恤和踝靴。我們在清單2.5中使用PyTorch的nn.Sequential類構建神經網絡(后續章節還將使用nn.Module類構建PyTorch神經網絡):
清單2.5 構建二分類模型
import torch.nn as nn device="cuda" if torch.cuda.is_available() else "cpu" ? binary_model=nn.Sequential( ? nn.Linear(28*28,256), ? nn.ReLU(), ? nn.Linear(256,128), nn.ReLU(), nn.Linear(128,32), nn.ReLU(), nn.Linear(32,1), nn.Dropout(p=0.25), nn.Sigmoid()).to(device) ?
? #PyTorch自動檢測是否有可用的啟用了CUDA的GPU
? #在PyTorch中創建一個順序神經網絡
? #一個線性層包含的輸入神經元和輸出神經元數量
? #對層的輸出應用ReLU激活函數
? #應用sigmoid激活函數并在GPU可用時將模型移到GPU上
PyTorch中的Linear()類對輸入數據進行線性變換,這實際上會在神經網絡中創建一個密集層。輸入的形狀是784,因為我們稍后會將二維圖像展平為包含28×28=784個值的一維向量。將二維圖像展平為一維張量,是因為密集層只接收一維輸入。在后續章節中,讀者會發現使用卷積層時無須將圖像展平。網絡中有3個隱藏層,分別有256、128和32個神經元。256、128和32這3個數字是任意選擇的,將它們分別改為300、200和50也不會影響訓練過程。
對這3個隱藏層應用線性整流單元(rectified linear unit,ReLU)激活函數。激活函數可根據加權和決定是否開啟一個神經元,這樣就可以為神經元的輸出引入非線性的特征,從而讓網絡學習輸入和輸出之間的非線性關系。除了極少數例外情況,大部分情況下都將使用ReLU作為激活函數,不過在本書后續章節中也會遇到其他激活函數。
模型最后一層的輸出包含一個單一值,使用sigmoid激活函數將其壓縮到[0, 1],這樣該數值就可以理解為物品是踝靴的概率;至于互補概率,則意味著物品是T恤的概率。
下面將設置學習率,并定義優化器和損失函數:
lr=0.001 optimizer=torch.optim.Adam(binary_model.parameters(),lr=lr) loss_fn=nn.BCELoss()
學習率被設為0.001。學習率的設置是一個經驗問題,需要長期的經驗積累,但也可以使用驗證集進行超參數調優來確定。PyTorch中的大多數優化器都使用0.001作為默認的學習率。Adam優化器是梯度下降算法的一種變體,用于確定在每個訓練步驟中調整模型參數的程度。Adam優化器由Diederik Kingma和Jimmy Ba于2014年首次提出。[1]傳統梯度下降算法只考慮當前迭代中的梯度,相比之下,Adam優化器還會考慮之前迭代中的梯度。
[1] KINGMA D P, BA J. Adam: A method for stochastic optimization[C]//Proceedings of the 3rd International Conference on Learning Representations, 2015.
我們將使用nn.BCELoss(),這是一種二元交叉熵損失函數。損失函數用于衡量機器學習模型的性能。模型的訓練過程需要調整參數以最小化損失函數。二元交叉熵損失函數廣泛應用于機器學習,尤其是二分類問題。它衡量的是分類模型的性能,而該分類模型的輸出值是在0和1之間的概率值。交叉熵損失隨預測概率與實際標簽的偏差的增大而增大。
用清單2.6所示的代碼可以訓練上文構建的神經網絡。
清單2.6 訓練二分類模型
for i in range(50): ? tloss=0 for imgs,labels in binary_train_loader: ? imgs=imgs.reshape(-1,28*28) ? imgs=imgs.to(device) labels=torch.FloatTensor(\ [x if x==0 else 1 for x in labels]) ? labels=labels.reshape(-1,1).to(device) preds=binary_model(imgs) loss=loss_fn(preds,labels) ? optimizer.zero_grad() loss.backward() ? optimizer.step() tloss+=loss.detach() tloss=tloss/n print(f"at epoch {i}, loss is {tloss}")
? #訓練50個輪次
? #針對所有批次進行迭代
? #先將圖像展平,然后將張量移到GPU上
? #將標簽轉換為0和1
? #計算損失
? #反向傳播
在PyTorch中訓練深度學習模型時,loss.backward()計算損失相對于每個模型參數的梯度,從而實現反向傳播;而optimizer.step()根據計算出的梯度更新模型參數,從而最小化損失。簡化起見,我們對模型進行了50個輪次的訓練(1個輪次是指使用訓練數據對模型進行1次訓練)。我們將在2.4.1節中用驗證集和早停止(early stopping)類來決定訓練多少個輪次。在二分類中,我們會將目標標記為0或1。由于只保留標簽分別為0和9的T恤與踝靴,因此需要通過清單2.6的代碼將標簽轉換為0和1。也就是說,轉換后,兩類服裝的標簽分別為0和1。
如果使用GPU,上述訓練只需幾分鐘。如果使用CPU,則需要更長時間,但整體訓練時間應至少不超過1小時。
2.3.3 測試二分類模型
訓練好的二分類模型的預測是一個介于0和1之間的數字。我們使用torch.where()方法將預測轉換為0和1。如果預測概率小于0.5,就將預測標記為0;否則,就將預測標記為1。然后將這些預測與實際標簽進行比較,即可計算出預測的準確性。在清單2.7中,我們用訓練好的模型對測試集進行預測,如下所示。
清單2.7 計算預測的準確性
import numpy as np results=[] for imgs,labels in binary_test_loader: ? imgs=imgs.reshape(-1,28*28).to(device) labels=(labels/9).reshape(-1,1).to(device) preds=binary_model(imgs) pred10=torch.where(preds>0.5,1,0) ? correct=(pred10==labels) ? results.append(correct.detach().cpu()\ .numpy().mean()) ? accuracy=np.array(results).mean() ? print(f"the accuracy of the predictions is {accuracy}")
? #對測試集中的所有批次進行迭代
? #使用訓練好的模型進行預測
? #將預測與標簽進行比較
? #計算批次的準確性
? #計算測試集的準確性
迭代測試集中的所有批次數據。訓練好的模型會得出圖像是踝靴的概率,然后使用torch.where()方法,根據0.5的臨界值將概率轉換為0或1。轉換后的預測要么是0(T恤),要么是1(踝靴)。將預測與實際標簽進行比較,看看模型有多少次是正確的。結果表明,在測試集中,預測的準確率為87.84%。