文章目錄
- 1 數據準備
- 2 `Dataset`
- 2.1 自定義 Dataset
- 2.2 使用示例
- 3 `TensorBoard`
- 3.1 安裝
- 3.2 標量可視化(Scalars)
- 3.3 圖像可視化(Images)
- 3.4 其他常用功能
- 4 `transform`
- 4.1 `ToTensor()`
- 4.2 `Normalize()`
- 4.3 `Resize()`
- 4.4 `Compose()`
- 4.5 Crop
- `RandomCrop()`
- `CenterCrop()`
- `RandomResizedCrop()`
- `FiveCrop() / TenCrop()`
- 4.6 `RandomHorizontalFlip() / RandomVerticalFlip()`
- 4.7 Random
- `RandomChoice()`
- `RandomApply()`
- `RandomOrder()`
- 4.8 自定義 transforms
- 4.9 其他
- 5 torchvision 中的數據集
- 5.1 CIFAR10 數據集
- 5.2 數據加載
- 5.3 數據格式
- 5.4 可視化
- 6 `DataLoader`
- 6.1 讀取數據
- 6.2 可視化
本文環境:
- Pycharm 2025.1
- Python 3.12.9
- Pytorch 2.6.0+cu124
1 數據準備
? 數據集放在 dataset 路徑下,其中 train 文件夾存放訓練數據,包括 ants 和 bees,val 文件夾存放測試數據,包括 ants 和 bees。

? 訓練數據為若干個 .jpg 圖片。

- 數據集下載鏈接:https://pan.baidu.com/s/1jZoTmoFzaTLWh4lKBHVbEA;密碼: 5suq。
- 參考教程視頻鏈接:P7. TensorBoard的使用(一)_嗶哩嗶哩_bilibili。
2 Dataset
? Dataset 是抽象類,定義數據來源及單樣本讀取邏輯,所有自定義的 Dataset 均需要繼承它。
? 必須實現的方法:
__getitem__(self, index)
:根據索引返回(樣本, 標簽)。__len__(self)
:返回數據集大小。
2.1 自定義 Dataset
import os
from PIL import Image
from torch.utils.data import Datasetclass MyData(Dataset):def __init__(self, root_dir, label_dir):# 初始化函數,傳入根目錄和標簽目錄self.root_dir = root_dir # 數據集根目錄self.label_dir = label_dir # 標簽目錄(也是類別名)# 拼接完整路徑self.path = os.path.join(self.root_dir, self.label_dir)# 獲取該路徑下所有圖片文件名self.img_path = os.listdir(self.path)def __getitem__(self, index):# 根據索引獲取圖片名img_name = self.img_path[index]# 拼接圖片完整路徑img_item_path = os.path.join(self.path, img_name)# 使用PIL打開圖片img = Image.open(img_item_path)# 標簽就是目錄名(如"ants"或"bees")label = self.label_dirreturn img, label # 返回圖片和標簽def __len__(self):# 返回數據集大小(圖片數量)return len(self.img_path)
__init__()
-
接收兩個參數:
root_dir
(根目錄)和label_dir
(標簽目錄)。 -
使用
os.path.join
拼接完整路徑。 -
os.listdir
獲取該目錄下所有文件名列表。
-
__getitem__()
-
根據索引獲取對應圖片。
-
使用 PIL.Image 打開圖片。
-
標簽直接使用目錄名(簡單示例中)。
-
返回(圖片, 標簽)元組。
-
-
__len__()
-
返回數據集大小(圖片數量)。
-
用于 DataLoader 確定迭代次數。
-
2.2 使用示例
# 定義路徑
root_dir = "dataset/train" # 訓練集根目錄
ants_label_dir = "ants" # 螞蟻圖片目錄
bees_label_dir = "bees" # 蜜蜂圖片目錄# 創建數據集實例
ants_dataset = MyData(root_dir, ants_label_dir)
bees_dataset = MyData(root_dir, bees_label_dir)# 合并數據集(實際應該使用ConcatDataset)
train_dataset = ants_dataset + bees_dataset # 簡單合并
? 示例中直接使用+
合并數據集不是很規范,PyTorch 提供ConcatDataset
類來正確合并多個 Dataset:
from torch.utils.data import ConcatDataset
train_dataset = ConcatDataset([ants_dataset, bees_dataset])
3 TensorBoard
? TensorBoard 是 TensorFlow 提供的可視化工具,PyTorch 通過torch.utils.tensorboard
模塊也支持使用 TensorBoard。它可以幫助我們:
- 監控訓練過程中的指標變化(如損失、準確率)。
- 可視化模型結構。
- 查看圖像、音頻等數據。
- 分析參數分布和直方圖。
3.1 安裝
? 使用以下命令進行安裝:
pip install tensorboard
?
? 基本使用流程如下:
- 創建
SummaryWriter
實例。 - 使用各種
add_*
方法記錄數據。 - 關閉
SummaryWriter。
- 啟動 TensorBoard 服務查看結果。
3.2 標量可視化(Scalars)
add_scalar(tag, scalar_value, global_step)
tag
: 數據標識(圖表標題)。scalar_value
: 要記錄的標量值。global_step
: 訓練步數/迭代次數。
from torch.utils.tensorboard import SummaryWriterwriter = SummaryWriter("logs") # 日志保存到logs目錄for i in range(100):writer.add_scalar("y=2x", 2*i, i) # 記錄y=2x函數值writer.close()
? 上述代碼運行后,在當前目錄下會生成 logs 目錄,里面存放 TensorBoard 的可視化數據。

? 進入 Pycharm 終端,在命令行運行如下命令:
tensorboard --logdir=Pytorch教程/logs --port=6006
- logdir:可視化數據的存儲路徑在哪里。
- port:從哪個端口打開可視化網頁。

? 在瀏覽器訪問http://localhost:6006
即可查看可視化結果。

注意
? 請確保從 cmd 中輸入命令,而不是 Powershell。
? 若出現如下報錯,說明使用 Powershell 打開而不是 cmd。
![]()
解決方案
? 打開 Pycharm 的設置選項,進入“終端”頁面,將默認頁簽更改為 cmd.exe,重新在 Pycharm 中打開終端即可。
![]()
3.3 圖像可視化(Images)
add_image(tag, img_tensor, global_step, dataformats)
-
tag
: 數據標識(圖表標題)。 -
img_tensor
: 圖像數據(numpy 數組或 torch tensor)。 -
global_step
: 訓練步數/迭代次數。 -
dataformats
: 指定數據格式,如 ‘HWC’(高度、寬度、通道)。
from PIL import Image
import numpy as npimg_PIL = Image.open("image.jpg")
img_array = np.array(img_PIL) # 轉換為numpy數組writer.add_image("train", img_array, 1, dataformats='HWC')
? 上述代碼運行后,在可視化網頁中點擊刷新,即可顯示圖像。

3.4 其他常用功能
add_graph()
: 可視化模型結構。add_histogram()
: 記錄參數分布。add_text()
: 記錄文本信息。add_embedding()
: 可視化高維數據降維結果。
4 transform
? torchvision.transforms
是 PyTorch 中用于圖像預處理的強大工具包,提供豐富的圖像轉換操作。主要功能包括:
- 圖像格式轉換(如 PIL Image ? Tensor)。
- 圖像尺寸調整(縮放、裁剪)。
- 數據增強(翻轉、旋轉、顏色變換)。
- 數據標準化。

4.1 ToTensor()

- 將 PIL/Numpy 圖像轉為 PyTorch Tensor。
- 將像素值從 [0, 255] 縮放到 [0.0, 1.0]。
- 調整維度順序為 (C, H, W)。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# ToTensor
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
writer.add_image("Tensor_img", tensor_img)
print(tensor_img) # 輸出形狀為(C, H, W)的tensor,值范圍[0,1]writer.close()

4.2 Normalize()

? 逐 Channel 對圖像進行標準化。
-
mean
:各通道的均值。 -
std
:各通道的標準差。 -
inplace
:是否原地操作。
使用公式:
output = (input - mean) / std
。此處將 [0, 1] 范圍的數據轉換到 [-1, 1] 范圍。
注意:必須先轉換為 Tensor 才能使用 Normalize。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# ToTensor
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)# Normalize
normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
normalize_img = normalize(tensor_img)
writer.add_image("Normalize_img", normalize_img)
print(normalize_img)writer.close()

4.3 Resize()

- 將圖像調整為指定尺寸 (512x512)。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# ToTensor
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)# Resize
resize = transforms.Resize((512, 512))
resize_img = resize(tensor_img)
writer.add_image("Resize_img", resize_img)
print(tensor_img)writer.close()

4.4 Compose()

- 將多個轉換步驟按順序組合。
- 執行順序:先 Resize 再 ToTensor。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# Compose
compose = transforms.Compose([transforms.Resize((512, 512)),transforms.ToTensor()
])
compose_img = compose(img)
writer.add_image("Compose_img", compose_img)
print(compose_img)writer.close()

4.5 Crop
RandomCrop()

? 從圖片中隨機裁剪出尺寸為 size 的圖片。
size
:所需裁剪圖片尺寸。padding
:設置填充大小。- 當為a時,上下左右均填充 a 個像素。
- 當為 (a, b) 時,上下填充 b 個像素,左右填充 a 個像素。
- 當為 (a, b, c, d) 時,左,上,右,下分別填充 a, b, c, d。
pad_if_needed
:若圖像小于設定 size,則填充。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# ToTensor
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)# RandomCrop
random_crop = transforms.RandomCrop((512, 512))
random_crop_img = random_crop(tensor_img)
writer.add_image("RandomCrop_img", random_crop_img)
print(random_crop_img)writer.close()

CenterCrop()

? 從圖像中心裁剪圖片。
? size
:所需裁剪圖片尺寸。
RandomResizedCrop()

? 隨機大小、長寬比裁剪圖片。
size
:所需裁剪圖片尺寸。scale
:隨機裁剪面積比例,默認 (0.08, 1)。ratio
:隨機長寬比,默認(3/4, 4/3)。interpolation
:插值方法。- PIL.Image.NEAREST。
- PIL.Image.BILINEAR。
- PIL.Image.BICUBIC。
FiveCrop() / TenCrop()


? FiveCrop 在圖像的上下左右以及中心裁剪出尺寸為 size 的 5 張圖片;
? TenCrop 對這 5 張圖片進行水平或者垂直鏡像獲得 10 張圖片.
size
:所需裁剪圖片尺寸。vertical_flip
:是否垂直翻轉。
4.6 RandomHorizontalFlip() / RandomVerticalFlip()

? 依概率水平(左右)或垂直(上下)翻轉圖片。
p
:翻轉概率。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformswriter = SummaryWriter("logs")
img = Image.open("image/pytorch.png")
print(img)# ToTensor
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)# RandomHorizontalFlip
random_flip = transforms.RandomHorizontalFlip(1)
random_flip_img = random_flip(tensor_img)
writer.add_image("RandomFlip_img", random_flip_img)
print(random_flip_img)writer.close()

4.7 Random
RandomChoice()
? 從一系列 transforms 方法中隨機挑選一個。
transforms.RandomChoice([transforms1, transforms2, transforms3])
RandomApply()
? 依據概率執行一組 transforms 操作。
transforms.RandomApply([transforms1, transforms2, transforms3], p=0.5)
RandomOrder()
? 對一組 transforms 操作打亂順序。
transforms.RandomOrder([transforms1, transforms2, transforms3])
4.8 自定義 transforms
? 自定義 transforms 要素:
__init__()
:初始化方法。__call__
:執行方法。
class YourTransforms(object):def __init__(self, ...):...def __call__(self, img):...return img
以 RandomChoice
為例:

注意
- 僅接收一個參數,返回一個參數。
- 注意上下游的輸出與輸入。
4.9 其他
-
Pad()
:對圖片邊緣進行填充。 -
ColorJitter()
:調整亮度、對比度、飽和度和色相。 -
Grayscale() / RandomGrayscale()
:依概率將圖片轉換為灰度圖。 -
RandomAffine()
:對圖像進行仿射變換。仿射變換是二維的線性變換,由五種基本原子變換構成,分別是旋轉、平移、縮放、錯切和翻轉。
-
RandomErasing()
:對圖像進行隨機遮擋。 -
Lambda()
:用戶自定義 Lambda 方法。
5 torchvision 中的數據集
? 官方文檔:Datasets — Torchvision 0.22 documentation。

5.1 CIFAR10 數據集
? 以 CIFAR10 為例:CIFAR10 — Torchvision 0.22 documentation。打開文檔鏈接,以下是 CIFAR10 的創建方法。

? 進入主頁,可觀看數據集詳細介紹。

-
包含 60,000 張 32×32 像素的 RGB 彩色圖像,分為 10 個類別(飛機、汽車、鳥、貓、鹿、狗、青蛙、馬、船、卡車),每類 6,000 張。
-
訓練集
50,000 張圖像,分為 5 個批次(data_batch_1 至 data_batch_5),每批 10,000 張。每個類別在訓練集中共 5,000 張圖像,但單個批次內類別分布可能不均勻。
-
測試集
10,000 張圖像(test_batch),每個類別均勻包含 1,000 張隨機選擇的圖像,且與訓練集無重疊。
-
-
類別間完全互斥,例如“汽車”與“卡車”不重疊(汽車含轎車 / SUV,卡車僅含大型貨車)。
5.2 數據加載
-
torchvision.datasets.CIFAR10
PyTorch 內置的 CIFAR-10 數據集加載接口。
root='./dataset'
:數據集存儲路徑(若不存在會自動創建)。train=True/False
:分別加載訓練集(50,000 張)或測試集(10,000 張)。transform=None
:接收 PIL 圖像并返回轉換后的版本的函數/轉換。target_transform=None
:接收目標并對其進行轉換的函數/轉換。download=True
:自動下載數據集(若本地不存在)。
import torchvision# 定義數據集的轉換方式
dataset_transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor(),
])# 加載訓練集
train_set = torchvision.datasets.CIFAR10(root='./dataset', # 數據集的根目錄train=True, # 是否為訓練集transform=dataset_transform, # 數據集的轉換方式download=True # 是否下載數據集
)
# 加載測試集
test_set = torchvision.datasets.CIFAR10(root='./dataset', # 數據集的根目錄train=False, # 是否為訓練集transform=dataset_transform, # 數據集的轉換方式download=True # 是否下載數據集
)
5.3 數據格式
-
未啟用
transform
時test_set[0]
返回 PIL.Image 對象和標簽(整數)。# 打印測試集的第一個樣本 print(test_set[0])# 獲取測試集的第一個樣本的圖像和標簽 img, target = test_set[0] # 打印圖像 print(img) # 打印標簽 print(target)
-
啟用
transform=ToTensor()
后圖像轉為 Tensor 格式(形狀為 [3, 32, 32],值域 [0, 1])。
# 獲取測試集的第一個樣本的圖像和標簽 img, target = test_set[0] # 打印圖像 print(img.shape) # 打印標簽 print(target)
-
test_set.classes
:直接輸出 10 個類別的名稱列表。# 打印測試集的類別 print(test_set.classes)
5.4 可視化
# 創建一個SummaryWriter對象,用于記錄訓練過程中的數據
writer = SummaryWriter("logs")# 遍歷測試集
for i in range(10):# 獲取測試集中的第i個樣本img, target = test_set[i]# 將第i個樣本的圖像添加到SummaryWriter中writer.add_image("test_set", img, i)writer.close()

6 DataLoader

? 功能:構建可迭代的數據裝載器。
? 常用參數:
dataset
:Dataset 類,決定數據從哪讀取及如何讀取。batch_size
:批大小。shuffle
:每個 Epoch 是否亂序。num_workers
:是否多進程讀取數據,0 表示使用主線程讀取。drop_last
:當樣本數不能被batch_size
整除時,是否舍棄最后一批數據。
Epoch:所有訓練樣本都已輸入到模型中,稱為一個 Epoch。
Iteration:一批樣本輸入到模型中,稱之為一個 Iteration。
Batchsize:批大小,決定一個 Epoch 有多少個 Iteration。
樣本總數:80,Batchsize:8
- 1 Epoch 10 Iteration
樣本總數:87,Batchsize:8
- drop_last = True:1 Epoch = 10 Iteration
- drop_last = False:1 Epoch = 11 Iteration
? 其他參數
sampler
:自定義采樣策略(如按權重采樣,與shuffle
互斥)。batch_sampler
:直接生成批次索引(與batch_size
/shuffle
/sampler
互斥)。collate_fn
:自定義批次合并邏輯(處理非規則數據,如變長序列)。pin_memory
:是否將數據復制到 CUDA 固定內存(加速 GPU 數據傳輸)。timeout
:從 worker 收集數據的超時時間(秒,0
=無超時)。worker_init_fn
:每個 worker 的初始化函數(常用于設置隨機種子)。multiprocessing_context
:多進程上下文(如'spawn'
/'fork'
,影響進程啟動方式)。generator
:控制隨機采樣的隨機數生成器(RNG)。prefetch_factor
:每個 worker 預加載的批次數量(默認2
,僅num_workers>0
生效)。persistent_workers
:是否保持 worker 進程存活(避免重復初始化開銷)。pin_memory_device
:指定固定內存的設備(如'cuda:0'
)。in_order
:是否強制按 FIFO 順序返回批次(num_workers>0
時生效)。
6.1 讀取數據
? 以 CIFAR10 測試集為例,共包含 10000 個樣本。
import torchvision
from torch.utils.data import DataLoader# 加載CIFAR10測試數據集
test_data = torchvision.datasets.CIFAR10(root='./dataset', # 數據集的根目錄train=False, # 是否為訓練集transform=torchvision.transforms.ToTensor(), # 數據預處理
)
? 設置batch_size=4
,即每次讀取 4 個樣本,并且drop_last=False
。
# 創建數據加載器
test_loader = DataLoader(dataset=test_data, # 數據集batch_size=4, # 每個batch的大小shuffle=True, # 是否打亂數據num_workers=0, # 加載數據的線程數drop_last=False # 是否丟棄最后一個batch
)
? 遍歷 test_loader 以獲得每批次的數據,
i = 0
# 遍歷test_loader中的數據
for data in test_loader:i += 1imgs, targets = data # 獲取每批次的數據與標簽print(i, " ", imgs.shape)print(targets)

- 數據集一共 10000 個樣本,每批次取出 4 個,因此序號為 10000 / 4 = 2500。
- 每個批次的張量形狀為 torch.Size([4, 3, 32, 32]),是 4 個 torch.Size([3, 32, 32]) 的組合。
- targets 為包含 4 個元素的列表,每個元素表示對應位置的數據標簽。
6.2 可視化
? 設置batch_size=64
,并且drop_last=False
。
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter# 加載CIFAR10測試數據集
test_data = torchvision.datasets.CIFAR10(root='./dataset', # 數據集的根目錄train=False, # 是否為訓練集transform=torchvision.transforms.ToTensor(), # 數據預處理
)# 創建數據加載器
test_loader = DataLoader(dataset=test_data, # 數據集batch_size=64, # 每個batch的大小shuffle=True, # 是否打亂數據num_workers=0, # 加載數據的線程數drop_last=False # 是否丟棄最后一個batch
)
? 使用 tensorboard 可視化每個批次。
writer = SummaryWriter('logs')step = 0
# 遍歷test_loader中的數據
for data in test_loader:# 獲取每批次的數據與標簽imgs, targets = data# 將imgs寫入tensorboardwriter.add_images('test_data', imgs, step)step += 1writer.close()
? 拖動滑動條,可看見第 32 step 的批次圖像如下。

? 將滑動條拖動到最右側,發現該批次只剩余 16 張圖像,因為 10000 % 64 = 16。
