使用Pytorch搭建模型的步驟及教程
我們知道,模型有一個特定的生命周期,了解這個為數據集建模和理解 PyTorch API 提供了指導方向。我們可以根據生命周期的每一個步驟進行設計和優化,同時更加方便調整各種細節。
模型的生命周期的五個步驟如下:
- 1.准備數據
- 2.定義模型
- 3.訓練模型
- 4.評估模型
- 5.進行預測
注意:使用 PyTorch API 有很多方法可以實現這些步驟中的每一個,下面是一些使用Pytorch API最簡單、最常見或最慣用的方法。
一、准備數據
第一步是加載和准備數據。
神經網絡模型需要數值輸入數據和數值輸出數據。
您可以使用標准 Python 庫來加載和准備表格數據,例如 CSV 文件。例如,Pandas 可用於加載 CSV 文件,scikit-learn 中的工具可用於編碼分類數據,例如類標簽。
PyTorch 提供了Dataset 類,您可以對其進行擴展和自定義以加載數據集。
例如,您的數據集對象的構造函數可以加載您的數據文件(例如 CSV 文件)。然后可以覆蓋__len __()可以被用於獲取數據集(行或樣本數)的長度函數和__getitem __() ,其用於獲得由索引的特定示例函數。
加載數據集時,您還可以執行任何所需的轉換,例如縮放或編碼。
下面提供了自定義數據集類的骨架。
# dataset definition
class CSVDataset(Dataset):
# load the dataset
def __init__(self, path):
# store the inputs and outputs
self.X = ...
self.y = ...
# number of rows in the dataset
def __len__(self):
return len(self.X)
# get a row at an index
def __getitem__(self, idx):
return [self.X[idx], self.y[idx]]
加載后,PyTorch 提供DataLoader 類以在模型的訓練和評估期間導航Dataset實例。
可以為訓練數據集、測試數據集甚至驗證數據集創建一個DataLoader實例。
所述random_split()函數可以被用於將數據集分裂成訓練集和測試集。拆分后,可以將數據集中的行選擇提供給 DataLoader,同時提供批量大小以及是否應在每個 epoch 中對數據進行混洗。
random_split(dataset, lengths)
返回從原始數據集隨機拆分的 n 個非重疊數據集。lengths 參數指定每個拆分的長度。
例如,我們可以通過傳入數據集中的選定行樣本來定義DataLoader。
DataLoader(dataset, batch_size=1, shuffle=False)
返回給定數據集的迭代,每批具有指定數量的樣本。該函數還有許多其他參數。
shuffle參數設置為“True”,以便在每個epoch之后對數據進行shuffled。這對於驗證和測試數據集是不必要的,因為我們將只對它們進行評估,而順序並不重要。
...
# create the dataset
dataset = CSVDataset(...)
# select rows from the dataset
train, test = random_split(dataset, [[...], [...]])
# create a data loader for train and test sets
train_dl = DataLoader(train, batch_size=32, shuffle=True)
test_dl = DataLoader(test, batch_size=1024, shuffle=False)
定義后,可以枚舉DataLoader,每次迭代產生一批樣本。
# train the model
for i, (inputs, targets) in enumerate(train_dl):
...
二、定義模型
下一步是定義模型。
在 PyTorch 中定義模型的習慣用法涉及定義一個擴展Module 類的類。
nn.Module 是為所有神經網絡模型擴展的基類。我們定義的模型有四個功能
1.__ init __(self)
該函數調用超類的構造函數。這是強制性的。
此處使用 torch.nn 庫定義了該模型的不同層。層的類型和數量特定於手頭的問題。它可以是單層線性模型,也可以是基於復雜數學模型的多層。
還聲明了每一層的輸入和輸出大小以及其他必需的參數。每層的大小和其他值可以作為構造函數中的參數進行檢索,從而允許模型實例具有可變架構或硬編碼。
2.forward(self, x)
此函數定義數據如何通過一次前向傳遞。可以從 torch.nn.functional 庫定義不同層的激活函數。
3.training_step(self,batch)
在這個函數中,我們定義了模型的一個訓練步驟,該步驟接收一批數據並返回損失。
對於給定的批次,我們將輸入和目標分開,這里是圖像及其標簽。輸入通過使用“ self ”關鍵字調用的 forward 函數傳遞,以獲得輸出。
將適當的損失函數應用於輸出和目標以計算損失。
4.validation_step(self,batch)
在這個函數中,我們定義了一個驗證步驟,即我們評估當前狀態的模型。
給定批次的損失是按照上面的 training_step() 函數中的描述計算的。除此之外,還可以評估其他幾個指標,例如准確度、auc、精確度、召回率等等。
這些指標的結果用於評估模型的性能,而不是用於訓練過程。因此,我們將.detach()應用於結果以將它們從梯度計算中排除。
對來自 DataLoader 對象的每批數據調用模型的 validation_step() 函數。輸出列表可以看作是一個二維數組,每一行對應一個批次,每一行按順序保存損失和 n 個度量的值。
它的轉置如下:
這使得使用 torch.mean() 函數更容易計算平均損失和其他指標。.item() 函數用於返回數值而不是單值張量。
fit擬合函數
fit 函數接受許多參數,其中一個是默認優化函數。創建了優化器的一個實例。在每個epoch:
- 每一批訓練集都經過模型的training_step()函數得到loss。
- 梯度是使用 .backward() 函數計算的。
- 優化器根據梯度更新權重和偏差。
- 梯度值被重置為 0,這樣它們就不會在 epoch 上累積。
- 在訓練階段結束時,將評估驗證集並將結果附加到歷史記錄中。
你的類的構造函數定義了模型的層,而 forward() 函數是定義如何通過模型的定義層向前傳播輸入的覆蓋。
此外,Pytorch Module還有許多網絡層級可用,例如Linear用於全連接層,Conv2d用於卷積層,MaxPool2d用於池化層。
激活函數也可以定義為層,例如ReLU、Softmax和Sigmoid。
下面是一個具有一層的簡單 MLP 模型的示例。
# model definition
class MLP(Module):
# define model elements
def __init__(self, n_inputs):
super(MLP, self).__init__()
self.layer = Linear(n_inputs, 1)
self.activation = Sigmoid()
# forward propagate input
def forward(self, X):
X = self.layer(X)
X = self.activation(X)
return X
給定層的權重也可以在構造函數中定義層后初始化。
...
xavier_uniform_(self.layer.weight)
三、訓練模型
訓練過程要求您定義損失函數和優化算法。
常見的損失函數包括:
- BCELoss:二元分類的二元交叉熵損失。
- CrossEntropyLoss:多類分類的分類交叉熵損失。
- MSELoss:回歸的均方損失。
有關損失函數的更多信息,請參閱教程:
使用隨機梯度下降進行優化,標准算法由SGD 類提供,盡管該算法的其他版本也可用,例如Adam。
# define the optimization
criterion = MSELoss()
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
訓練模型涉及枚舉訓練數據集的DataLoader。
首先,訓練時期的數量需要一個循環。然后,隨機梯度下降的小批量需要一個內循環。
...
# enumerate epochs
for epoch in range(100):
# enumerate mini batches
for i, (inputs, targets) in enumerate(train_dl):
...
模型的每次更新都涉及相同的一般模式,包括:
- 清除最后一個誤差梯度。
- 輸入通過模型的前向傳遞。
- 計算模型輸出的損失。
- 通過模型反向傳播錯誤。
- 更新模型以減少損失。
...
# clear the gradients
optimizer.zero_grad()
# compute the model output
yhat = model(inputs)
# calculate loss
loss = criterion(yhat, targets)
# credit assignment
loss.backward()
# update model weights
optimizer.step()
四、評估模型
一旦模型擬合好,就可以在測試數據集上對其進行評估。
這可以通過將DataLoader用於測試數據集並收集測試集的預測,然后將預測與測試集的預期值進行比較並計算性能指標來實現。
...
for i, (inputs, targets) in enumerate(test_dl):
# evaluate the model on the test set
yhat = model(inputs)
...
五、進行預測
擬合模型可用於對新數據進行預測。
例如,您可能有一張圖像或一行數據,並且想要進行預測。
這要求您將數據包裝在PyTorch Tensor數據結構中。
Tensor只是用於保存數據的 NumPy 數組的 PyTorch 版本。它還允許您在模型圖中執行自動微分任務,例如在訓練模型時調用Backward()。
預測也將是一個Tensor,盡管您可以通過從自動微分圖中分離張量並調用 NumPy 函數來檢索 NumPy 數組。
...
# convert row to data
row = Variable(Tensor([row]).float())
# make prediction
yhat = model(row)
# retrieve numpy array
yhat = yhat.detach().numpy()