目錄
- 1 數據
- (1)導入數據
- (2)數據集可視化
- (3)為自己制作的數據集創建類
- (4)數據集批處理
- (5)數據預處理
- 2 神經網絡
- (1)定義神經網絡類
- (3)模型參數
- 3 最優化模型參數
- (1)超參數
- (2)損失函數
- (3)優化方法
- 4 模型的訓練與測試
- (1)訓練循環與測試循環
- (2)禁用梯度跟蹤
- 5 模型的保存、導入與GPU加速
- (1)模型的保存與導入
- (2)GPU加速
- 總結
1 數據
(1)導入數據
我們以Fashion-MNIST數據集為例,介紹一下關於pytorch的數據集導入。
PyTorch域庫提供許多預加載的數據集(如FashionMNIST),這些數據集是torch.utils.data.Dataset的子類,並實現瞭特定於指定數據的功能。
Fashion-MNIST是Zalando文章中的圖像數據集,包含60,000個訓練示例和10,000個測試示例。每個示例包括28×28灰度圖像和來自10個類中的一個的關聯標簽。
import torch from torchvision import datasets from torchvision.transforms import ToTensor import matplotlib.pyplot as plt import os os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE' # 沒有這句會報錯,具體原因我也不知道 training_data = datasets.FashionMNIST( root="../data", train=True, download=True, transform=ToTensor() ) test_data = datasets.FashionMNIST( root="../data", train=False, download=True, transform=ToTensor() )
輸出(下面的截圖不完整)
我們使用以下參數加載FashionMNIST數據集:
root是存儲訓練/測試數據的路徑,
train指定訓練或測試數據集,
download=True 如果數據集不存在於指定存儲路徑,那麼就從網上下載。
transform和target_transform用於指定屬性和標簽轉換操作,這裡所說的“轉換操作”,通常封裝在torchvision.transforms中,因此通常需要導入torchvision.transforms,或者導入這個包中的操作
(2)數據集可視化
我們可以像列表一樣手動索引數據集:training_data[index]。我們使用matplotlib來可視化訓練數據中的一些示例。
labels_map = { 0: "T-Shirt", 1: "Trouser", 2: "Pullover", 3: "Dress", 4: "Coat", 5: "Sandal", 6: "Shirt", 7: "Sneaker", 8: "Bag", 9: "Ankle Boot", } figure = plt.figure(figsize=(8, 8)) cols, rows = 3, 3 for i in range(1, cols * rows + 1): # 從0-len(training_data)中隨機生成一個數字(不包括右邊界) sample_idx = torch.randint(len(training_data), size=(1,)).item() img, label = training_data[sample_idx] # 獲得圖片和標簽 figure.add_subplot(rows, cols, i) plt.title(labels_map[label]) plt.axis("off") # 坐標軸不可見 plt.imshow(img.squeeze(), cmap="gray") # 顯示灰度圖 plt.show()
輸出
上面的程式中,有兩個地方指的註意,一個是可以求training_data的長度,另一個可以通過索引獲得單個樣本,當然這裡的樣本已經被轉換成瞭張量,如下圖所示
(3)為自己制作的數據集創建類
如果要導入自己制作的數據集,需要編寫一個類,這個類用於繼承torch.utils.data中的Dataset類。自制的數據集類必須實現三個函數:init、len__和__getitem,分別是初始化類,求長度len(obj),通過索引獲得單個樣本(像列表一樣)。
import os import pandas as pd from torch.utils.data import Dataset from torchvision.io import read_image class CustomImageDataset(Dataset): def __init__(self, annotations_file, img_dir, transform=None, target_transform=None): self.img_labels = pd.read_csv(annotations_file) self.img_dir = img_dir self.transform = transform self.target_transform = target_transform def __len__(self): return len(self.img_labels) def __getitem__(self, idx): img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0]) image = read_image(img_path) label = self.img_labels.iloc[idx, 1] if self.transform: image = self.transform(image) if self.target_transform: label = self.target_transform(label) return image, label
具體細節可以在pytorch的官網教程:https://pytorch.org/tutorials/beginner/basics/data_tutorial.html
Creating a Custom Dataset for your files
(4)數據集批處理
上面的程式中,雖然可以使用索引獲得樣本,但一次隻能獲得單個樣本,無法像列表、張量、numpy切片一樣一次切出多個
而在訓練模型的時候,我們希望能夠批處理,即一次處理若幹個樣本,同時,我們希望數據在每次遍歷完之後打亂一次,以減少過擬合,並使用Python的多處理來加快數據提取。
pytorch中,專門有一個類可以實現上述功能,即torch.utils.data.DataLoader
下面的程式是將數據集導入到DataLoader中
from torch.utils.data import DataLoader train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True) # train_dataloader是一個DataLoader類的對象 test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
training_data和test_data就是前面導入的數據集,由於我們指定瞭batch的大小是64,因為我們指定瞭shuffle=True,所以在遍歷所有batch之後,數據將被打亂。
此時training_data和test_data仍然不是可迭代對象,還需要將其變成可迭代對象,可以使用iter函數將每一個batch轉化成可迭代對象,或者enumerate函數將其的每個batch帶上序號變成元組
用iter函數
for batch_index, (features, label) in enumerate(train_dataloader): print(batch_index) print(f"Feature batch shape: {features.size()}") print(f"Labels batch shape: {label.size()}") img = features[0].squeeze() label = label[0] plt.imshow(img, cmap="gray") plt.show() print(f"Label: {label}") break
輸出
上面的程式中,train_features, train_labels都是包含64個樣本的張量
用enumerate函數
for batch_index, (features, label) in enumerate(train_dataloader): print(batch_index) print(f"Feature batch shape: {features.size()}") print(f"Labels batch shape: {label.size()}") img = features[0].squeeze() label = label[0] plt.imshow(img, cmap="gray") plt.show() print(f"Label: {label}") break
(5)數據預處理
數據並不總是以訓練機器學習算法所需的最終處理形式出現,因此我們需要對數據進行一些變換操作,使其適合於訓練。
所有的TorchVision數據集都有兩個參數,它們接受包含轉換邏輯的可調用對象:(1)transform用於修改特性,(2)target_transform用於修改標簽
torchvision.transforms模塊提供瞭多種常用的轉換,這裡我們介紹一下ToTensor和Lambda。
為瞭進行訓練,我們需要將FashionMNIST中的特征轉化為normalized tensors,將標簽轉化為One-hot編碼的張量。為瞭完成這些變換,我們使用ToTensor和Lambda。
import torch from torchvision import datasets from torchvision.transforms import ToTensor, Lambda ds = datasets.FashionMNIST( root="data", train=True, download=True, transform=ToTensor(), target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(dim=0, index=torch.tensor(y), value=1)) )
ToTensor將PIL圖像或NumPy ndarray轉換為FloatTensor,並將圖像的像素值(或者灰度值)縮放到[0, 1]區間
Lambda可以用於任何用戶定義的lambda函數,在這裡,我們定義一個函數來將整數轉換為一個one-hot編碼張量,首先建立一個長度為10的0張量(之所以為10,是因為有10個類別),然後調用scatter_函數,把對應的位置換成1。scatter_函數的用法如下:
更多torchvision.transforms的API詳見:https://pytorch.org/vision/stable/transforms.html
2 神經網絡
神經網絡由對數據進行操作的層/模塊組成,torch.nn提供瞭構建的神經網絡所需的所有構建塊。PyTorch中的每個模塊都繼承瞭nn.Module,神經網絡本身就是一個模塊,它由其他模塊(層)組成,這種嵌套結構允許輕松構建和管理復雜的體系結構。
在下面的小節中,我們將構建一個神經網絡來對FashionMNIST數據集中的圖像進行分類。
(1)定義神經網絡類
我們通過繼承nn.Module來定義我們的神經網絡類,並在__init__中初始化神經網絡層,每一個nn.Module的子類在forward方法中繼承瞭對輸入數據的操作。
在初始化方法中搭建網絡結構
class NeuralNetwork(nn.Module): def __init__(self): super(NeuralNetwork, self).__init__() self.flatten = nn.Flatten() # 打平 self.linear_relu_stack = nn.Sequential( nn.Linear(28*28, 512), # 線性層 nn.ReLU(), # 激活層 nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 10), nn.ReLU() ) def forward(self, x): x = self.flatten(x) # 打平層 logits = self.linear_relu_stack(x) # 線性激活層 return logits
We create an instance of NeuralNetwork, and print its structure.
我們可以建立一個NeuralNetwork(即剛剛定義的類)的實例,並打印它的結構
model = NeuralNetwork() print(model)
輸出
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
(5): ReLU()
)
)
使用模型時,我們將輸入數據傳遞給它,這將執行模型的forward方法,以及一些背後的操作。註意:不要直接調用model.forward() !
定義好我們自己的神經網絡類之後,我們可以隨機生成一個張量,來測試一下輸出的size是否符合要求
每個樣本傳入模型後會得到一個10維的張量,將這個張量傳入nn.Softmax的實例中,可以得到每個類別的概率
X = torch.rand(1, 28, 28) # 生成一個樣本 logits = model(X) # 將樣本輸入到模型中,自動調用forward方法 print(logits.size()) pred_probab = nn.Softmax(dim=1)(logits) # 實例化一個Softmax對象,並通過對象調用 y_pred = pred_probab.argmax(1) # 獲得概率最大索引 print(f"Predicted class: {y_pred}")
輸出
torch.Size([1, 10])
Predicted class: tensor([8])
(2)神經網絡組件
上面搭建神經網絡時,我們使用瞭打平函數、線性函數、激活函數,我們來看看這些函數的功能
打平層
input_image = torch.rand(3,28,28) print(input_image.size())
輸出
torch.Size([3, 28, 28])
線性層
layer1 = nn.Linear(in_features=28*28, out_features=20) hidden1 = layer1(flat_image) print(hidden1.size())
輸出
torch.Size([3, 20])
線性層其實就是實現瞭 y=w*x + b,其實是和下面的程式是等效的,但下面的程式不適合放在nn.Sequential中(但可以放在forward方法裡)
w = torch.rand(784, 20) b = torch.rand((1, 20)) hidden2 = flat_image @ w + b print(hidden2.size())
輸出
torch.Size([3, 20])
nn.Sequential是一個模塊容器類,在初始化時,將各個模塊按順序放入容器中,調用模型時,數據按照初始化時的順序傳遞。
例如:
seq_modules = nn.Sequential( flatten, # 在nn.Sequential中可以調用其他模塊 layer1, nn.ReLU(), nn.Linear(20, 10) ) input_image = torch.rand(3,28,28) logits = seq_modules(input_image)
在nn.Sequential中可以調用其他模塊,nn.Sequential定義的模塊也可以被其他模塊調用
(3)模型參數
神經網絡中的許多層都是參數化的,也就是說,在訓練過程中會優化相關的權值和偏差,我們可以使用模型的parameters()或named_parameters()方法訪問所有參數。
model.parameters()返回的是一個參數生成器,可以用list()將其轉化為列表,例如
para_list = list(model.parameters()) # 將參數生成器轉換成列表之後,列表的第一個元素是w,第二個元素是b print(type(para_list[0])) print(f'number of linear_layers :{len(para_list)/2}') print('weights:') print(para_list[0][:2]) # 隻切出兩個樣本來顯示 print('bias:') print(para_list[1][:2]) print('\nthe shape of first linear layer:', para_list[0].shape)
輸出
<class ‘torch.nn.parameter.Parameter’>
number of linear_layers :3.0
weights:
tensor([[ 0.0135, 0.0206, 0.0051, …, -0.0184, -0.0131, -0.0246],
[ 0.0127, 0.0337, 0.0177, …, 0.0304, -0.0177, 0.0316]],
grad_fn=<SliceBackward>)
bias:
tensor([0.0333, 0.0108], grad_fn=<SliceBackward>)the shape of first linear layer: torch.Size([512, 784])
named_parameters()方法返回參數的名稱和參數張量,例如:
print("Model structure: ", model, "\n\n") for name, param in model.named_parameters(): print(f"Layer: {name} | Size: {param.size()} | Values : \n{param[:2]} \n") # 隻切出前兩行顯示
輸出
Model structure: NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
(5): ReLU()
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values :
tensor([[ 0.0135, 0.0206, 0.0051, …, -0.0184, -0.0131, -0.0246],
[ 0.0127, 0.0337, 0.0177, …, 0.0304, -0.0177, 0.0316]],
grad_fn=<SliceBackward>)Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values :
tensor([0.0333, 0.0108], grad_fn=<SliceBackward>)Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values :
tensor([[ 0.0338, 0.0266, -0.0030, …, -0.0163, -0.0096, -0.0246],
[-0.0292, 0.0302, -0.0308, …, 0.0279, -0.0291, -0.0105]],
grad_fn=<SliceBackward>)Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values :
tensor([ 0.0137, -0.0036], grad_fn=<SliceBackward>)Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values :
tensor([[ 0.0029, -0.0025, 0.0105, …, -0.0054, 0.0090, 0.0288],
[-0.0391, -0.0088, 0.0405, …, 0.0376, -0.0331, -0.0342]],
grad_fn=<SliceBackward>)Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values :
tensor([0.0406, 0.0369], grad_fn=<SliceBackward>)
更多關於torch.nn的API請看:https://pytorch.org/docs/stable/nn.html
3 最優化模型參數
(1)超參數
在繪制計算圖之前,需要給出超參數,這裡說的超參數,指的是學習率、批大小、迭代次數等
learning_rate = 1e-3 batch_size = 64 epochs = 5
(2)損失函數
回歸問題一般用nn.MSELoss,二分類問題一般用nn.BCELoss,多分類問題一般用nn.CrossEntropyLoss,這裡FashionMNIST中,標簽有十個類別,因此這裡我們用nn.CrossEntropyLoss
# Initialize the loss function loss_fn = nn.CrossEntropyLoss()
(3)優化方法
這裡我們用隨機梯度下降,即每傳入一個樣本,更新一次參數
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
更多優化方法的API,可以看:https://pytorch.org/docs/stable/optim.html
常用的優化算法原理,可以看:https://zhuanlan.zhihu.com/p/78622301
4 模型的訓練與測試
(1)訓練循環與測試循環
每個epoch包括兩個主要部分:
訓練循環(train_loop)——遍歷訓練數據集並嘗試收斂到最優參數。
驗證/測試循環(test_loop)——遍歷測試數據集以檢查模型性能是否正在改善。
我們先把上述兩個過程封裝成函數
def train_loop(dataloader, model, loss_fn, optimizer): size = len(dataloader.dataset) for batch, (X, y) in enumerate(dataloader): # Compute prediction and loss,下面兩步相當於繪制計算圖 pred = model(X) loss = loss_fn(pred, y) # Backpropagation optimizer.zero_grad() # 梯度信息清零 loss.backward() # 反向傳播 optimizer.step() # 一旦有瞭梯度,就可以更新參數 if batch % 100 == 0: loss, current = loss.item(), batch * len(X) print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]") def test_loop(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) test_loss, correct = 0, 0 with torch.no_grad(): # 禁用梯度跟蹤,後面會講 for X, y in dataloader: pred = model(X) test_loss += loss_fn(pred, y).item() correct += (pred.argmax(1) == y).type(torch.float).sum().item() test_loss /= num_batches correct /= size print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
現在可以進行訓練瞭
for t in range(epochs): print(f"Epoch {t+1}\n-------------------------------") train_loop(train_dataloader, model, loss_fn, optimizer) test_loop(test_dataloader, model, loss_fn) print("Done!")
輸出
我們可以寫一段程式碼,看看預測的圖片對不對
test_features, test_labels = next(iter(test_dataloader)) logits = model(test_features[0]) pred_probab = nn.Softmax(dim=1)(logits) pred = pred_probab.argmax(1) img = test_features[0].squeeze() # 將長度為1的維度去掉 true_label = test_labels[0] plt.imshow(img, cmap="gray") plt.show() print(f"True label: {true_label}") print(f"Predict: {pred.item()}")
輸出
(2)禁用梯度跟蹤
在上面的測試循環中,使用瞭torch.no_grad()方法,在表示所在的with塊不對梯度進行記錄。
默認情況下,所有requires_grad=True的張量(在創建優化器的時候,內部就把裡面的參數全部設置為瞭requires_grad=True)都跟蹤它們的計算歷史並支援梯度計算。但是,在某些情況下,我們並不需要這樣做,例如,測試的時候,我們隻是想通過網絡進行正向計算。我們可以通過使用torch.no_grad()塊包圍計算程式碼來停止跟蹤計算:
z = torch.matmul(x, w)+b print(z.requires_grad) with torch.no_grad(): z = torch.matmul(x, w)+b print(z.requires_grad)
輸出
True
False
禁用梯度跟蹤主要用於下面兩種情況:
(1)將神經網絡中的一些參數標記為凍結參數,這是對預先訓練過的網絡進行微調的一個常見的場景
(2)當你隻做正向傳遞時,為瞭加快計算速度,因為不跟蹤梯度的張量的計算會更有效率。
5 模型的保存、導入與GPU加速
(1)模型的保存與導入
PyTorch模型將學習到的參數存儲在一個內部狀態字典中,稱為state_dict,我們可以通過torch.save()將模型的參數保存到指定路徑。
保存瞭模型的參數,還需要保存模型的形狀(即模型的結構)
# 保存模型參數 torch.save(model.state_dict(), './model_weights.pth') # 保存模型結構 torch.save(model, './model.pth')
導入模型時,需要先導入模型的結構,再導入模型的參數,程式碼如下:
# 導入模型結構 model_loaded = torch.load('./model.pth') # 如果原來的model在cuda:0上,那麼導入之後,model_loaded也在cuda:0上 # 導入模型參數 model_loaded.load_state_dict(torch.load('model_weights.pth'))
因為model是NeuralNetwork類的一個對象,所以在導入狀態前,必須先有一個NeuralNetwork對象,要麼實例化一個,要麼通過導入結構torch.load(‘./model.pth’)導入一個.
torch.load直接導入模型,不是特別推薦,原因有以下兩點:
(1)如果A.py档案中的程式保存瞭model.pth,如果档案B.py想讀取這個模型,則不能直接用torch.load導入模型結構,必須先實例化一個NeuralNetwork對象,要麼從A.py或者從其他档案中把NeuralNetwork類給導進來,要麼這裡重寫一個與A.py中一模一樣的NeuralNetwork類,類名也要一樣,否則報錯。
# 實例化一個NeuralNetwork對象 model_loaded = NeuralNetwork() # model_loaded默認是CPU中 # 導入模型參數 model_loaded.load_state_dict(torch.load('./gdrive/MyDrive/model_weights.pth'))
(2)如果用torch.load導入模型,當我們在cuda:0上訓練好一個模型並保存時,讀取出來的模型也是默認在cuda:0上的,如果訓練過程的其他數據被放到瞭如cuda:1上,則會報錯。而實例化創建模型,由於.load_state_dict可以跨設備,則無論原來的模型在什麼設備上,都不妨礙把參數導入到新創建的模型對象當中。
綜合上面兩點,torch.load慎用,最好是先實例化後再導入模型狀態。
我們可以用導入的模型做預測
test_features, test_labels = next(iter(test_dataloader)) logits = model_loaded(test_features[0]) # 使用導入的模型 pred_probab = nn.Softmax(dim=1)(logits) pred = pred_probab.argmax(1) img = test_features[0].squeeze() # 將長度為1的維度去掉 true_label = test_labels[0] plt.imshow(img, cmap="gray") plt.show() print(f"True label: {true_label}") print(f"Predict: {pred.item()}")
輸出
(2)GPU加速
默認情況下,張量和模型是在CPU上創建的。如果想讓其在GPU中操作,我們必須使用.to方法(確定GPU可用後)顯式地移動到GPU。需要註意的是,跨設備復制大張量在時間和內存上開銷都是很大的!
# We can move our tensor to the GPU if available device = 'cuda' if torch.cuda.is_available() else 'cpu' print('Using {} device'.format(device))
輸出
Using cuda device
在初始化模型時,可以將模型放入GPU中
model = NeuralNetwork().to(device)
對於張量,可以在創建的時候指定為在GPU上創建,也可以在創建後轉移到GPU當中
X = torch.rand(1, 28, 28, device=device) # 創建時指定設備 Y = torch.rand(10).to(device) # 創建後轉移
當然,張量和模型也能從GPU轉移到CPU當中,我們可以用.device()來查看張量所在設備
另外,需要註意的是,如果需要將模型送到GPU當中,必須在構建優化器之前。因為CPU和GPU中的模型,是兩個不同的對象,構建完優化器再將模型放入GPU,將導致優化器隻優化CPU中的模型參數。
有些電腦有多張顯卡,那麼.to(‘cuda’)默認是將張量或者模型轉移到第一張顯卡(編號為0)上,如果想轉移到其他顯卡上,則用下面的程式
device = torch.device(‘cuda:2') # 2是設備號,假如有八張顯卡,那麼編號就是0—7
torch.save
至此,所有程式已經完成
總結
上面的程式有點亂,我這裡綜合一下:
# coding=utf-8 import torch import torch.nn as nn from torchvision import datasets from torch.utils.data import DataLoader from torchvision.transforms import ToTensor import matplotlib.pyplot as plt import os os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE' # 沒有這句會報錯,具體原因我也不知道 # 導入數據 training_data = datasets.FashionMNIST( root="../data", train=True, download=True, transform=ToTensor() ) test_data = datasets.FashionMNIST( root="../data", train=False, download=True, transform=ToTensor() ) # 定義超參數 # 之所以在這個地方定義,是因為在初始化DataLoader時需要用到batch_size learning_rate = 1e-3 batch_size = 64 epochs = 5 train_dataloader = DataLoader(training_data, batch_size=batch_size, shuffle=True) # train_dataloader是一個DataLoader類的對象 test_dataloader = DataLoader(test_data, batch_size=batch_size, shuffle=True) # 搭建神經網絡 class NeuralNetwork(nn.Module): def __init__(self): super(NeuralNetwork, self).__init__() self.flatten = nn.Flatten() # 打平 self.linear_relu_stack = nn.Sequential( nn.Linear(28*28, 512), # 線性層 nn.ReLU(), # 激活層 nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 10), nn.ReLU() ) def forward(self, x): x = self.flatten(x) # 打平層 logits = self.linear_relu_stack(x) # 線性激活層 return logits # 確定使用設備 device = 'cuda' if torch.cuda.is_available() else 'cpu' # 實例化一個神經網絡類 model = NeuralNetwork().to(device) # 確定損失函數 loss_fn = nn.CrossEntropyLoss() # 確定優化器 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) # 封裝訓練過程 def train_loop(dataloader, model, loss_fn, optimizer): size = len(dataloader.dataset) for batch, (X, y) in enumerate(dataloader): X, y = X.to(device), y.to(device) # 將樣本和標簽轉移到device中 # Compute prediction and loss,下面兩步相當於繪制計算圖 pred = model(X) loss = loss_fn(pred, y) # Backpropagation optimizer.zero_grad() # 梯度信息清零 loss.backward() # 反向傳播 optimizer.step() # 一旦有瞭梯度,就可以更新參數 if batch % 100 == 0: loss, current = loss.item(), batch * len(X) print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]") # 封裝測試過程 def test_loop(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) test_loss, correct = 0, 0 with torch.no_grad(): for X, y in dataloader: X, y = X.to(device), y.to(device) # 將樣本和標簽轉移到device中 pred = model(X) test_loss += loss_fn(pred, y).item() correct += (pred.argmax(1) == y).type(torch.float).sum().item() test_loss /= num_batches correct /= size print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n") # 訓練 for t in range(epochs): print(f"Epoch {t+1}\n-------------------------------") train_loop(train_dataloader, model, loss_fn, optimizer) test_loop(test_dataloader, model, loss_fn) print("Done!") # 保存模型參數 torch.save(model.state_dict(), './model_weights.pth') # 保存模型結構 torch.save(model, './model.pth') # 導入模型結構 model_loaded = torch.load('./model.pth') # 模型自動導入到GPU當中 # 導入模型參數 model_loaded.load_state_dict(torch.load('model_weights.pth')) # 用導入的模型測試 test_features, test_labels = next(iter(test_dataloader)) test_features = test_features.to(device) logits = model_loaded(test_features[0]) # 使用導入的模型 pred_probab = nn.Softmax(dim=1)(logits) pred = pred_probab.argmax(1) # 可視化 img = test_features[0].squeeze() # 將長度為1的維度去掉 img = img.to('cpu') # 繪圖時,需要將張量轉回到CPU當中 true_label = test_labels[0] # 標簽是否轉移到CPU無所謂,因為沒有用於plt的方法中 plt.imshow(img, cmap="gray") plt.show() print(f"True label: {true_label}") print(f"Predict: {pred.item()}")
到此這篇關於pytorch 搭建神經网络的實現的文章就介紹到這瞭,更多相關pytorch 神經网络內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支援!
You may also like
相关贴文:
近期文章
- SHOPIFY REBELLON vs BOOM ESPORT [BO2] – TIMADO, YOPAJ 對上 JACKKY, MAC – ESL ONE BANGKOK 2024 DOTA 2
- Dota2 – Team Spirit VS Shopify Rebellion – ESL One 曼谷
- 德國滑雪選手如何打造 Shopify?
- 2024 年 12 月 2 款必銷產品🚀(Shopify 得獎者)
- Shopify Rebellon vs 獵鷹隊 [BO2] – TIMADO, YOPAJ 對 SKITER, AMMAR – ESL ONE BANGKOK 2024 DOTA 2
- 添加這些直銷產品並觀察您的銷售爆炸式增長#dropshipping #shopify
- 我如何在 19 歲時開始在 30 天內從巴基斯坦開始 Shopify Dropshipping 從 0 美元到 1000 美元
- 我打破了 Shopify 應用程式商店世界紀錄!
- 如何在 Shopify 上傳/更改封面主頁圖片
發佈留言