網(wǎng)站seo診斷評分63淘寶指數(shù)查詢
人臉表情分類任務(wù)
- 注意:整個(gè)項(xiàng)目來自阿里云天池,下面是開發(fā)人員的聯(lián)系方式,本人僅作為學(xué)習(xí)記錄!!!
- 該文章原因,學(xué)習(xí)該項(xiàng)目,完善注釋內(nèi)容,針對新版本的Pytorch進(jìn)行部分代碼調(diào)整
- 本文章采用pytorch2.0.1版本,python3.10版本
源碼鏈接
這是一個(gè)使用pytorch實(shí)現(xiàn)的簡單的2分類任務(wù)
項(xiàng)目結(jié)構(gòu):- net.py: 網(wǎng)絡(luò)定義腳本- train.py:模型訓(xùn)練腳本- inference.py:模型推理腳本- run_train.sh 訓(xùn)練可執(zhí)行文件- run_inference.sh 推理可執(zhí)行文件# Copyright 2019 longpeng2008. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# If you find any problem,please contact us longpeng2008to2012@gmail.com
1. 網(wǎng)絡(luò)結(jié)構(gòu)
# coding:utf8import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np# 3層卷積神經(jīng)網(wǎng)絡(luò)simpleconv3定義
# 包括3個(gè)卷積層,3個(gè)BN層,3個(gè)ReLU激活層,3個(gè)全連接層class simpleconv3(nn.Module):# 初始化函數(shù)def __init__(self, nclass):# 繼承父類super(simpleconv3, self).__init__()# 3通道 輸入圖片大小為3*48*48,輸出特征圖大小為12*23*23,卷積核大小為3*3,步長為2'''輸出特征圖大小 = [(輸入大小 - 卷積核大小) / 步長] + 1輸入大小是 48x48卷積核大小是 3x3步長是 2將這些值代入公式,您將得到輸出特征圖的大小:輸出特征圖大小 = [(48 - 3) / 2] + 1 = (45 / 2) + 1 = 22.5 + 1 = 23'''self.conv1 = nn.Conv2d(3, 12, 3, 2)# 批量標(biāo)準(zhǔn)化操作 12個(gè)特征通道self.bn1 = nn.BatchNorm2d(12)# 輸入圖片大小為12*23*23,輸出特征圖大小為24*11*11,卷積核大小為3*3,步長為2'''輸出特征圖大小 = [(輸入大小 - 卷積核大小) / 步長] + 1輸入大小是 23x23卷積核大小是 3x3步長是 2將這些值代入公式,您將得到輸出特征圖的大小:輸出特征圖大小 = [(23 - 3) / 2] + 1 = (20 / 2) + 1 = 10 + 1 = 11'''self.conv2 = nn.Conv2d(12, 24, 3, 2)# 批量標(biāo)準(zhǔn)化操作 24個(gè)特征通道self.bn2 = nn.BatchNorm2d(24)# 輸入圖片大小為24*11*11,輸出特征圖大小為48*5*5,卷積核大小為3*3,步長為2'''輸出特征圖大小 = [(輸入大小 - 卷積核大小) / 步長] + 1輸入大小是 11x11卷積核大小是 3x3步長是 2將這些值代入公式,您將得到輸出特征圖的大小:輸出特征圖大小 = [(11 - 3) / 2] + 1 = (8 / 2) + 1 = 4 + 1 = 5'''self.conv3 = nn.Conv2d(24, 48, 3, 2)# 批量標(biāo)準(zhǔn)化操作 48個(gè)特征通道self.bn3 = nn.BatchNorm2d(48)# 輸入向量長為48*5*5=1200,輸出向量長為1200 展平self.fc1 = nn.Linear(48 * 5 * 5, 1200)# 1200 -> 128self.fc2 = nn.Linear(1200, 128) # 輸入向量長為1200,輸出向量長為128# 128 -> 類別數(shù)self.fc3 = nn.Linear(128, nclass) # 輸入向量長為128,輸出向量長為nclass,等于類別數(shù)# 前向函數(shù)def forward(self, x):# relu函數(shù),不需要進(jìn)行實(shí)例化,直接進(jìn)行調(diào)用# conv,fc層需要調(diào)用nn.Module進(jìn)行實(shí)例化# 先卷積后標(biāo)準(zhǔn)化再激活x = F.relu(self.bn1(self.conv1(x)))x = F.relu(self.bn2(self.conv2(x)))x = F.relu(self.bn3(self.conv3(x)))# 更改形狀 改為1維x = x.view(-1, 48 * 5 * 5)# 全連接再激活x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xif __name__ == '__main__':import torchx = torch.randn(1, 3, 48, 48)model = simpleconv3(2)y = model(x)print(model)'''simpleconv3((conv1): Conv2d(3, 12, kernel_size=(3, 3), stride=(2, 2))(bn1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(12, 24, kernel_size=(3, 3), stride=(2, 2))(bn2): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(24, 48, kernel_size=(3, 3), stride=(2, 2))(bn3): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(fc1): Linear(in_features=1200, out_features=1200, bias=True)(fc2): Linear(in_features=1200, out_features=128, bias=True)(fc3): Linear(in_features=128, out_features=2, bias=True))'''
2. 訓(xùn)練函數(shù)
部分代碼內(nèi)容與作者不同
- scheduler.step()與optimizer.step()修改前后順序
- RandomSizedCrop改為RandomCrop
- transforms.Scale修改為transforms.Resize
# coding:utf8
from __future__ import print_function, division
import os
import torch
import torch.nn as nn
import torch.optim as optim
# 使用tensorboardX進(jìn)行可視化
from tensorboardX import SummaryWriter
from torch.optim import lr_scheduler
from torchvision import datasets, transformsfrom net import simpleconv3writer = SummaryWriter('logs') # 創(chuàng)建一個(gè)SummaryWriter的示例,默認(rèn)目錄名字為runs# 訓(xùn)練主函數(shù)
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):"""訓(xùn)練模型Args:model: 模型criterion: loss函數(shù)optimizer: 優(yōu)化器scheduler: 學(xué)習(xí)率調(diào)度器num_epochs: 訓(xùn)練輪次Returns:"""# 開始訓(xùn)練for epoch in range(num_epochs):# 打印訓(xùn)練輪次print(f'Epoch {epoch+1}/{num_epochs}')for phase in ['train', 'val']:if phase == 'train':# 設(shè)置為訓(xùn)練模式model.train(True)else:# 設(shè)置為驗(yàn)證模式model.train(False)# 損失變量running_loss = 0.0# 精度變量running_accs = 0.0number_batch = 0# 從dataloaders中獲得數(shù)據(jù)for data in dataloaders[phase]:inputs, labels = dataif use_gpu:inputs = inputs.cuda()labels = labels.cuda()# 清空梯度optimizer.zero_grad()# 前向運(yùn)行outputs = model(inputs)# 使用max()函數(shù)對輸出值進(jìn)行操作,得到預(yù)測值索引_, preds = torch.max(outputs.data, 1)# 計(jì)算損失loss = criterion(outputs, labels)if phase == 'train':# 誤差反向傳播loss.backward()# 參數(shù)更新optimizer.step()running_loss += loss.data.item()running_accs += torch.sum(preds == labels).item()number_batch += 1# 調(diào)整學(xué)習(xí)率scheduler.step()# 得到每一個(gè)epoch的平均損失與精度epoch_loss = running_loss / number_batchepoch_acc = running_accs / dataset_sizes[phase]# 收集精度和損失用于可視化if phase == 'train':writer.add_scalar('data/trainloss', epoch_loss, epoch)writer.add_scalar('data/trainacc', epoch_acc, epoch)else:writer.add_scalar('data/valloss', epoch_loss, epoch)writer.add_scalar('data/valacc', epoch_acc, epoch)print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))writer.close()return modelif __name__ == '__main__':# 圖像統(tǒng)一縮放大小image_size = 60# 圖像裁剪大小,即訓(xùn)練輸入大小crop_size = 48# 分類類別數(shù)nclass = 2# 創(chuàng)建模型model = simpleconv3(nclass)# 數(shù)據(jù)目錄data_dir = './data'# 模型緩存接口if not os.path.exists('models'):os.mkdir('models')# 檢查GPU是否可用,如果是使用GPU,否使用CPUuse_gpu = torch.cuda.is_available()if use_gpu:model = model.cuda()print(model)# 創(chuàng)建數(shù)據(jù)預(yù)處理函數(shù),訓(xùn)練預(yù)處理包括隨機(jī)裁剪縮放、隨機(jī)翻轉(zhuǎn)、歸一化,驗(yàn)證預(yù)處理包括中心裁剪,歸一化data_transforms = {'train': transforms.Compose([transforms.RandomCrop(48), # 隨機(jī)大小、長寬比裁剪圖片size=48 RandomSizedCrop改為RandomCroptransforms.RandomHorizontalFlip(), # 隨機(jī)水平翻轉(zhuǎn) 默認(rèn)概率p=0.5transforms.ToTensor(), # 將原始的PILImage格式或者numpy.array格式的數(shù)據(jù)格式化為可被pytorch快速處理的張量類型transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) # 數(shù)據(jù)標(biāo)準(zhǔn)化 要將圖像三個(gè)通道的數(shù)據(jù) 整理到 [-1,1] 之間 ,可以加快模型的收斂]),'val': transforms.Compose([transforms.Resize(64), # Scale用于調(diào)整圖像的大小,現(xiàn)在采用transforms.Resize()代替transforms.CenterCrop(48), # 從圖像中心裁剪圖片尺寸size=48transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]),}# 使用torchvision的dataset ImageFolder接口讀取數(shù)據(jù)image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']}# 創(chuàng)建數(shù)據(jù)指針,設(shè)置batch大小,shuffle,多進(jìn)程數(shù)量dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x],batch_size=16, # 每個(gè)小批次包含16個(gè)樣本shuffle=True, # 是否隨機(jī)打亂數(shù)據(jù)num_workers=4) # 加載數(shù)據(jù)的子進(jìn)程數(shù)for x in ['train', 'val']}# 獲得數(shù)據(jù)集大小dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}# 優(yōu)化目標(biāo)使用交叉熵,優(yōu)化方法使用帶動量項(xiàng)的SGD,學(xué)習(xí)率迭代策略為step,每隔100個(gè)epoch,變?yōu)樵瓉淼?.1倍criterion = nn.CrossEntropyLoss()# 優(yōu)化器 傳入權(quán)重閾值,學(xué)習(xí)率0.1 動量(momentum)是一個(gè)控制梯度下降方向的超參數(shù)。# 它有助于加速訓(xùn)練,特別是在存在平坦區(qū)域或局部極小值時(shí)。動量的值通常在0到1之間。較大的動量值會使參數(shù)更新更平滑。在這里,動量設(shè)置為0.9。optimizer_ft = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)'''lr_scheduler.StepLR 是PyTorch中的學(xué)習(xí)率調(diào)度器(learning rate scheduler),用于在訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)動態(tài)調(diào)整學(xué)習(xí)率。lr_scheduler.StepLR 允許您在訓(xùn)練的不同階段逐步減小學(xué)習(xí)率,以幫助優(yōu)化過程。optimizer_ft:這是您用于優(yōu)化模型參數(shù)的優(yōu)化器,通常是 optim.SGD 或其他PyTorch優(yōu)化器的實(shí)例。學(xué)習(xí)率調(diào)度器將監(jiān)控這個(gè)優(yōu)化器的狀態(tài),并根據(jù)其規(guī)則更新學(xué)習(xí)率。step_size=100:這是學(xué)習(xí)率更新的周期,也稱為學(xué)習(xí)率下降步數(shù)。在每個(gè) step_size 個(gè)訓(xùn)練周期之后,學(xué)習(xí)率將減小。gamma=0.1:這是學(xué)習(xí)率減小的因子。在每個(gè) step_size 個(gè)訓(xùn)練周期之后,學(xué)習(xí)率將乘以 gamma。這意味著學(xué)習(xí)率將以 gamma 的倍數(shù)逐步減小。'''exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=100, gamma=0.1)model = train_model(model=model,criterion=criterion,optimizer=optimizer_ft,scheduler=exp_lr_scheduler,num_epochs=10)torch.save(model.state_dict(), 'models/model.pt')
3. 預(yù)測
執(zhí)行以下內(nèi)容,或者自行安排數(shù)據(jù)集
## 使用方法 python3 inference.py 模型路徑 圖片路徑
python3 inference.py models/model.pt data/train/0/1neutral.jpg
python3 inference.py models/model.pt data/train/1/1smile.jpg
# coding:utf8import sys
import numpy as np
import torch
from PIL import Image
from torchvision import transforms# 全局變量
# sys.argv[1] 權(quán)重文件
# sys.argv[2] 圖像文件夾testsize = 48 # 測試圖大小
from net import simpleconv3# 定義模型
net = simpleconv3(2)
# 設(shè)置推理模式,使得dropout和batchnorm等網(wǎng)絡(luò)層在train和val模式間切換
net.eval()
# 停止autograd模塊的工作,以起到加速和節(jié)省顯存
torch.no_grad()# 載入模型權(quán)重
modelpath = sys.argv[1]
net.load_state_dict(torch.load(modelpath, map_location=lambda storage, loc: storage))# 定義預(yù)處理函數(shù)
data_transforms = transforms.Compose([transforms.Resize(48),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])# 讀取3通道圖片,并擴(kuò)充為4通道tensor
imagepath = sys.argv[2]
image = Image.open(imagepath)
imgblob = data_transforms(image).unsqueeze(0)# 獲得預(yù)測結(jié)果predict,得到預(yù)測的標(biāo)簽值label
predict = net(imgblob)
index = np.argmax(predict.detach().numpy())
# print(predict)
# print(index)if index == 0:print('the predict of ' + sys.argv[2] + ' is ' + str('none'))
else:print('the predict of ' + sys.argv[2] + ' is ' + str('smile'))
4. TensorBoardX的使用
TensorBoardX 是一個(gè)用于在 PyTorch 中可視化訓(xùn)練過程和結(jié)果的工具。它是 TensorBoard 的 Python 版本,用于創(chuàng)建交互式、實(shí)時(shí)的訓(xùn)練和評估圖表。以下是一些使用 TensorBoardX 的一般步驟:
-
安裝 TensorBoardX:首先,您需要安裝 TensorBoardX 庫。您可以使用以下命令安裝它:
pip install tensorboardX
-
導(dǎo)入庫:在您的 PyTorch 代碼中,導(dǎo)入 TensorBoardX 庫:
from tensorboardX import SummaryWriter
-
創(chuàng)建 SummaryWriter:創(chuàng)建一個(gè)
SummaryWriter
對象,以將日志數(shù)據(jù)寫入 TensorBoard 日志目錄。writer = SummaryWriter()
-
記錄數(shù)據(jù):在訓(xùn)練循環(huán)中,使用
writer.add_*
方法來記錄各種數(shù)據(jù),例如標(biāo)量、圖像、直方圖等。以下是一些示例:-
記錄標(biāo)量數(shù)據(jù):
writer.add_scalar('loss', loss, global_step)
-
記錄圖像數(shù)據(jù):
writer.add_image('image', image, global_step)
-
記錄直方圖數(shù)據(jù):
writer.add_histogram('weights', model.conv1.weight, global_step)
-
記錄文本數(shù)據(jù):
writer.add_text('description', 'This is a description.', global_step)
-
-
啟動 TensorBoard 服務(wù)器:在命令行中,使用以下命令啟動 TensorBoard 服務(wù)器:
tensorboard --logdir=/path/to/log/directory
其中
/path/to/log/directory
是存儲 TensorBoardX 日志的目錄。 -
查看可視化結(jié)果:在瀏覽器中打開 TensorBoard 的 Web 界面,通常位于
http://localhost:6006
,您可以在該界面上查看可視化結(jié)果。
請注意,您可以根據(jù)需要記錄不同類型的數(shù)據(jù),并根據(jù)訓(xùn)練過程的不同階段定期記錄數(shù)據(jù)。TensorBoardX 提供了豐富的可視化工具,以幫助您監(jiān)視和分析模型的訓(xùn)練過程。
確保在訓(xùn)練循環(huán)中適時(shí)記錄數(shù)據(jù),并使用 TensorBoardX 查看結(jié)果,以更好地理解和改進(jìn)您的深度學(xué)習(xí)模型。
這是 TensorBoard 啟動時(shí)的一般信息,表明TensorBoard運(yùn)行在本地主機(jī)(localhost)。如果您想使 TensorBoard 可以在網(wǎng)絡(luò)上訪問,可以采取以下幾種方法:
-
使用代理:您可以使用代理服務(wù)器來將 TensorBoard 的端口暴露到網(wǎng)絡(luò)上。這通常需要在代理服務(wù)器上進(jìn)行一些配置,以便外部用戶可以訪問 TensorBoard。代理服務(wù)器可以是諸如 Nginx 或 Apache 之類的 Web 服務(wù)器。
-
使用 --bind_all 參數(shù):在啟動 TensorBoard 時(shí),您可以使用
--bind_all
參數(shù),以將 TensorBoard 綁定到所有網(wǎng)絡(luò)接口。這樣,TensorBoard 將可以在本地網(wǎng)絡(luò)上的任何 IP 地址上訪問,而不僅僅是本地主機(jī)。例如:tensorboard --logdir=/path/to/log/directory --bind_all
-
使用 --host 參數(shù):您還可以使用
--host
參數(shù)來指定 TensorBoard 的主機(jī)名(hostname),以使其在指定的主機(jī)上可用。例如:tensorboard --logdir=/path/to/log/directory --host=0.0.0.0
這將允許 TensorBoard 在所有網(wǎng)絡(luò)接口上運(yùn)行,從而在網(wǎng)絡(luò)上的任何 IP 地址上訪問。
請根據(jù)您的需求和網(wǎng)絡(luò)設(shè)置選擇適當(dāng)?shù)姆椒?。如果只需要在本地訪問 TensorBoard,無需進(jìn)行任何更改。如果需要在網(wǎng)絡(luò)上訪問,可以使用上述選項(xiàng)之一。不過,請注意,為了安全起見,最好將 TensorBoard 限制在受信任的網(wǎng)絡(luò)上,或者使用身份驗(yàn)證和授權(quán)來保護(hù)訪問。
效果展示