做視頻剪輯接私活的網(wǎng)站軟文擬發(fā)布的平臺與板塊
1.數(shù)據(jù)加載
1.1 讀取文本文件
- 方法一:使用 open() 函數(shù)和 read() 方法
# 打開文件并讀取全部內(nèi)容
file_path = 'example.txt' # 替換為你的文件路徑
with open(file_path, 'r') as file:content = file.read()print(content)
- 方法二:逐行讀取文件內(nèi)容
# 逐行讀取文件內(nèi)容
file_path = 'example.txt' # 替換為你的文件路徑
with open(file_path, 'r') as file:for line in file:print(line.strip()) # strip() 方法用于去除行末尾的換行符
- 方法三:指定編碼讀取文件內(nèi)容(如果文本文件不是UTF-8編碼)
# 指定編碼讀取文件內(nèi)容
file_path = 'example.txt' # 替換為你的文件路徑
with open(file_path, 'r', encoding='utf-8') as file:content = file.read()print(content)
- 方法四:一次讀取多行內(nèi)容
# 一次讀取多行內(nèi)容
file_path = 'example.txt' # 替換為你的文件路徑
with open(file_path, 'r') as file:lines = file.readlines()for line in lines:print(line.strip()) # strip() 方法用于去除行末尾的換行符
1.2 讀取圖片
- 使用Pillow(PIL)庫
安裝了Pillow庫:pip install Pillow
from PIL import Image# 打開圖片文件
img = Image.open('example.jpg') # 替換成你的圖片文件路徑# 顯示圖片信息
print("圖片格式:", img.format)
print("圖片大小:", img.size)
print("圖片模式:", img.mode)# 顯示圖片
img.show()# 轉(zhuǎn)換為numpy數(shù)組(如果需要在其他庫中處理圖像)
import numpy as np
img_array = np.array(img)
- 使用OpenCV庫
安裝OpenCV庫:pip install opencv-python
import cv2# 讀取圖片
img = cv2.imread('example.jpg') # 替換成你的圖片文件路徑# 顯示圖片信息
print("圖片尺寸:", img.shape) # 高度、寬度、通道數(shù)(rgb默認是3)
print("像素值范圍:", img.dtype) # 數(shù)據(jù)類型(像素值類型)# 可選:顯示圖片(OpenCV中顯示圖像的方法)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()# 可選:將BGR格式轉(zhuǎn)換為RGB格式
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 可選:保存圖片
cv2.imwrite('output.jpg', img)
- 應用
# 繼承Dataset類
class MyData(Dataset):# 初始化def __init__(self, root_dir, image_dir, label_dir):# root_dir 訓練目錄地址self.root_dir = root_dir# 圖片地址self.image_dir = image_dir# label_dir 標簽地址self.label_dir = label_dir# 訓練樣本地址self.path = os.path.join(self.root_dir, self.image_dir)# 將所有樣本地址(名稱)變成一個列表self.img_path = os.listdir(self.path)# 讀取圖片,并且對應label# idx 圖片下標def __getitem__(self, idx):# 圖片名稱img_name = self.img_path[idx]# 圖片路徑img_item_path = os.path.join(self.path, img_name)# 獲取圖片img = Image.open(img_item_path)# 打開文件并讀取全部內(nèi)容(文件存取對應樣本的標簽)file_path = os.path.join(self.root_dir, self.label_dir, img_name.split('.jpg')[0])with open(file_path + ".txt", 'r') as file:label = file.read()# 獲取標簽return img, label# 訓練樣本長度def __len__(self):return len(self.img_path)root_dir = "hymenoptera_data/train"
ants_image_dir = "ants_image"
ants_label_dir = "ants_label"
bees_image_dir = "bees_image"
bees_label_dir = "bees_label"
ants_dataset = MyData(root_dir, ants_image_dir, ants_label_dir)
img, label = ants_dataset[0] # 返回數(shù)據(jù)集第一個樣本的圖片和標簽
img.show() # 展示圖片
bees_dataset = MyData(root_dir, bees_image_dir, bees_label_dir)
import cv2
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from PIL import Imageimg_path = "dataset/train/ants_image/0013035.jpg"
# 打開圖片
img = Image.open(img_path)# 利用cv2打開圖片,直接是ndarray格式
img_cv2 = cv2.imread(img_path)print(img_cv2)write = SummaryWriter('logs')# 創(chuàng)建一個ToTensor的對象(PIL Image or ndarray to tensor)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
print(tensor_img)
1.3 數(shù)據(jù)可視化(TensorBoard)
SummaryWriter 是 TensorBoard 的日志編寫器,用于創(chuàng)建可視化和跟蹤模型訓練過程中的指標和結(jié)果。它通常用于記錄模型的訓練損失、準確率、權(quán)重分布、梯度分布等信息,方便后續(xù)在 TensorBoard 中進行可視化分析。
import torch
from torch.utils.tensorboard import SummaryWriter# 創(chuàng)建一個 SummaryWriter 對象,指定保存日志的路徑
writer = SummaryWriter('logs')# 示例:記錄模型的訓練過程中的損失值和準確率
for step in range(100):# 模擬訓練過程中的損失值和準確率loss = 0.4 * (100 - step) + torch.rand(1).item()accuracy = 0.6 * (step / 100) + torch.rand(1).item()# 將損失值和準確率寫入日志writer.add_scalar('Loss/train', loss, step)writer.add_scalar('Accuracy/train', accuracy, step)# 關(guān)閉 SummaryWriter
writer.close()
首先,我們導入了需要的庫,包括 PyTorch 和 SummaryWriter。
然后,創(chuàng)建了一個 SummaryWriter 對象,并指定了保存日志的路徑 ‘logs’。
在模擬的訓練過程中,我們循環(huán)了 100 步,每一步模擬生成一個損失值和準確率。
使用 writer.add_scalar 方法將每一步的損失值和準確率寫入日志。這些信息將被保存在指定的日志路徑中,以便后續(xù)在 TensorBoard 中進行查看和分析。
最后,使用 writer.close() 關(guān)閉 SummaryWriter,確保日志寫入完成并正確保存。
- SummaryWriter 對象的 add_scalar 方法用于向 TensorBoard 日志中添加標量數(shù)據(jù),例如損失值、準確率等。這些標量數(shù)據(jù)通常用于跟蹤模型訓練過程中的指標變化。
add_scalar 方法的參數(shù)說明:
add_scalar(tag, scalar_value, global_step=None, walltime=None)
tag (str):用于標識數(shù)據(jù)的名稱,將作為 TensorBoard 中的圖表的名稱顯示。
scalar_value (float):要記錄的標量數(shù)據(jù),通常是一個數(shù)值。
global_step (int, optional):可選參數(shù),表示記錄數(shù)據(jù)的全局步驟數(shù)。主要用于繪制圖表時在 x 軸上顯示步驟數(shù),方便對訓練過程進行時間序列分析。
walltime (float, optional):可選參數(shù),表示記錄數(shù)據(jù)的時間戳。默認情況下,使用當前時間戳。
- add_image 函數(shù)用于向 TensorBoard 日志中添加圖像數(shù)據(jù),這對于監(jiān)視模型輸入、輸出或中間層的可視化非常有用。
add_image 方法的參數(shù)說明:
add_image(tag, img_tensor, global_step=None, walltime=None, dataformats='CHW')
tag (str):用于標識圖像的名稱,將作為 TensorBoard 中圖像的名稱顯示。
img_tensor (Tensor or numpy.array):要記錄的圖像數(shù)據(jù),可以是 PyTorch 的 Tensor 對象或者 numpy 數(shù)組。如果是 numpy 數(shù)組,會自動轉(zhuǎn)換為 Tensor。
global_step (int, optional):可選參數(shù),表示記錄數(shù)據(jù)的全局步驟數(shù)。主要用于在 TensorBoard 中按時間顯示圖像。
walltime (float, optional):可選參數(shù),表示記錄數(shù)據(jù)的時間戳。默認情況下,使用當前時間戳。
dataformats (str, optional):可選參數(shù),指定圖像的數(shù)據(jù)格式。默認為 ‘CHW’,即通道-高度-寬度的順序。
啟動命令:tensorboard --logdir 文件路徑
1.4 Transforms
transforms.py 文件通常是指用于進行數(shù)據(jù)預處理和數(shù)據(jù)增強的模塊。這個模塊通常用于處理圖像數(shù)據(jù),包括但不限于加載、轉(zhuǎn)換、裁剪、標準化等操作,以便將數(shù)據(jù)準備好用于模型的訓練或評估。
常見的 transforms.py 功能包括:
- 數(shù)據(jù)加載和預處理:
讀取圖像數(shù)據(jù)并轉(zhuǎn)換為 PyTorch 的 Tensor 格式。
對圖像進行大小調(diào)整、裁剪、旋轉(zhuǎn)、鏡像翻轉(zhuǎn)等操作。
將圖像數(shù)據(jù)標準化為特定的均值和標準差。 - 數(shù)據(jù)增強:
隨機裁剪和大小調(diào)整,以增加訓練數(shù)據(jù)的多樣性。
隨機水平或垂直翻轉(zhuǎn)圖像。
添加噪聲或扭曲以增加數(shù)據(jù)的多樣性。 - 轉(zhuǎn)換為 Tensor:
將 PIL 圖像或 numpy 數(shù)組轉(zhuǎn)換為 PyTorch 的 Tensor 格式。
對圖像數(shù)據(jù)進行歸一化,例如將像素值縮放到 [0, 1] 或 [-1, 1] 之間。 - 組合多個轉(zhuǎn)換操作:
將多個轉(zhuǎn)換操作組合成一個流水線,可以順序應用到圖像數(shù)據(jù)上。 - 實時數(shù)據(jù)增強:
在每次訓練迭代中實時生成增強后的數(shù)據(jù),而不是預先對所有數(shù)據(jù)進行轉(zhuǎn)換。
import torch
from torchvision import transforms
from PIL import Image# 示例圖像路徑
img_path = 'example.jpg'# 定義數(shù)據(jù)轉(zhuǎn)換
data_transform = transforms.Compose([transforms.Resize((256, 256)), # 調(diào)整圖像大小為 256x256 像素transforms.RandomCrop(224), # 隨機裁剪為 224x224 像素transforms.RandomHorizontalFlip(), # 隨機水平翻轉(zhuǎn)圖像transforms.ToTensor(), # 將圖像轉(zhuǎn)換為 Tensor,并歸一化至 [0, 1]transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 標準化
])# 加載并預處理圖像
img = Image.open(img_path)
img_transformed = data_transform(img)# 打印轉(zhuǎn)換后的圖像形狀和數(shù)據(jù)類型
print("Transformed image shape:", img_transformed.shape)
print("Transformed image data type:", img_transformed.dtype)
1.首先,導入了必要的庫和模塊,包括 PyTorch 的 transforms 模塊、PIL 庫中的 Image。
定義了一個 transforms.Compose 對象 data_transform,它是一個包含多個轉(zhuǎn)換操作的列表,按順序應用到輸入數(shù)據(jù)上。
2.示例中的轉(zhuǎn)換操作包括將圖像調(diào)整為指定大小、隨機裁剪為 224x224 像素、隨機水平翻轉(zhuǎn)、轉(zhuǎn)換為 PyTorch 的 Tensor 對象,并進行歸一化。
3.加載示例圖像,并將 data_transform 應用到圖像上,得到轉(zhuǎn)換后的圖像數(shù)據(jù) img_transformed。
4.最后,打印轉(zhuǎn)換后的圖像形狀和數(shù)據(jù)類型,以確保轉(zhuǎn)換操作正確應用。
transforms.Normalize(mean, std, inplace=False)
Normalize 類用于對圖像數(shù)據(jù)進行標準化操作。標準化是一種常見的數(shù)據(jù)預處理步驟,通常用于將數(shù)據(jù)縮放到一個較小的范圍,以便于模型訓練的穩(wěn)定性和收斂速度。在圖像處理中,Normalize 類主要用于將圖像的每個通道進行均值和標準差的歸一化處理
- mean:用于歸一化的均值。可以是一個列表或元組,每個元素分別對應于圖像的每個通道的均值。例如 [mean_channel1, mean_channel2, mean_channel3]。
- std:用于歸一化的標準差。同樣是一個列表或元組,每個元素對應于圖像的每個通道的標準差。例如 [std_channel1, std_channel2, std_channel3]。
- inplace:是否原地操作。默認為 False,表示會返回一個新的標準化后的圖像。如果設(shè)置為 True,則會直接修改輸入的 Tensor。
Compose類
transforms.Compose(transforms)
transforms:一個由 torchvision.transforms 中的轉(zhuǎn)換操作組成的列表或序列,每個操作會依次應用到輸入數(shù)據(jù)上。
1.5 torchvision.datasets
PyTorch 中用于加載和處理常見視覺數(shù)據(jù)集的模塊。這個模塊提供了對多種經(jīng)典數(shù)據(jù)集的訪問接口,包括圖像分類、物體檢測、語義分割等任務常用的數(shù)據(jù)集。
- 數(shù)據(jù)集加載:
torchvision.datasets 提供了方便的接口,可以直接從互聯(lián)網(wǎng)下載和加載常用的數(shù)據(jù)集,例如 MNIST、CIFAR-10、ImageNet 等。 - 數(shù)據(jù)預處理:
支持在加載數(shù)據(jù)集時進行數(shù)據(jù)預處理,例如圖像大小調(diào)整、裁剪、翻轉(zhuǎn)、歸一化等操作,這些操作可以通過 transforms 模塊進行定義和組合。 - 數(shù)據(jù)集管理:
提供了便捷的方法來管理和訪問數(shù)據(jù)集,例如對數(shù)據(jù)集進行隨機訪問、按照批次加載數(shù)據(jù)等,以支持機器學習模型的訓練和評估。 - 多樣的數(shù)據(jù)集支持:
支持多種類型的數(shù)據(jù)集,包括但不限于分類數(shù)據(jù)集(如 MNIST、CIFAR-10)、檢測數(shù)據(jù)集(如 COCO)、語義分割數(shù)據(jù)集(如 Pascal VOC)等,適用于不同的視覺任務。
# 以CIFAR-10為例
import torchvision.transforms as transforms
import torchvision.datasets as datasets# 定義數(shù)據(jù)預處理
transform = transforms.Compose([transforms.Resize(224),transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])# 加載數(shù)據(jù)集
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)# 獲取數(shù)據(jù)集中的樣本數(shù)量
print("Training dataset size:", len(train_dataset))
print("Test dataset size:", len(test_dataset))# 使用 DataLoader 加載數(shù)據(jù)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
使用 datasets.CIFAR10 加載 CIFAR-10 數(shù)據(jù)集
指定了數(shù)據(jù)集存儲的根目錄 root、是否為訓練集 train=True、是否下載數(shù)據(jù)集 download=True、以及預處理管道 transform。
datasets.CIFAR10 返回一個 torch.utils.data.Dataset 對象,可以像常規(guī) Python 的列表一樣進行索引和切片操作。
1.6 DataLoader
DataLoader 是 PyTorch 中用于批量加載數(shù)據(jù)的重要工具
- 數(shù)據(jù)加載:
DataLoader 可以加載 Dataset 對象中的數(shù)據(jù),并將其組織成小批量。這些數(shù)據(jù)可以是圖像、文本、數(shù)值數(shù)據(jù)等。 - 批量處理:
DataLoader 支持對數(shù)據(jù)進行批處理,即一次性加載和處理多個樣本。這樣可以提高訓練效率,尤其是在 GPU 計算的情況下。 - 數(shù)據(jù)打亂:
通過設(shè)置 shuffle=True 參數(shù),DataLoader 可以在每個 epoch 開始時對數(shù)據(jù)進行打亂,這有助于增加數(shù)據(jù)的隨機性,防止模型陷入局部極值。 - 多進程加載:
DataLoader 支持使用多個子進程來并行加載數(shù)據(jù),這可以顯著提升數(shù)據(jù)加載速度,特別是在數(shù)據(jù)集很大時。 - 數(shù)據(jù)采樣:
可以使用 sampler 參數(shù)來指定數(shù)據(jù)的采樣方法,例如隨機采樣、順序采樣等。默認情況下,使用的是 SequentialSampler,即順序采樣。 - 數(shù)據(jù)批處理方式:
可以設(shè)置 batch_size 參數(shù)指定每個小批量的樣本數(shù)目。 - 自定義數(shù)據(jù)加載:
可以通過設(shè)置 collate_fn 參數(shù)來指定如何將樣本數(shù)據(jù)拼接成小批量,通常情況下,PyTorch 提供了默認的拼接方式,但是有時候用戶可能需要根據(jù)自己的需求來自定義拼接過程。 - 數(shù)據(jù)傳輸?shù)?GPU:
當數(shù)據(jù)加載到 DataLoader 后,可以方便地將其傳輸?shù)?GPU 上進行計算,這樣可以利用 GPU 的并行計算能力加速模型訓練。
dataset:
這是必需的參數(shù),指定要加載的數(shù)據(jù)集 Dataset 對象。
batch_size:
指定每個小批量包含的樣本數(shù)目。例如,batch_size=64 表示每個小批量包含 64 個樣本。訓練時常用的批量大小通常是 2 的冪次方,以便能夠充分利用 GPU 的并行計算能力。
shuffle:
設(shè)置為 True 表示每個 epoch 開始時都會對數(shù)據(jù)進行重新打亂(隨機采樣)。這樣可以增加數(shù)據(jù)的隨機性,有助于模型更好地學習數(shù)據(jù)的分布,避免模型陷入局部極值。
sampler:
可選參數(shù),用于指定數(shù)據(jù)采樣策略。默認情況下,如果不指定這個參數(shù),將使用 SequentialSampler,即順序采樣。也可以自定義 Sampler 對象,實現(xiàn)自定義的采樣邏輯。
batch_sampler:
可選參數(shù),如果指定了這個參數(shù),則會覆蓋 batch_size 和 shuffle 參數(shù)。它
num_workers:
表示用于數(shù)據(jù)加載的子進程數(shù)目??梢酝ㄟ^增加子進程數(shù)來加速數(shù)據(jù)加載,特別是當主機有多個 CPU 核心時。通常建議設(shè)置為 num_workers > 0
collate_fn:
可選參數(shù),用于指定如何將樣本列表拼接成小批量。默認情況下,PyTorch 使用 default_collate 函數(shù)來執(zhí)行標準的張量拼接操作。
pin_memory:
如果設(shè)置為 True,則會將加載的數(shù)據(jù)存儲在 CUDA 固定內(nèi)存中,這樣可以加速數(shù)據(jù)傳輸?shù)?GPU。在使用 GPU 訓練模型時,建議設(shè)置為 True。
drop_last:
如果數(shù)據(jù)集的樣本總數(shù)不能被 batch_size 整除,設(shè)置為 True 將會丟棄最后一個不完整的批次。如果設(shè)置為 False,則最后一個批次的樣本數(shù)目可能會少于 batch_size。
import torch
from torch.utils.data import Dataset, DataLoader# 定義一個簡單的數(shù)據(jù)集類
class MyDataset(Dataset):def __init__(self):self.data = torch.randn(100, 3, 32, 32) # 假設(shè)有 100 個大小為 3x32x32 的張量數(shù)據(jù)def __len__(self):return len(self.data)def __getitem__(self, idx):return self.data[idx]# 創(chuàng)建數(shù)據(jù)集實例
dataset = MyDataset()# 創(chuàng)建 DataLoader 實例
batch_size = 16
train_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)# 迭代數(shù)據(jù)集
for batch_idx, batch_data in enumerate(train_loader):inputs = batch_data # 輸入數(shù)據(jù)targets = batch_data # 如果有標簽,也可以在此處獲取# 在這里添加訓練代碼...
在上述示例中,首先定義了一個簡單的數(shù)據(jù)集類 MyDataset,它生成了包含 100 個大小為 3x32x32 的張量數(shù)據(jù)。然后,通過 DataLoader 將這個數(shù)據(jù)集加載為 train_loader,并設(shè)置了批量大小為 16,并且打亂了數(shù)據(jù)順序。最后,在迭代 train_loader 中的小批量數(shù)據(jù)時,可以獲取到每個小批量的輸入數(shù)據(jù) inputs,并在訓練過程中使用。
2.構(gòu)建模型
神經(jīng)網(wǎng)絡(luò)輸入和輸出參數(shù)數(shù)據(jù)格式:
輸入輸出的張量,通常是一個四維張量,形狀為 (N, C, H, W),其中:
N 表示批處理大小(batch size),
C 表示輸入輸出通道數(shù)(input channels),
H 表示輸入輸出的高度(input height),
W 表示輸入輸出的寬度(input width)。
2.1 nn.Module
PyTorch 中的一個核心類,用于構(gòu)建神經(jīng)網(wǎng)絡(luò)模型。
-
模型組件封裝:
nn.Module 是所有神經(jīng)網(wǎng)絡(luò)模型的基類,可以通過繼承它來定義自己的神經(jīng)網(wǎng)絡(luò)模型。
它提供了模型組件的封裝和管理機制,使得模型的構(gòu)建和維護更加清晰和結(jié)構(gòu)化。 -
參數(shù)管理:
模型內(nèi)部的所有參數(shù)(權(quán)重和偏置)都由 nn.Module 對象管理。
通過模型的 parameters() 方法可以輕松地訪問和管理所有模型參數(shù),便于參數(shù)初始化、優(yōu)化器更新等操作。 -
前向傳播定義:
模型的前向傳播邏輯都在 forward() 方法中定義。
重寫 forward() 方法可以定義模型的計算圖,指定輸入數(shù)據(jù)如何通過各個層進行前向傳播,從而計算出輸出。 -
反向傳播支持:
nn.Module 支持自動求導功能,因此可以利用 PyTorch 提供的自動求導機制進行反向傳播和梯度計算。
這使得模型的訓練過程可以高效地優(yōu)化模型參數(shù)。 -
子模塊管理:
nn.Module 支持將多個子模塊組合成一個大模型。
通過在 init 方法中初始化其他 nn.Module 的子類對象,可以構(gòu)建復雜的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),實現(xiàn)模塊化設(shè)計。 -
狀態(tài)管理:
nn.Module 不僅管理模型參數(shù),還負責管理模型的狀態(tài)(如 train() 和 eval() 方法控制模型的訓練和評估狀態(tài))。
這些狀態(tài)管理方法在模型訓練、驗證和測試時非常有用。 -
設(shè)備適配:
通過 to() 方法,nn.Module 支持簡單地將模型移動到 GPU 或者其他計算設(shè)備上進行加速計算,提高訓練和推理的效率。
class MyModule(nn.Module):def __init__(self):super().__init__()def forward(self, input):output = input + 1return outputmymodule = MyModule()
x = torch.tensor(1.0)
y = mymodule(x)
print(y)
2.2 nn.Conv2d
PyTorch 中用于定義二維卷積層的類。它是 nn.Module 的子類,用于構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)中的卷積操作。
卷積原理
參數(shù)介紹:
nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
in_channels:
表示輸入的通道數(shù),對于灰度圖像,通道數(shù)為 1;對于彩色圖像,通道數(shù)為 3(分別是紅、綠、藍)。
out_channels:(每個卷積核生成一個特征圖作為輸出)
表示輸出的通道數(shù),也就是卷積核的數(shù)量,每個卷積核生成一個特征圖作為輸出。通常情況下,輸出通道數(shù)決定了下一層的輸入通道數(shù)。
kernel_size:
卷積核的大小,可以是一個整數(shù)或者一個元組(如 (3, 3))。整數(shù)表示正方形卷積核的邊長,元組則表示非正方形卷積核的形狀。
stride:
卷積操作的步幅,即卷積核在輸入上滑動的步長??梢允且粋€整數(shù)或者一個元組。默認為 1,表示卷積核每次滑動一個像素;
可以設(shè)定為大于 1 的整數(shù),以減少輸出特征圖的尺寸。
padding:
輸入的每一條邊補充 0 的層數(shù)??梢允且粋€整數(shù)或一個元組。添加 padding 可以幫助保持特征圖大小,避免在卷積過程中信息損失過多。
dilation:
空洞卷積的擴展因子,控制卷積核元素之間的間距。默認為 1,表示卷積核內(nèi)的每個元素之間都是連續(xù)的;
大于 1 的值將導致空洞卷積,可以增加感受野。
groups:
輸入和輸出之間連接的組數(shù)。默認為 1,表示所有輸入通道和輸出通道之間都有連接;可以設(shè)置為其他值,以實現(xiàn)分組卷積操作。
bias:
是否添加偏置。默認為 True,表示在卷積后加上偏置項;如果設(shè)置為 False,則卷積層不會有額外的偏置。
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterclass MyConv2d(nn.Module):def __init__(self):super(MyConv2d, self).__init__()# 定義卷積層self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)def forward(self, x):outputs = self.conv1(x)return outputstest_data = torchvision.datasets.CIFAR10(root='./dataset', train=False, transform=torchvision.transforms.ToTensor(),download=True)
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)
write = SummaryWriter(log_dir='./logs')my_conv = MyConv2d()step = 1
# 遍歷數(shù)據(jù)
for data in test_loader:# 每個批次的圖片及便簽imgs, targets = dataoutputs = my_conv(imgs)print(imgs.shape) # torch.Size([64, 3, 32, 32]) 批量64 輸入通道3(RGB彩色) 圖片大小32*32print(outputs.shape) # torch.Size([64, 6, 30, 30]) 批量64 輸出通道6 圖片大小30*30# 根據(jù)輸入的卷積參數(shù)計算卷積后圖片大小的方法見官網(wǎng)# https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html#torch.nn.Conv2dwrite.add_images("imgs", imgs, step)# 由于outputs.shape = [64, 6, 30, 30] 輸出通道6 RGB為3 無法構(gòu)建圖像,利用reshape變化格式outputs = torch.reshape(outputs, (-1, 3, 30, 30)) # 不確定的維度用-1自動填充write.add_images("outputs", outputs, step)step += 1
write.close()
2.3 MaxPool2d
PyTorch 中用于執(zhí)行二維最大池化(Max Pooling)操作的類。它通常用于卷積神經(jīng)網(wǎng)絡(luò)(CNN)中,用于減少特征圖的空間維度,從而減少模型的參數(shù)數(shù)量,降低過擬合風險,并提高計算效率。
最大池化層原理
MaxPool2d 的主要參數(shù)
kernel_size (int 或 tuple):
池化窗口的大小??梢允且粋€整數(shù),例如 kernel_size=2,表示窗口的高度和寬度都是 2;也可以是一個長度為 2 的元組 (kernel_height, kernel_width),例如 kernel_size=(2, 2)。
stride (int 或 tuple, optional):
池化操作的步幅??梢允且粋€整數(shù),例如 stride=2,表示在高度和寬度方向上的步幅都是 2;也可以是一個長度為 2 的元組 (stride_height, stride_width),例如 stride=(2, 2)。默認值是 kernel_size。
padding (int 或 tuple, optional):
輸入的每條邊補充0的層數(shù)。可以是一個整數(shù),例如 padding=1,也可以是一個長度為 2 的元組 (padding_height, padding_width),例如 padding=(1, 1)。默認值是 0,即不填充。
dilation (int 或 tuple, optional):
池化核元素之間的間距??梢允且粋€整數(shù),例如 dilation=1,也可以是一個長度為 2 的元組 (dilation_height, dilation_width),例如 dilation=(2, 2)。默認值是 1,即沒有間距。
return_indices (bool, optional):
如果設(shè)置為 True,則返回輸出中每個最大值的索引。默認為 False。
ceil_mode (bool, optional):
如果設(shè)置為 True,則使用 ceil 而不是 floor 計算輸出形狀。默認為 False。
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterdataset = torchvision.datasets.CIFAR10(root='./dataset', train=False,transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset, batch_size=64)class MyPool(torch.nn.Module):def __init__(self):super(MyPool, self).__init__()self.pool = torch.nn.MaxPool2d(kernel_size=3,ceil_mode=True)def forward(self, x):return self.pool(x)my_pool = MyPool()
write = SummaryWriter(log_dir='./logs')
step = 1
for data in dataloader:imgs, labels = datawrite.add_images("imgs",imgs,step)outputs = my_pool(imgs)write.add_images("MaxPool2d",outputs,step)step += 1
write.close()
2.4 ReLU
ReLU(Rectified Linear Unit)是深度學習中常用的一種激活函數(shù),用于增加神經(jīng)網(wǎng)絡(luò)的非線性特性。ReLU 的輸出對于負值是零,這意味著在訓練過程中,神經(jīng)元可以學習更加稀疏的表示,從而減少了過擬合的可能性。
import torch
from torch import nninput = torch.tensor([[1, -0.5],[-5, 8]])
"""
myrelu = nn.ReLU()
output = myrelu(input)
"""
class myReLU(nn.Module):def __init__(self):super(myReLU, self).__init__()self.relu = nn.ReLU()def forward(self, x):return self.relu(x)myrelu = myReLU()
output = myrelu(input)
print(output)
2.5 BatchNorm2d
PyTorch 中用于二維批量歸一化操作的類。它在深度學習中廣泛用于加速網(wǎng)絡(luò)訓練,并提高模型的收斂速度和穩(wěn)定性。
- 計算均值和方差:
對每個通道,在一個 batch 的所有樣本上分別計算均值和方差。- 歸一化:
使用計算得到的均值和方差對每個通道的特征圖進行歸一化,得到標準化的特征圖。- 縮放和位移:
引入可學習的參數(shù) gamma(縮放因子)和 beta(位移參數(shù)),用于調(diào)整歸一化后的特征圖的分布,增加網(wǎng)絡(luò)的表達能力。- 反向傳播時的梯度更新:
在訓練過程中,BatchNorm2d 對歸一化后的輸出進行縮放和位移,這些參數(shù)會隨著反向傳播更新。
參數(shù)
num_features:
說明:指定輸入數(shù)據(jù)的特征數(shù)或通道數(shù)。對于二維卷積來說,通常是輸出特征圖的通道數(shù)。
示例:如果你的卷積層輸出通道數(shù)是 16,則 num_features 應該設(shè)置為 16。
eps:
說明:是一個小的數(shù),用于防止除以零的情況。在歸一化過程中,會將方差加上 eps,以確保數(shù)值穩(wěn)定性。
示例:一般情況下,不需要手動調(diào)整這個值,使用默認值即可。
momentum:
說明:用于計算運行均值和方差的動量。在訓練過程中,當前的均值和方差會根據(jù) momentum 更新到運行均值和方差中。
示例:通常情況下,使用默認值即可。較大的 momentum 表示更多的歷史信息被保留,可以提高歸一化的穩(wěn)定性。
affine:
說明:一個布爾值,用于指定是否應該學習 gamma 和 beta 參數(shù)。如果設(shè)置為 False,則 BatchNorm2d 只執(zhí)行歸一化,不學習額外的縮放和偏移參數(shù)。
示例:通常情況下,保持默認值,即學習 gamma 和 beta 參數(shù)。
track_running_stats:
說明:一個布爾值,指定是否應該追蹤運行時的均值和方差。如果設(shè)置為 True,則在訓練過程中會計算并更新運行時的均值和方差;如果設(shè)置為 False,則使用批次內(nèi)的均值和方差。
示例:通常情況下,保持默認值。但在某些情況下,如在推斷時可以設(shè)置為 False,以減少內(nèi)存占用和計算量。
import torch
import torch.nn as nn# 示例:創(chuàng)建一個卷積層,接著一個BatchNorm2d層,然后是ReLU激活函數(shù)# 假設(shè)輸入特征圖大小為 (N, C, H, W) = (1, 3, 32, 32)
input_tensor = torch.randn(1, 3, 32, 32)# 定義一個卷積層
conv_layer = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)# 添加BatchNorm2d層
# 注意:BatchNorm2d的num_features參數(shù)應該是卷積層輸出的通道數(shù),這里是16
batchnorm_layer = nn.BatchNorm2d(16)# 使用ReLU作為激活函數(shù)
relu = nn.ReLU()# 將輸入通過卷積層、BatchNorm2d層和ReLU激活函數(shù)依次傳遞
output = conv_layer(input_tensor)
output = batchnorm_layer(output)
output = relu(output)
nn.Conv2d
定義了一個卷積層,輸入通道數(shù)為 3,輸出通道數(shù)為 16。nn.BatchNorm2d
創(chuàng)建了一個BatchNorm2d
層,它的num_features
參數(shù)設(shè)置為卷積層輸出的通道數(shù)(這里是 16)。nn.ReLU
是一個ReLU
激活函數(shù),用于增加網(wǎng)絡(luò)的非線性特性。- 輸入通過卷積層、
BatchNorm2d
層和ReLU
激活函數(shù)的順序傳遞,以形成網(wǎng)絡(luò)的前向傳播流程。
2.6 Linear
輸入?yún)?shù)
in_features:(一般需要展平,一維)
如果輸入是一個大小為 10 的向量 (in_features=10),那么每個輸入樣本就有 10 個特征。
out_features:
如果希望層的輸出是大小為 5 的向量 (out_features=5),那么每個樣本的輸出就是一個大小為 5 的向量。
bias:
如果設(shè)置為 True,則層會學習一個可學習的偏置。如果設(shè)置為 False,則層不會學習額外的偏置項。
通常情況下會設(shè)置為 True,除非你特別希望從層中去除偏置。
import torch
import torchvision
from torch import nn
from torch.utils.tensorboard import SummaryWriterdataset = torchvision.datasets.CIFAR10(root='./dataset', train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataload = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True,drop_last=True)
class MyLinear(nn.Module):def __init__(self):super(MyLinear, self).__init__()self.linear = nn.Linear(in_features=196608, out_features=10)def forward(self, x):return self.linear(x)mylinear = MyLinear()for data in dataload:imgs, labels = data# [64, 3, 32, 32]->[1,1,1,196608]->[10]print(imgs.shape)# 將圖片張量展平(一行) 作為in_featuresoutputs = torch.flatten(imgs) # 或者outputs = torch.reshape(imgs,(1,1,1,-1))print(outputs.shape)# 傳入linear層outputs = mylinear(outputs)print(outputs.shape)
2.7 Sequential
Sequential是一種模型的組織方式,特別適用于那些層按照順序堆疊的簡單模型。
Sequential 有時也指一種按照順序處理數(shù)據(jù)的方法或工作流。
dataset = torchvision.datasets.CIFAR10(root='./dataset', train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataload = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True, drop_last=True)class MyNet(torch.nn.Module):def __init__(self):super(MyNet, self).__init__()self.conv1 = nn.Conv2d(3, 32, 5, padding=2)self.maxpool1 = nn.MaxPool2d(2)self.conv2 = nn.Conv2d(32, 32, 5, padding=2)self.maxpool2 = nn.MaxPool2d(2)self.conv3 = nn.Conv2d(32, 64, 5, padding=2)self.maxpool3 = nn.MaxPool2d(2)self.flatten = nn.Flatten()self.linear1 = nn.Linear(1024, 64)self.linear2 = nn.Linear(64, 10)def forward(self, x):x = self.conv1(x)x = self.maxpool1(x)x = self.conv2(x)x = self.maxpool2(x)x = self.conv3(x)x = self.maxpool3(x)x = self.flatten(x)x = self.linear1(x)x = self.linear2(x)return x# 利用Sequential
class MySeq(nn.Module):def __init__(self):super(MySeq, self).__init__()self.model1 = Sequential(nn.Conv2d(3, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 64, 5, padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model1(x)return xmynet = MyNet()
myseq = MySeq()
for data in dataload:imgs, labels = dataoutputs = mynet(imgs)outputs2 = myseq(imgs)print("test1:",end="")print(outputs.shape)print("test2:",end="")print(outputs2.shape)
3 損失函數(shù)
3.1 MSELoss
均方誤差(MSE)損失是機器學習中常用的一種損失函數(shù),特別適用于回歸問題。使用MSE作為損失函數(shù)的目的是,對較大的誤差進行更重的懲罰,而對較小的誤差進行輕微的懲罰。通過平方差的方式實現(xiàn)了這一目的。
使用方法
- 準備數(shù)據(jù):
確保你有一個包含輸入特征(例如房屋面積、股票歷史數(shù)據(jù)等)和對應輸出值(例如房價、股票價格等)的數(shù)據(jù)集。- 定義模型:
選擇適當?shù)臋C器學習模型,如線性回歸、神經(jīng)網(wǎng)絡(luò)等,這取決于你的問題和數(shù)據(jù)。- 選擇優(yōu)化算法:
選擇一個優(yōu)化算法,比如梯度下降,用于調(diào)整模型參數(shù)以最小化MSE損失。- 定義損失函數(shù):
在訓練過程中,定義MSE損失函數(shù)。在大多數(shù)機器學習框架中,這通常是預先定義好的,你只需要選擇并使用。- 訓練模型:
將數(shù)據(jù)輸入模型,通過反向傳播算法優(yōu)化模型參數(shù),使得MSE損失逐步減小。- 評估模型:
在訓練過程中和/或之后,使用驗證集或測試集評估模型的性能。通常,計算預測值與真實值之間的MSE來衡量模型的準確性。
import torch
import torch.nn as nn
import torch.optim as optim# 假設(shè)有數(shù)據(jù) X_train, y_train 作為訓練集# 定義模型
class LinearRegression(nn.Module):def __init__(self, input_size, output_size):super(LinearRegression, self).__init__()self.linear = nn.Linear(input_size, output_size)def forward(self, x):return self.linear(x)# 設(shè)置模型參數(shù)
input_size = X_train.shape[1] # 輸入特征的大小
output_size = 1 # 輸出為單個數(shù)值(房價)model = LinearRegression(input_size, output_size)# 定義損失函數(shù)和優(yōu)化器
criterion = nn.MSELoss() # 使用均方誤差損失
optimizer = optim.SGD(model.parameters(), lr=0.01) # 使用隨機梯度下降優(yōu)化器# 訓練模型
num_epochs = 100
for epoch in range(num_epochs):# 前向傳播outputs = model(X_train)loss = criterion(outputs, y_train)# 反向傳播和優(yōu)化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch+1) % 10 == 0:print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')# 模型訓練完成,可以進行預測
with torch.no_grad():predicted = model(X_test)test_loss = criterion(predicted, y_test)print(f'Test MSE Loss: {test_loss.item():.4f}')
- 我們定義了一個簡單的線性回歸模型。
- 使用PyTorch中的nn.MSELoss()定義了MSE損失函數(shù)。
- 使用隨機梯度下降(SGD)作為優(yōu)化器,通過反向傳播算法來優(yōu)化模型參數(shù)。
- 訓練模型并打印出每個epoch的訓練損失。
- 最后,用測試集評估模型的性能,計算測試集上的MSE損失。
3.2 CrossEntropyLoss
交叉熵損失是深度學習中常用的一種損失函數(shù),特別適用于多類別分類任務。
參數(shù):
Input: Shape(C)or (N,C)
C =number of classes
N = batch size
reduction:指定損失的計算方式,可以是’mean’(默認)、‘sum’或’none’
import torch
from torch import nn
"""
損失函數(shù):
1.計算實際輸出和目標之間的差距
2.為我們更新輸出提供一定的依據(jù)(反向傳播)
"""
input = torch.tensor([1.0, 2.0, 3.0])
target = torch.tensor([3.0, 2.0, 3.0])
# 批量維度 通道維度 寬度維度 高度維度
input = torch.reshape(input, (1, 1, 1, 3))
target = torch.reshape(target, (1, 1, 1, 3))loss = nn.MSELoss(reduction='mean')
result = loss(input, target)
print(result)x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
x= torch.reshape(x, (1, 3)) # 1個樣本,3個類別
cross_loss = nn.CrossEntropyLoss()
result = cross_loss(x, y)
print(result)
4 梯度優(yōu)化
4.1 optim.SGD
PyTorch中用于實現(xiàn)隨機梯度下降優(yōu)化算法的類。
- SGD是一種基本的優(yōu)化算法,每次迭代都使用一小批次(batch)的數(shù)據(jù)來計算梯度和更新模型參數(shù)。
- 它通過計算每個參數(shù)的梯度以及學習率來更新模型的權(quán)重,以減少損失函數(shù)的值。
參數(shù)
params:需要優(yōu)化的參數(shù)列表。
lr:學習率,控制每次參數(shù)更新的步長大小。
momentum:動量因子,用于加速SGD在相關(guān)方向上前進,并減少擺動。
dampening:動量的抑制因子。
weight_decay:權(quán)重衰減(L2懲罰),用于對模型參數(shù)進行正則化。
nesterov:是否使用Nesterov動量。
import torch
import torchvision
from torch import nn
from torch.nn import Sequential
from torch.utils.tensorboard import SummaryWriterdataset = torchvision.datasets.CIFAR10(root='./dataset', train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataload = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True, drop_last=True)# 利用Sequential
class MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.model1 = Sequential(nn.Conv2d(3, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 64, 5, padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model1(x)return xmynet = MyNet()
loss = nn.CrossEntropyLoss()
optim = torch.optim.SGD(mynet.parameters(), lr=0.01)
for epoch in range(20): # 一共訓練20次epoch_loss = 0.0 # 每次訓練所有樣本的損失和for data in dataload: # 訓練一次所有數(shù)據(jù)imgs, targets = dataoutputs = mynet(imgs)res_loss = loss(outputs, targets)########################################optim.zero_grad() # 清空梯度 (多次訓練,防止梯度影響)res_loss.backward() # 反向傳播計算梯度optim.step() # 更新參數(shù)#######################################epoch_loss += res_loss.item()print("epoch:{}, loss:{}".format(epoch, epoch_loss))
5 模型
5.1 VGG16模型
模型使用步驟
-
下載模型權(quán)重:如果你第一次運行該代碼,PyTorch 會自動下載并緩存預訓練模型的權(quán)重文件。這些權(quán)重通常存儲在預定義的位置(通常是 PyTorch 提供的服務器上)。
-
加載權(quán)重:一旦下載完成,models.vgg16(pretrained=True) 將會加載這些權(quán)重并應用于模型的各個層次,包括卷積層和全連接層。這意味著模型會被初始化為在 ImageNet 數(shù)據(jù)集上訓練過的狀態(tài),其中包括了學習到的特征權(quán)重。
-
使用預訓練模型:加載后的 vgg16 模型現(xiàn)在可以直接用于特征提取、微調(diào)或者其他任務。由于預訓練模型已經(jīng)學習了大量的特征表示,因此在許多視覺任務中,使用這樣的預訓練模型往往能夠顯著提升訓練效果和泛化能力。
vgg16_true = torchvision.models.vgg16(pretrained=True)
# pretrained=True 參數(shù)的作用是告訴PyTorch加載一個預訓練好的 VGG16 模型。
vgg16_false = torchvision.models.vgg16(pretrained=False)print(vgg16_true) # VGG16模型的架構(gòu)# 修改已有模型
# 添加新的模塊(獲取已有模塊的各個部分)
vgg16_true.classifier.add_module("add_module",nn.Linear(1000, 10))
print(vgg16_true)
# 修改新的模塊
vgg16_false.classifier[6] = nn.Linear(4096, 10)
print(vgg16_false)
5.2 模型保存與加載
- 保存
torch.save()
是 PyTorch 提供的一個函數(shù),用于將模型、張量或者字典等對象保存到磁盤上的文件中。
torch.save(obj, filepath)
obj: 要保存的對象,可以是模型、張量或者字典等。
filepath: 保存對象的文件路徑。
import torch
import torchvisionvgg16 = torchvision.models.vgg16(pretrained=False)
保存方式1 保存模型的結(jié)構(gòu)和參數(shù)(整個全保存)
torch.save(vgg16, 'vgg16.pth') #上面的代碼將整個模型保存到的文件中。這種方法保存了模型的架構(gòu)和訓練好的權(quán)重。
上面的代碼將整個 vgg16 模型保存到名為 vgg16.pth
的文件中。這種方法保存了模型的架構(gòu)和訓練好的權(quán)重。
只需要保存模型的狀態(tài)字典(即模型的權(quán)重),而不保存整個模型對象的結(jié)構(gòu)。
torch.save(vgg16.state_dict(), 'vgg16_dict.pth')
這段代碼將只保存 vgg16 模型的權(quán)重到 vgg16_dict.pth
文件中,這樣可以節(jié)省存儲空間并且更加靈活,因為在加載時我們可以根據(jù)需要重新構(gòu)建模型。
- 加載
torch.load()
是 PyTorch 提供的函數(shù),用于從磁盤上加載已保存的模型、張量或字典等對象。
torch.load(filepath)
filepath: 要加載的文件路徑,該文件通常是由 torch.save() 函數(shù)保存的。
# 加載模型(結(jié)構(gòu)、參數(shù)等等)
"""
這段代碼會將之前保存的整個vgg16模型加載到變量 model 中。
加載后的模型可以直接用于預測或繼續(xù)訓練,因為它包含了之前保存的所有結(jié)構(gòu)和參數(shù)。
"""
model1 = torch.load("vgg16.pth")
print(model1)# 記載狀態(tài)參數(shù)模型
"""
這段代碼首先創(chuàng)建了一個與預訓練的vgg 模型相同結(jié)構(gòu)的新模型 model,
然后將加載的狀態(tài)字典 state_dict 復制到這個新模型中。
這種方法適用于當我們需要從文件中加載權(quán)重,并且已有對應模型結(jié)構(gòu)的情況。
"""
model2 = torchvision.models.vgg16(pretrained=False)
print(torch.load("vgg16_dict.pth")) # 只包含權(quán)重參數(shù)
model2.load_state_dict(torch.load("vgg16_dict.pth"))
print(model2) # 整個模型
5.3 完整模型訓練
準備數(shù)據(jù):加載訓練數(shù)據(jù)集,并設(shè)置數(shù)據(jù)加載器(DataLoader)用于批量加載數(shù)據(jù)。
定義模型:創(chuàng)建或加載需要訓練的模型,并選擇損失函數(shù)(loss function)和優(yōu)化器(optimizer)。
訓練循環(huán):使用循環(huán)遍歷訓練數(shù)據(jù)集,對模型進行訓練,主要包括以下步驟:
- 將模型設(shè)置為訓練模式,即調(diào)用 model.train()。
- 遍歷每個小批量數(shù)據(jù),在每個批量中執(zhí)行以下操作:
- 將數(shù)據(jù)傳遞給模型,獲取模型的輸出。
- 計算損失(loss)。
- 執(zhí)行反向傳播(backpropagation),計算梯度。
- 使用優(yōu)化器更新模型參數(shù)。
在每個小批量數(shù)據(jù)的處理結(jié)束后,可能會記錄或打印訓練過程中的一些指標,如損失值或準確率。
評估模型:在每個 epoch 或一定周期后,使用驗證集評估模型性能,通常使用 torch.no_grad() 禁止梯度計算,以減少內(nèi)存占用。
保存模型:在訓練完成后,保存模型的參數(shù)或整個模型,以便后續(xù)推理或繼續(xù)訓練。
構(gòu)建模型
class MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.model1 = Sequential(nn.Conv2d(3, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 64, 5, padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model1(x)return x
訓練模型
# 準備數(shù)據(jù)集
train_data = torchvision.datasets.CIFAR10(root='./dataset', train=True, transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10(root='./dataset', train=False, transform=torchvision.transforms.ToTensor(),download=True)# 數(shù)據(jù)集長度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("訓練數(shù)據(jù)集的長度為:{}".format(train_data_size))
print("測試數(shù)據(jù)集的長度為:{}".format(test_data_size))# 利用DataLoader來加載數(shù)據(jù)集
train_dataloader = DataLoader(train_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)# 搭建神經(jīng)網(wǎng)絡(luò)
mynet = MyNet()# 損失函數(shù)
loss_fn = nn.CrossEntropyLoss()# 優(yōu)化器
learning_rate = 0.01
optimizer = torch.optim.SGD(mynet.parameters(), lr=learning_rate)# 訓練需要的參數(shù)
# 記錄訓練的次數(shù)
total_train_step = 0
# 記錄測試的次數(shù)
total_test_step = 0
# 訓練的輪數(shù)
epoch = 10# 添加TensorBoard
write = SummaryWriter(log_dir='./logs')
# 開始輪數(shù)
for ep in range(epoch):print("----------第{}輪訓練開始-------------".format(ep + 1))# 訓練步驟開始mynet.train()start_time = time.time()for data in train_dataloader:imgs, targets = dataoutputs = mynet(imgs)loss = loss_fn(outputs, targets)# 優(yōu)化器優(yōu)化模型optimizer.zero_grad()loss.backward()optimizer.step()total_train_step += 1# 每訓練100次 打印一次數(shù)據(jù)if total_train_step % 100 == 0:end_time = time.time()write.add_scalar('train_loss', loss.item(), total_train_step)print("訓練次數(shù):{} Loss:{} Time:{}".format(total_train_step, loss.item(),end_time-start_time))# 測試步驟開始mynet.eval()"""正確率分析(以二分類為例)inputs = [0,1] # 表示輸入的類別outputs = torch.tensor([1.0,4.0],[2.0,3.0]) # 表示輸出各類別的概率preds = outputs.argmax(1) # 橫向求出最大值的下標->[1,1]->預測的類別inputs==preds # 比較輸入與預測——>[flase,true]"""total_loss = 0 # 計算每輪測試的梯度和total_accuracy = 0 # 計算每輪測試的正確個數(shù)# 測試不需要求梯度(此部分不會求梯度)"""用于在執(zhí)行代碼時臨時關(guān)閉梯度計算。它的作用主要是在推理階段或者不需要計算梯度的代碼段中,提高代碼的運行效率和減少內(nèi)存消耗"""with torch.no_grad():for data in test_dataloader:imgs, targets = dataoutputs = mynet(imgs)loss = loss_fn(outputs, targets)# 每次預測正確的個數(shù)accuracy = (targets==outputs.argmax(1)).sum()total_accuracy += accuracy.item()total_test_step += 1total_loss += loss.item()write.add_scalar('test_loss', total_loss, total_test_step)print("第{}輪整體測試集上的Loss:{}".format(ep + 1, total_loss))write.add_scalar('accuracy_rate', total_accuracy/test_data_size, total_test_step)print("第{}輪整體測試集上的accuracy_rate:{}".format(ep+1, total_accuracy/test_data_size))保存每次訓練的模型(結(jié)構(gòu)及訓練的參數(shù))torch.save(mynet,"mynet_{}.pth".format(ep))print("模型保存成功")
write.close()
train() 和 eval() 是在深度學習中經(jīng)常用到的兩個方法,它們通常用于切換模型的工作模式,即訓練模式和評估模式。
mynet.train()
在訓練過程中,我們需要使用 train() 方法來告訴模型開始訓練,并啟用一些特定于訓練的功能,
比如啟用 dropout 或者批量歸一化的訓練模式。
mynet.eval()
在評估或推理階段,我們使用 eval() 方法告訴模型停止學習,不啟用 dropout 或批量歸一化的訓練模式,以確保輸出的一致性和穩(wěn)定性
- 停用 dropout 層:在評估時,dropout 層不再丟棄神經(jīng)元,以保持輸出的穩(wěn)定性。
- 使用訓練時計算的移動平均值來代替批量歸一化的計算,以減少測試時間的波動。
區(qū)別與使用場景
- 區(qū)別:主要區(qū)別在于在訓練模式下是否啟用了
dropout
和批量歸一化
的訓練行為。訓練模式下,模型會保留這些行為以便模型學習;評估模式下,這些行為被停用以保持輸出的一致性。 - 使用場景:在訓練階段,使用
train()
方法訓練模型;在測試、驗證或?qū)嶋H應用中,使用eval()
方法評估模型。
5.4 利用GPU訓練模型
在PyTorch中,.cuda()是一個方法,用于將Tensor或模型加載到GPU上進行加速計算。
- 將Tensor數(shù)據(jù)、網(wǎng)絡(luò)、損失函數(shù)移到GPU上
.cuda()
是一個方法,用于將Tensor或模型加載到GPU上進行加速計算。
通常是對模型、數(shù)據(jù)、損失函數(shù)使用.cuda()
...
...
...
# 搭建神經(jīng)網(wǎng)絡(luò)
mynet = MyNet()
# 使用.cuda()首先判斷gpu是否可用
if torch.cuda.is_available():mynet.cuda()# 損失函數(shù)
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():loss_fn = loss_fn.cuda()...
...
...
# 開始輪數(shù)
for ep in range(epoch):
...
...
...for data in train_dataloader:imgs, targets = dataif torch.cuda.is_available():imgs, targets = imgs.cuda(), targets.cuda()...
...
...
- 將Tensor或模型加載到特定設(shè)備上
.to()
方法是一個用于Tensor或模型轉(zhuǎn)移到不同設(shè)備(如CPU或GPU)的通用方法。它的主要作用是將數(shù)據(jù)或模型從當前設(shè)備移動到目標設(shè)備
.to()
方法可以接受一個torch.device
對象或一個設(shè)備字符串作為參數(shù),從而將Tensor或模型加載到指定的設(shè)備上。
device = torch.device('cuda')
...
...
...# 搭建神經(jīng)網(wǎng)絡(luò)
mynet = MyNet()
# 轉(zhuǎn)移設(shè)備
mynet.to(device)
# 損失函數(shù)
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
...
...
...
# 開始輪數(shù)
for ep in range(epoch):print("----------第{}輪訓練開始-------------".format(ep + 1))# 訓練步驟開始start_time = time.time()for data in train_dataloader:imgs, targets = dataimgs, targets = imgs.to(device), targets.to(device)
...
...
...
5.5 應用模型
使用訓練的模型去預測CIFAR10中圖片的分類
- 加載待預測圖片
- 修改圖片格式為模型規(guī)定的格式
- 加載模型
- 使用模型預測
image_path = "imgs/dog.png"
# 加載圖片,并轉(zhuǎn)換為正確格式
image = Image.open(image_path)
'''
用于對圖像進行大小調(diào)整(resize)。
在計算機視覺任務中,經(jīng)常需要對輸入的圖像進行預處理,使其符合模型的輸入要求或者統(tǒng)一到相同的尺寸上進行批處理。
Resize 類允許我們按照指定的大小調(diào)整圖像。
'''
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape) # torch.Size([3, 32, 32])# 加載訓練好的模型
class MyNet(nn.Module):def __init__(self):super(MyNet, self).__init__()self.model1 = Sequential(nn.Conv2d(3, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 32, 5, padding=2),nn.MaxPool2d(2),nn.Conv2d(32, 64, 5, padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model1(x)return x# 加載模型
'''
mynet.pth在gpu訓練的模型需要在cpu進行映射map_location=torch.device('cpu')
否則錯誤 Input type (torch.FloatTensor) and weight type (torch.cuda.FloatTensor) should be the same or input should be a MKLDNN tensor and weight is a dense tensor
'''
model = torch.load("mynet.pth", map_location=torch.device('cpu'))
# 重塑確保 image 的形狀符合下游操作或模型的預期形狀。這是深度學習工作流中常見的操作,用于標準化張量的形狀。
image = torch.reshape(image, (1, 3, 32, 32))
# 評估模式
model.eval()
with torch.no_grad():outputs = model(image)
print(outputs.argmax(dim=1).item()) # 輸出概率最大的種類下標
''' 種類坐標對應
{'airplane': 0, 'automobile': 1, 'bird': 2, 'cat': 3, 'deer': 4,'dog': 5, 'frog': 6, 'horse': 7, 'ship': 8, 'truck': 9}
'''