本篇涵蓋的內容
在之前的文章中,我們已經討論了如何獲取數據,轉換數據以及如何準備自定義數據集,本篇文章將涵蓋更加深入的問題,希望通過詳細的代碼示例,幫助大家了解PyTorch自定義數據集是如何應對各種復雜實際情況中,數據處理的。
更加詳細的,我們將討論下面一些內容:
主題 | 內容 |
---|---|
7 Model 0:沒有數據增強的TinyVGG | 到這個階段,我們已經準備好了數據,讓我們建立一個能夠擬合數據的模型。我們還將創建一些訓練和測試函數來訓練和評估我們的模型。 |
8 探索損失曲線 | 損失曲線是觀察你的模型如何訓練/改進的好方法。它們也是一種很好的方法來判斷你的模型是過擬合還是欠擬合。 |
9 Model 1:帶數據增強功能的TinyVGG | 到目前為止,我們已經嘗試了一個沒有數據增強的模型? |
10 比較模型結果 | 讓我們比較不同模型的損失曲線,看看哪個表現更好,并討論一些改進性能的選項。 |
11 對自定義圖像進行預測 | 我們的模型是在披薩、牛排和壽司圖像的數據集上訓練的。在本節中,我們將介紹如何使用我們訓練好的模型來預測現有數據集之外的圖像。 |
7 Model 0:沒有數據增強的TinyVGG
好了,我們已經看到了如何把數據從文件夾里的圖像變成變換后的張量。
現在讓我們構建一個計算機視覺模型,看看我們是否可以將圖像分類為披薩、牛排或壽司。
首先,我們將從一個簡單的變換開始,僅將圖像大小調整為(64,64)并將它們轉換為張量。
7.1 為模型0創建轉換和加載數據
# Create simple transform
simple_transform = transforms.Compose([ transforms.Resize((64, 64)),transforms.ToTensor(),
])
很好,現在我們有了一個簡單的變換,讓我們
-
加載數據,首先使用torchvision.datasets.ImageFolder()將每個訓練和測試文件夾轉換為Dataset
-
然后使用torch.utils.data.DataLoader())轉換為數據加載器。
-
我們將把batch_size=32和num_workers設置為機器上盡可能多的cpu(這取決于您使用的機器)。
# 1. Load and transform data
from torchvision import datasets
train_data_simple = datasets.ImageFolder(root=train_dir, transform=simple_transform)
test_data_simple = datasets.ImageFolder(root=test_dir, transform=simple_transform)# 2. Turn data into DataLoaders
import os
from torch.utils.data import DataLoader# Setup batch size and number of workers
BATCH_SIZE = 32
NUM_WORKERS = os.cpu_count()
print(f"Creating DataLoader's with batch size {BATCH_SIZE} and {NUM_WORKERS} workers.")# Create DataLoader's
train_dataloader_simple = DataLoader(train_data_simple, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS)test_dataloader_simple = DataLoader(test_data_simple, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS)print(train_dataloader_simple, test_dataloader_simple)
輸出為:
Creating DataLoader's with batch size 32 and 16 workers.
<torch.utils.data.dataloader.DataLoader object at 0x0000024974F734D0> <torch.utils.data.dataloader.DataLoader object at 0x0000024974F07A80>
很好dataloader已經創建好了,現在讓我們設立模型。
7.2創建TinyVGG模型類
在上一篇文章中,我們使用了來自CNN解釋器網站的TinyVGG模型。
讓我們重新創建相同的模型,只不過這次我們將使用彩色圖像而不是灰度圖像(對于RGB像素,in_channels=3而不是in_channels=1)。
class TinyVGG(nn.Module):"""Model architecture copying TinyVGG from: https://poloclub.github.io/cnn-explainer/"""def __init__(self, input_shape: int, hidden_units: int, output_shape: int) -> None:super().__init__()self.conv_block_1 = nn.Sequential(nn.Conv2d(in_channels=input_shape, out_channels=hidden_units, kernel_size=3, # how big is the square that's going over the image?stride=1, # defaultpadding=1), # options = "valid" (no padding) or "same" (output has same shape as input) or int for specific number nn.ReLU(),nn.Conv2d(in_channels=hidden_units, out_channels=hidden_units,kernel_size=3,stride=1,padding=1),nn.ReLU(),nn.MaxPool2d(kernel_size=2,stride=2) # default stride value is same as kernel_size)self.conv_block_2 = nn.Sequential(nn.Conv2d(hidden_units, hidden_units, kernel_size=3, padding=1),nn.ReLU(),nn.Conv2d(hidden_units, hidden_units, kernel_size=3, padding=1),nn.ReLU(),nn.MaxPool2d(2))self.classifier = nn.Sequential(nn.Flatten(),# Where did this in_features shape come from? # It's because each layer of our network compresses and changes the shape of our input data.nn.Linear(in_features=hidden_units*16*16,out_features=output_shape))def forward(self, x: torch.Tensor):x = self.conv_block_1(x)# print(x.shape)x = self.conv_block_2(x)# print(x.shape)x = self.classifier(x)# print(x.shape)return x# return self.classifier(self.conv_block_2(self.conv_block_1(x))) # <- leverage the benefits of operator fusiontorch.manual_seed(42)
model_0 = TinyVGG(input_shape=3, # number of color channels (3 for RGB) hidden_units=10, output_shape=len(train_data.classes)).to(device)
print(model_0)
輸出為:
TinyVGG((conv_block_1): Sequential((0): Conv2d(3, 10, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU()(2): Conv2d(10, 10, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU()(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(conv_block_2): Sequential((0): Conv2d(10, 10, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU()(2): Conv2d(10, 10, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU()(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(classifier): Sequential((0): Flatten(start_dim=1, end_dim=-1)(1): Linear(in_features=2560, out_features=3, bias=True)</