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