讀寫文件
到目前為止,我們討論了如何處理數據,以及如何構建、訓練和測試深度學習模型。
然而,有時我們希望保存訓練的模型,以備將來在各種環境中使用(比如在部署中進行預測)。
此外,當運行一個耗時較長的訓練過程時,最佳的做法是定期保存中間結果,以確保在服務器電源被不小心斷掉時,我們不會損失幾天的計算結果。
因此,現在是時候學習如何加載和存儲權重向量和整個模型了。
(加載和保存張量)
對于單個張量,我們可以直接調用load
和save
函數分別讀寫它們。
這兩個函數都要求我們提供一個名稱,save
要求將要保存的變量作為輸入。
import torch
from torch import nn
from torch.nn import functional as F# 創建一個包含從 0 到 3 的整數的一維張量
x = torch.arange(4)
# 將張量 x 保存到名為 'x-file' 的文件中
torch.save(x, 'x-file')
通常
x-file
的文件格式一般是.pt
或者.pth
,用于保存PyTorch
模型的狀態字典(state_dict)或者整個模型對象。
我們現在可以將存儲在文件中的數據讀回內存。
# 從名為 'x-file' 的文件中加載之前保存的張量,并將其賦值給變量 x2
x2 = torch.load('x-file')
# 打印加載得到的張量 x2
x2
tensor([0, 1, 2, 3])
我們可以[存儲一個張量列表,然后把它們讀回內存。]
# 創建一個包含 4 個零的一維張量
y = torch.zeros(4)
# 將張量 x 和 y 組成一個列表,并保存到名為 'x-files' 的文件中
torch.save([x, y], 'x-files')
# 從 'x-files' 文件中加載保存的張量,并將它們分別賦值給 x2 和 y2
x2, y2 = torch.load('x-files')
# 打印加載得到的張量元組 (x2, y2)
(x2, y2)
(tensor([0, 1, 2, 3]), tensor([0., 0., 0., 0.]))
我們甚至可以(寫入或讀取從字符串映射到張量的字典)。當我們要讀取或寫入模型中的所有權重時,這很方便。
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
mydict2
{'x': tensor([0, 1, 2, 3]), 'y': tensor([0., 0., 0., 0.])}
[加載和保存模型參數]
保存單個權重向量(或其他張量)確實有用,但是如果我們想保存整個模型,并在以后加載它們,單獨保存每個向量則會變得很麻煩。
畢竟,我們可能有數百個參數散布在各處。因此,深度學習框架提供了內置函數來保存和加載整個網絡。需要注意的一個重要細節是,這將保存模型的參數而不是保存整個模型。
例如,如果我們有一個3層多層感知機,我們需要單獨指定架構。因為模型本身可以包含任意代碼,所以模型本身難以序列化。因此,為了恢復模型,我們需要用代碼生成架構,然后從磁盤加載參數。
讓我們從熟悉的多層感知機開始嘗試一下。
import torch
import torch.nn as nn
import torch.nn.functional as Fclass MLP(nn.Module):"""定義一個多層感知機(MLP)模型,繼承自 nn.Module。該模型包含一個隱藏層和一個輸出層。"""def __init__(self):"""初始化 MLP 模型的各層。"""# 調用父類 nn.Module 的構造函數super().__init__()# 定義隱藏層,輸入維度為 20,輸出維度為 256self.hidden = nn.Linear(20, 256)# 定義輸出層,輸入維度為 256,輸出維度為 10self.output = nn.Linear(256, 10)def forward(self, x):"""定義模型的前向傳播過程。參數:x (torch.Tensor): 輸入張量。返回:torch.Tensor: 模型的輸出張量。"""# 對隱藏層的輸出應用 ReLU 激活函數hidden_output = F.relu(self.hidden(x))# 通過輸出層得到最終輸出return self.output(hidden_output)# 創建 MLP 模型的實例
net = MLP()
# 生成一個形狀為 (2, 20) 的隨機輸入張量
X = torch.randn(size=(2, 20))
# 將輸入張量傳入模型進行前向傳播,得到輸出
Y = net(X)
接下來,我們[將模型的參數存儲在一個叫做“mlp.params”的文件中。]
torch.save(net.state_dict(), 'mlp.params')
為了恢復模型,我們[實例化了原始多層感知機模型的一個備份。]
這里我們不需要隨機初始化模型參數,而是(直接讀取文件中存儲的參數。)
# 創建一個新的 MLP 模型實例,用于加載預訓練的參數
clone = MLP()
# 從 'mlp.params' 文件中加載保存的模型參數狀態字典,并將其加載到 clone 模型中
clone.load_state_dict(torch.load('mlp.params'))
# 將模型設置為評估模式,這會影響一些特定層(如 Dropout、BatchNorm)的行為,確保在推理時使用正確的參數
clone.eval()
load_state_dict
方法可以將一個保存好的狀態字典加載到當前的模型實例中,從而實現模型參數的恢復或遷移。狀態字典是一個 Python 字典對象,它包含了模型中所有可學習參數(如權重和偏置)的張量。
clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()
由于兩個實例具有相同的模型參數,在輸入相同的X
時,兩個實例的計算結果應該相同。讓我們來驗證一下。
Y_clone = clone(X)
Y_clone == Y
tensor([[True, True, True, True, True, True, True, True, True, True],[True, True, True, True, True, True, True, True, True, True]])