1. 前言
PyTorch 是目前非常受歡迎的深度學習框架之一,廣泛應用於研究與實務領域。特別是為了更有效率地處理資料前處理與迷你批次管理,PyTorch 提供了一個名為「DataLoader」的工具。
本文將詳細說明 PyTorch 中 DataLoader 的功能與使用方式,包括如何建立自訂資料集。此外,也會介紹常見錯誤與對應的解決方法,對於初學者到中階使用者都非常實用。
閱讀本文您將學到:
- PyTorch 中 DataLoader 的基本功能與使用範例
- 如何建立自訂資料集及其應用
- 常見錯誤與解決對策
如果您是剛開始接觸 PyTorch 的新手,或是在資料處理上遇到瓶頸的使用者,請務必閱讀到最後。
2. 什麼是 DataLoader?其角色與重要性
DataLoader 是什麼?
PyTorch 的 DataLoader 是一種從資料集中高效提取資料,並以適合模型訓練的方式提供資料的工具。其主要功能包括以下幾點:
- 迷你批次處理: 可將大型資料分成較小的批次,讓處理更符合 GPU 記憶體容量。
- 隨機打亂功能: 可隨機打亂資料順序,降低過度擬合的風險。
- 平行處理: 可使用多個執行緒同時載入資料,有效縮短訓練時間。
為什麼需要 DataLoader?
在機器學習中,資料前處理與批次處理是非常常見的任務。如果全靠人工管理,會非常耗時且容易使程式碼變得複雜。使用 DataLoader 可以帶來以下好處:
- 高效率的資料管理: 自動完成批次分割與順序控制。
- 高度自訂化: 可根據任務需求輕鬆實作資料轉換與處理。
- 良好的通用性: 不依賴資料型態或格式,能處理多樣的資料集。
3. Dataset 與 DataLoader 的關係
Dataset 類別的角色
Dataset 類別是 PyTorch 中資料管理的基礎,透過它可以方便地載入與自訂資料集。
Dataset 的主要特點
- 資料儲存: 將資料有效地儲存在記憶體或硬碟中。
- 資料存取功能: 提供以索引方式取得資料的機制。
- 可自訂擴充: 支援使用者自訂資料集的建立方式。
以下是 PyTorch 內建的 Dataset 使用範例:
from torchvision import datasets, transforms
transform = transforms.Compose([transforms.ToTensor()])
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
與 DataLoader 的搭配使用
Dataset 定義的是「資料本身」,而 DataLoader 則是將這些資料送入模型的橋樑。
以下是剛才的 MNIST 資料集搭配 DataLoader 使用的範例:
from torch.utils.data import DataLoader
train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
如上所示,DataLoader 負責從 Dataset 中擷取資料,並以批次方式提供給模型,是一個非常方便的介面。
4. DataLoader 的基本用法
本章將說明 PyTorch 中 DataLoader 的實際使用方式。透過掌握基本語法與設定參數,您可以培養實戰技能。
1. DataLoader 的基本語法
以下是 DataLoader 的基本範例程式碼:
import torch
from torch.utils.data import DataLoader, TensorDataset
# 範例資料
data = torch.randn(100, 10) # 100筆樣本,每筆10個特徵
labels = torch.randint(0, 2, (100,)) # 標籤為 0 或 1
# 使用 TensorDataset 建立資料集
dataset = TensorDataset(data, labels)
# 設定 DataLoader
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
重點說明:
- TensorDataset: 將資料與標籤配對,方便管理。
- batch_size=32: 每批處理32筆資料。
- shuffle=True: 每個 epoch 隨機打亂資料順序,防止模型過度擬合。
2. DataLoader 的主要參數與設定
DataLoader 提供以下常用的重要參數:
參數 | 說明 | 使用範例 |
---|---|---|
batch_size | 每次處理的樣本數。 | batch_size=64 |
shuffle | 是否隨機打亂資料順序,預設為 False。 | shuffle=True |
num_workers | 讀取資料時使用的子程序數量,預設為 0(單執行緒)。 | num_workers=4 |
drop_last | 若最後一個 batch 小於 batch_size,是否捨棄它。 | drop_last=True |
pin_memory | 是否將資料加載到固定記憶體中,加快傳輸到 GPU 的速度。 | pin_memory=True (當使用 GPU 時建議設為 True) |
使用範例:
以下是開啟平行處理與固定記憶體的設定方式:
dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True)
3. 從 DataLoader 取得資料的範例
以下示範如何從 DataLoader 中取出每個 batch 的資料:
for batch_idx, (inputs, targets) in enumerate(dataloader):
print(f"Batch {batch_idx+1}")
print("Inputs:", inputs.shape) # 顯示資料的形狀
print("Targets:", targets.shape) # 顯示標籤的形狀
這段程式碼會逐一處理每個 batch 的資料與標籤。
inputs.shape
: 例如 (32, 10),顯示每個 batch 的資料形狀。targets.shape
: 顯示對應的標籤形狀。
4. 為什麼要隨機打亂資料?
DataLoader 的 shuffle=True
選項會將資料順序隨機排列,具有以下優點:
- 避免偏差學習: 若每次都以相同順序訓練,模型可能會對特定模式過度擬合。
- 提升泛化能力: 隨機化資料順序,有助於模型學習更多樣的特徵。
5. 如何建立自訂 Dataset
在 PyTorch 中,除了使用內建的標準資料集之外,有時我們也需要使用自己準備的資料。這種情況下,我們可以建立自訂 Dataset,並搭配 DataLoader 使用。本節將詳細說明建立自訂 Dataset 的步驟。
1. 需要自訂 Dataset 的情境
以下是您可能需要自訂 Dataset 的幾種常見情況:
- 使用特殊格式的資料: 例如圖片、文字或 CSV 檔案等,非內建資料集格式。
- 想要自動進行資料前處理: 像是資料標準化、篩選或轉換。
- 標籤結構較複雜: 例如多個標籤、或同時包含圖像與文字的複合資料。
2. 自訂 Dataset 的基本結構
建立自訂 Dataset 時,需要繼承 torch.utils.data.Dataset
並實作以下三個方法:
__init__
: 初始化資料集,通常在這裡讀取檔案與進行前處理。__len__
: 回傳資料集中樣本的數量。__getitem__
: 根據索引回傳對應的資料與標籤。
3. 自訂 Dataset 的實作範例
以下是一個讀取 CSV 檔案並建立自訂 Dataset 的範例:
範例:使用 CSV 檔案建立 Dataset
import torch
from torch.utils.data import Dataset
import pandas as pd
class CustomDataset(Dataset):
def __init__(self, csv_file):
# 讀取 CSV 檔
self.data = pd.read_csv(csv_file)
# 分離特徵與標籤
self.features = self.data.iloc[:, :-1].values
self.labels = self.data.iloc[:, -1].values
def __len__(self):
# 回傳樣本數
return len(self.features)
def __getitem__(self, idx):
# 取出指定索引的資料與標籤
sample = torch.tensor(self.features[idx], dtype=torch.float32)
label = torch.tensor(self.labels[idx], dtype=torch.long)
return sample, label
重點說明:
__init__
: 在初始化中讀取 CSV 並分開特徵與標籤。__len__
: 告知 DataLoader 有多少資料可以使用。__getitem__
: 傳回對應索引的資料與標籤,格式為 Tensor。
4. 搭配 DataLoader 使用
以下是將上述自訂 Dataset 搭配 DataLoader 的範例:
# 建立 Dataset 實例
dataset = CustomDataset(csv_file='data.csv')
# 設定 DataLoader
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 資料取得範例
for inputs, labels in dataloader:
print("Inputs:", inputs.shape)
print("Labels:", labels.shape)
重點說明:
- batch_size=32: 每個批次處理 32 筆資料。
- shuffle=True: 在每個 epoch 隨機排列資料順序。
透過上述方法,您可以彈性地管理各種資料格式的自訂資料集。
5. 進階範例:處理圖片資料的 Dataset
以下是一個處理圖片與標籤的自訂 Dataset 範例:
from PIL import Image
import os
class ImageDataset(Dataset):
def __init__(self, image_dir, transform=None):
self.image_dir = image_dir
self.image_files = os.listdir(image_dir)
self.transform = transform
def __len__(self):
return len(self.image_files)
def __getitem__(self, idx):
img_path = os.path.join(self.image_dir, self.image_files[idx])
image = Image.open(img_path)
# 圖片轉換處理
if self.transform:
image = self.transform(image)
# 根據檔名設定標籤(範例為二分類)
label = 1 if 'dog' in img_path else 0
return image, label
重點說明:
- 圖片轉換: 使用
transform
進行 resize、normalize 等處理。 - 標籤產生: 根據圖片檔名進行簡易標籤分類。
6. 進階技巧與最佳實踐
本節將介紹如何進一步活用 PyTorch 的 DataLoader,透過進階技巧提升資料處理效率與彈性,幫助您更專業地應用於實際專案。
1. 使用平行處理加速資料讀取
問題點:
當資料集很大時,單一程序讀取資料會變得非常慢。尤其處理圖片或音訊資料時,讀取過程容易成為瓶頸。
解決方案:
設定 num_workers
參數,讓多個程序同時載入資料,以加速處理。
範例:使用多個程序的 DataLoader
from torch.utils.data import DataLoader
# 設定 DataLoader
dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4)
for batch in dataloader:
# 資料處理
pass
重點說明:
num_workers=4
: 使用 4 個子程序並行讀取資料,可根據系統性能調整。- 注意事項: 若在 Windows 環境中,記得使用
if __name__ == '__main__':
避免多程序錯誤。
2. 最佳化記憶體使用效率
問題點:
當使用 GPU 訓練模型時,若資料從 CPU 傳輸至 GPU 的速度太慢,會影響整體效能。
解決方案:
設定 pin_memory=True
,讓資料載入至固定記憶體,加快資料傳輸速度。
範例:啟用固定記憶體加速傳輸
dataloader = DataLoader(dataset, batch_size=64, shuffle=True, pin_memory=True)
重點:
- 使用 GPU 訓練時特別有效,若只使用 CPU 則不必設定。
3. 使用 Sampler 控制資料選取
問題點:
在資料分布不均(例如分類不平衡)時,單純使用 shuffle 難以控制訓練效果。
解決方案:
使用 Sampler 來自訂資料的抽樣策略。
範例:使用 WeightedRandomSampler 處理不平衡資料
from torch.utils.data import WeightedRandomSampler
# 建立每個樣本的權重(假設 0 類少、1 類多)
weights = [0.1 if label == 0 else 0.9 for label in dataset.labels]
sampler = WeightedRandomSampler(weights, num_samples=len(weights), replacement=True)
# 設定 DataLoader
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
重點:
- 不平衡資料處理: 透過調整樣本出現機率,改善學習表現。
- 自訂抽樣策略: 可根據任務需求,設計條件式的抽樣邏輯。
4. 使用資料擴增技術提高模型準確率
問題點:
當資料集太小時,模型容易過擬合,泛化能力下降。
解決方案:
對圖片或文字進行「資料擴增(Data Augmentation)」以增加資料多樣性。
範例:使用 torchvision.transforms 擴增圖片
from torchvision import transforms
transform = transforms.Compose([
transforms.RandomHorizontalFlip(), # 隨機水平翻轉
transforms.RandomRotation(10), # 隨機旋轉 10 度以內
transforms.ToTensor(), # 轉為 Tensor
transforms.Normalize((0.5,), (0.5,))# 標準化處理
])
重點:
- 資料擴增是防止過擬合、提升泛化能力的重要方法。
- 可搭配自訂 Dataset 彈性應用不同的轉換流程。
5. 處理大型資料集的批次與分散式訓練
問題點:
當資料集龐大時,容易造成記憶體不足或訓練時間過長。
解決方案:
使用「批次處理(Batch Processing)」與「分散式訓練(Distributed Training)」加速訓練。
範例:使用 DistributedSampler 進行分散式訓練
from torch.utils.data.distributed import DistributedSampler
sampler = DistributedSampler(dataset)
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
重點:
- 在多 GPU 或多機系統中,可使用分散式學習平衡計算負載。
- 搭配 Sampler,可有效控制每個訓練節點讀取的資料範圍。
7. 常見錯誤與對應解決方法
雖然 PyTorch 的 DataLoader 十分方便,但在實際使用中仍可能遇到各種錯誤。本節將整理常見的錯誤訊息、可能的原因,以及對應的解決方案。
1. 錯誤一:記憶體不足(Out of Memory)
錯誤訊息:
RuntimeError: CUDA out of memory.
可能原因:
- batch size 設定過大。
- 嘗試一次處理高解析度圖片或龐大的資料集。
- GPU 記憶體未正確釋放。
解決方法:
- 降低 batch size:
dataloader = DataLoader(dataset, batch_size=16, shuffle=True)
- 使用較輕量的模型或資料型別(如半精度):
model.half()
inputs = inputs.half()
- 手動釋放 GPU 記憶體:
import torch
torch.cuda.empty_cache()
- 啟用 pin_memory 以優化資料傳輸:
dataloader = DataLoader(dataset, batch_size=16, shuffle=True, pin_memory=True)
2. 錯誤二:平行處理出錯
錯誤訊息:
RuntimeError: DataLoader worker (pid 12345) is killed by signal: 9
可能原因:
num_workers
設定過高,超過系統資源上限。- 資料加載過重或發生資源衝突。
解決方法:
- 減少
num_workers
數量:
dataloader = DataLoader(dataset, batch_size=32, num_workers=2)
- 將資料切分為多份或分批載入。
- 在 Windows 環境中,加入保護程式碼:
if __name__ == '__main__':
dataloader = DataLoader(dataset, batch_size=32, num_workers=2)
3. 錯誤三:資料格式錯誤
錯誤訊息:
IndexError: list index out of range
可能原因:
__getitem__
嘗試存取不存在的索引。__len__
回傳的長度與實際資料不一致。
解決方法:
- 確認
__len__
是否正確:
def __len__(self):
return len(self.data)
- 在
__getitem__
中加上邊界檢查:
def __getitem__(self, idx):
if idx >= len(self.data):
raise IndexError("Index out of range")
return self.data[idx]
4. 錯誤四:資料型別錯誤(TypeError)
錯誤訊息:
TypeError: default_collate: batch must contain tensors, numpy arrays, numbers, dicts or lists; found <class 'str'>
可能原因:
- 自訂 Dataset 傳回的資料格式不符合 Tensor 格式。
解決方法:
- 將資料轉換為 Tensor:
import torch
def __getitem__(self, idx):
feature = torch.tensor(self.features[idx], dtype=torch.float32)
label = torch.tensor(self.labels[idx], dtype=torch.long)
return feature, label
- 使用自訂的 collate 函數處理非標準格式:
def custom_collate(batch):
inputs, labels = zip(*batch)
return torch.stack(inputs), torch.tensor(labels)
dataloader = DataLoader(dataset, batch_size=32, collate_fn=custom_collate)
5. 錯誤五:隨機性與結果不一致
錯誤訊息:
Randomness in shuffling produces inconsistent results.
可能原因:
- 未設定隨機種子,導致每次執行結果不一致。
解決方法:
- 設定隨機種子(seed)以確保重現性:
import torch
import numpy as np
import random
def seed_everything(seed=42):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
seed_everything(42)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
8. 實作範例:資料前處理與模型訓練的應用
本節將透過實際範例說明如何使用 PyTorch 的 DataLoader 來處理資料並訓練模型。我們將使用經典的 CIFAR-10 圖片分類資料集,示範整個訓練流程。
1. 資料集下載與前處理
首先下載 CIFAR-10 資料集並進行必要的前處理:
import torch
import torchvision
import torchvision.transforms as transforms
# 資料轉換(資料擴增 + 標準化)
transform = transforms.Compose([
transforms.RandomHorizontalFlip(), # 隨機水平翻轉
transforms.RandomCrop(32, padding=4), # 隨機裁切
transforms.ToTensor(), # 轉換為 Tensor
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 標準化處理
])
# 載入訓練與測試資料集
train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
重點說明:
- 資料擴增: 使用隨機翻轉與裁切來增加樣本多樣性。
- 標準化: 將圖片像素值正規化至 -1~1 範圍,加速訓練。
- CIFAR-10: 小型圖片分類資料集,共 10 個分類。
2. 設定 DataLoader
接下來建立 DataLoader,以批次方式讀取資料:
from torch.utils.data import DataLoader
# 設定訓練與測試的 DataLoader
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=4, pin_memory=True)
重點說明:
- batch_size: 每個 batch 處理 64 筆資料。
- shuffle: 訓練資料打亂,測試資料保持原順序。
- num_workers: 使用 4 個執行緒讀取資料。
3. 建立模型
定義一個簡單的卷積神經網路(CNN):
import torch.nn as nn
import torch.nn.functional as F
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.fc1 = nn.Linear(64 * 8 * 8, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2)
x = x.view(-1, 64 * 8 * 8)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
重點說明:
- 卷積層(Conv2d): 提取圖像特徵。
- 池化層(MaxPooling): 降低資料維度與位置敏感度。
- 全連接層(Linear): 用於最終的分類。
4. 模型訓練
使用訓練資料進行模型訓練:
import torch.optim as optim
# 使用 GPU(如可用)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = CNN().to(device)
# 設定損失函數與優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 訓練迴圈
for epoch in range(10):
model.train()
running_loss = 0.0
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {running_loss / len(train_loader)}")
重點說明:
- 裝置設定: 若有 CUDA 裝置,則使用 GPU 加速。
- Adam 優化器: 提供自動學習率調整與快速收斂。
- 交叉熵損失: 適用於分類問題。
5. 模型評估
使用測試資料來評估模型準確率:
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f"Test Accuracy: {100 * correct / total:.2f}%")
重點說明:
- eval 模式: 關閉 dropout 等訓練專用設定。
- 準確率計算: 統計預測正確的比例。

9. 總結與下一步行動
在本教學中,我們從基礎到實戰,全面介紹了 PyTorch 中 DataLoader 的使用方法。最後讓我們一起回顧重點,並提供後續學習的方向。
1. 重點回顧
第1~4章:
- DataLoader 的基礎: 說明 DataLoader 的功能與如何簡化資料管理與前處理流程。
- 與 Dataset 的搭配: 使用內建與自訂 Dataset 的方式靈活整合資料處理流程。
第5~6章:
- 自訂 Dataset 建立方法: 學會處理非標準資料格式(如圖片、CSV等),並提供可執行的範例。
- 進階技巧與最佳實踐: 探討平行處理、記憶體最佳化、資料抽樣與資料擴增等技術。
第7~8章:
- 常見錯誤與排除方式: 提供實際錯誤訊息、原因與對應的修正方案,提升問題處理能力。
- 實作範例: 從 CIFAR-10 圖片分類任務中,完整展示資料載入、模型訓練與評估流程。
2. 實務應用建議
① 嘗試修改並擴充程式碼
本文提供的範例屬於基礎模板,實際開發中情況會更複雜。您可以依照下列建議進行擴充:
- 加入更多資料擴增技術,減少過擬合。
- 使用學習率調整器(scheduler)、正則化(如 Dropout)提高泛化能力。
- 若資料量龐大,考慮使用分散式訓練來提升效率。
② 嘗試不同的資料集
除了 MNIST 和 CIFAR-10,您也可以挑戰以下資料集:
- 圖片分類: ImageNet、COCO。
- 自然語言處理: IMDB、SNLI、TREC 等。
- 語音辨識: Librispeech、Common Voice。
③ 練習調整超參數
DataLoader 中的 batch_size
、num_workers
等參數會直接影響訓練速度與資源使用效率。多嘗試不同組合以找出最適配置。
④ 改變模型架構
除了 CNN,還可嘗試以下常見模型以增進理解:
- RNN / LSTM: 適用於時序資料與語言模型。
- Transformer: 適用於 NLP 任務的高效模型。
- ResNet / EfficientNet: 在圖像分類中表現優異的深度模型。
3. 下一步學習建議
① 善用 PyTorch 官方文件
想進一步掌握 API 細節或了解新功能,建議參考官方文件:
② 動手做實戰專案
將本篇學到的技巧應用在實際專案中,例如:
- 圖片分類應用: 開發一個簡易的 Web App 或行動應用。
- 自然語言處理: 製作情感分析系統或聊天機器人。
- 強化學習: 建立遊戲 AI 或最適化模型。
③ 分享與交流
將您的程式碼發布至 GitHub 或參加 Kaggle 比賽,與其他開發者互相學習並提升實力。
4. 結語
DataLoader 是 PyTorch 中資料處理與訓練效率提升的關鍵工具。本文從基礎觀念、應用實例到錯誤排除,為初學者與中階使用者提供一套完整的學習地圖。
重點總結:
- DataLoader 提供高效的資料管理與模型輸入流程。
- 自訂 Dataset 能處理任何格式的資料集。
- 搭配進階技巧如平行處理、資料擴增、sampler 可大幅提升訓練效率與模型表現。
- 透過實作範例,學會從資料預處理到模型訓練與評估的全流程。
若您正準備踏入 PyTorch 的機器學習與深度學習領域,希望這篇文章能成為您實作與思考的起點。持續學習與實踐,未來將能掌握更複雜的模型設計與應用技巧。