官术网_书友最值得收藏!

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%。

主站蜘蛛池模板: 和顺县| 于田县| 斗六市| 东莞市| 民和| 东乡县| 汉寿县| 化州市| 定兴县| 兴城市| 万载县| 麻城市| 宁国市| 诸城市| 大连市| 土默特左旗| 乌什县| 江口县| 连州市| 巩义市| 广德县| 育儿| 凤庆县| 中方县| 黑河市| 洛南县| 平原县| 辽阳市| 尼勒克县| 商丘市| 荃湾区| 吴堡县| 宣汉县| 大石桥市| 邛崃市| 德清县| 梁平县| 柏乡县| 长岭县| 蓝山县| 葵青区|