日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pytorch实现性别检测

發(fā)布時間:2025/3/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pytorch实现性别检测 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
卷積神經(jīng)網(wǎng)絡(luò)的訓(xùn)練是耗時的,很多場合不可能每次都從隨機初始化參數(shù)開始訓(xùn)練網(wǎng)絡(luò)。 1.訓(xùn)練 pytorch中自帶幾種常用的深度學(xué)習(xí)網(wǎng)絡(luò)預(yù)訓(xùn)練模型,如VGG、ResNet等。往往為了加快學(xué)習(xí)的進度,在訓(xùn)練的初期我們直接加載pre-train模型中預(yù)先訓(xùn)練好的參數(shù),所以這里使用的網(wǎng)絡(luò)是: torchvision.models.Resnet34(pretrained=True)

然后更改其最后的全連接層。因為resnet網(wǎng)絡(luò)最后一層分類層fc是對1000種類型進行劃分,對于自己的數(shù)據(jù)集,這里進行的是性別檢測,只有男/女2類,所以修改的代碼為:

#提取fc層中固定的參數(shù) fc_features = model.fc.in_features #修改類別為2 model.fc = nn.Linear(fc_features, 2)

?

在網(wǎng)上看見一些教程僅對最后一層全連接層的參數(shù)進行訓(xùn)練,所以他們的設(shè)定為:

#凍結(jié)參數(shù),不訓(xùn)練卷積層網(wǎng)絡(luò) for param in model_conv.parameters():param.requires_grad = False

然后下面就是定義你使用的損失函數(shù),優(yōu)化器和學(xué)習(xí)率調(diào)整的算法:

注意在這里可以看見優(yōu)化器中輸入的參數(shù)為model_conv.fc.parameters(),即僅對全連接層fc的參數(shù)進行調(diào)參

#定義使用的損失函數(shù)為交叉熵代價函數(shù) criterion = nn.CrossEntropyLoss() #定義使用的優(yōu)化器 optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.0001, momentum=0.9) #設(shè)置自動遞減的學(xué)習(xí)率,等間隔調(diào)整學(xué)習(xí)率,即在25個step時,將學(xué)習(xí)率調(diào)整為 lr*gamma exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=25, gamma=0.1)

?

但是我訓(xùn)練過程發(fā)現(xiàn)這樣做的效果不是很好,我還是對整個網(wǎng)絡(luò)的參數(shù)都進行了訓(xùn)練,所以我沒有進行凍結(jié)參數(shù)的設(shè)定,同時使用的算法中傳入的參數(shù)是model_conv.parameters()

這樣得到的最好訓(xùn)練結(jié)果是:

train Loss: 0.1020 Acc: 0.9617 val Loss: 0.0622 Acc: 0.9820 Training complete in 336m 56s Best val Acc: 0.982000

可見其實還沒有訓(xùn)練完,還是欠擬合的狀態(tài)

??補充知識:optimizer.step()和scheduler.step()的區(qū)別:
optimizer.step()通常用在每個mini-batch之中,而scheduler.step()通常用在epoch里面,但是不絕對,可以根據(jù)具體的需求來做。只有用了optimizer.step(),模型才會更新,而scheduler.step()是對lr進行調(diào)整。

?

然后后面我調(diào)了一下優(yōu)化器,從momentum改成了Adam,并將學(xué)習(xí)率的調(diào)整step_size更改為20,讓其一開始能更快收斂:

#定義的優(yōu)化器 optimizer_conv = optim.Adam(model_conv.parameters(), lr=0.0001, betas=(0.9, 0.99)) #設(shè)置自動遞減的學(xué)習(xí)率,等間隔調(diào)整學(xué)習(xí)率,即在20個step時,將學(xué)習(xí)率調(diào)整為 lr*gamma exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=20, gamma=0.1)

?運行結(jié)果優(yōu)化為:

train Loss: 0.0668 Acc: 0.9725 val Loss: 0.0630 Acc: 0.9820 Training complete in 385m 42s Best val Acc: 0.986000

?可見效果好了一點,但是還是沒能訓(xùn)練完,之后又對代碼進行了更改,將step_size調(diào)節(jié)得更大,使得一開始能夠收斂得快一些,以免后面的學(xué)習(xí)率過小后一直收斂不下去:

optimizer_conv = optim.Adam(model_conv.parameters(), lr=0.0001, betas=(0.9, 0.99)) #設(shè)置自動遞減的學(xué)習(xí)率,等間隔調(diào)整學(xué)習(xí)率,即在45個step時,將學(xué)習(xí)率調(diào)整為 lr*gamma exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=45, gamma=0.1)

判斷的代碼也進行了更改,不再是以最高的val acc作為最優(yōu)參數(shù)的選擇,而是選擇train acc最高且train acc大于val acc的訓(xùn)練參數(shù):

# deep copy the model# 對模型進行深度復(fù)制if phase == 'train' and epoch_acc > best_train_acc:temp = epoch_accif phase =='val' and epoch_acc > 0 and epoch_acc < temp:best_train_acc = tempbest_val_acc = epoch_accbest_iteration = epochbest_model_wts = copy.deepcopy(model.state_dict())

這樣的返回值果然更好了一點:

Training complete in 500m 10s Best epoch: 166.000000 Best train Acc: 0.985175 Best val Acc: 0.984000

?

代碼運行過程中出現(xiàn)了錯誤:

RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same

這個的解決辦法是為model_conv也添加.to(device):

model_conv.to(device)

?

另一個錯誤是:

RuntimeError: Expected object of backend CPU but got backend CUDA for argument #4 'mat1'

覺得原因可能是因為我的機器上面只有一個cuda,所以要顯示指明使用的是'cuda:0':

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

或者是因為一開始我將model_conv.to(device)寫錯了位置,寫到了model_conv.fc = nn.Linear(fc_features, 2)之前,寫到其后面即可

?

所以最后的訓(xùn)練代碼為: # coding:utf8 from torchvision import datasets, models from torch import nn, optim from torchvision import transforms as T from torch.utils import dataimport os import copy import time import torch#首先進行數(shù)據(jù)的處理 data_dir = './data' device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#轉(zhuǎn)換圖片數(shù)據(jù) normalize = T.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]) data_transforms ={'train': T.Compose([T.RandomResizedCrop(224),#從圖片中心截取T.RandomHorizontalFlip(),#隨機水平翻轉(zhuǎn)給定的PIL.Image,翻轉(zhuǎn)概率為0.5 T.ToTensor(),#轉(zhuǎn)成Tensor格式,大小范圍為[0,1]normalize]),'val': T.Compose([T.Resize(256),#重新設(shè)定大小 T.CenterCrop(224),T.ToTensor(),normalize]), }#加載圖片 #man的label為0, woman的label為1 image_datasets = {x : datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']}#得到train和val中的數(shù)據(jù)量 dataset_sizes = {x : len(image_datasets[x].imgs) for x in ['train', 'val']} dataloaders = {x : data.DataLoader(image_datasets[x], batch_size=4, shuffle=True,num_workers=4) for x in ['train', 'val']}#然后選擇使用的模型 model_conv = models.resnet34(pretrained=True) #凍結(jié)參數(shù),不訓(xùn)練卷積層網(wǎng)絡(luò) #for param in model_conv.parameters(): # param.requires_grad = False#提取fc全連接層中固定的參數(shù),后面的訓(xùn)練只對全連接層的參數(shù)進行優(yōu)化 fc_features = model_conv.fc.in_features #修改類別為2,即man和woman model_conv.fc = nn.Linear(fc_features, 2) model_conv.to(device) #定義使用的損失函數(shù)為交叉熵代價函數(shù) criterion = nn.CrossEntropyLoss() #定義使用的優(yōu)化器 #optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.0001, momentum=0.9) #optimizer_conv = optim.SGD(model_conv.parameters(), lr=0.0001, momentum=0.9) optimizer_conv = optim.Adam(model_conv.parameters(), lr=0.0001, betas=(0.9, 0.99)) #設(shè)置自動遞減的學(xué)習(xí)率,等間隔調(diào)整學(xué)習(xí)率,即在7個step時,將學(xué)習(xí)率調(diào)整為 lr*gamma exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=45, gamma=0.1) #exp_lr_scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer_conv, mode='min', verbose=True)# 訓(xùn)練模型 # 參數(shù)說明: # model:待訓(xùn)練的模型 # criterion:評價函數(shù) # optimizer:優(yōu)化器 # scheduler:學(xué)習(xí)率 # num_epochs:表示實現(xiàn)完整訓(xùn)練的次數(shù),一個epoch表示一整個訓(xùn)練周期 def train_model(model, criterion, optimizer, scheduler, num_epochs=200):# 定義訓(xùn)練開始時間since = time.time()#用于保存最優(yōu)的權(quán)重best_model_wts = copy.deepcopy(model.state_dict())#最優(yōu)精度值best_train_acc = 0.0best_val_acc = 0.0best_iteration = 0# # meters,統(tǒng)計指標(biāo):平滑處理之后的損失,還有混淆矩陣# loss_meter = meter.AverageValueMeter()#能夠計算所有數(shù)的平均值和標(biāo)準(zhǔn)差,用來統(tǒng)計一個epoch中損失的平均值# confusion_matrix = meter.ConfusionMeter(2)#用來統(tǒng)計分類問題中的分類情況,是一個比準(zhǔn)確率更詳細的統(tǒng)計指標(biāo)# 對整個數(shù)據(jù)集進行num_epochs次訓(xùn)練for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)#用于存儲train acc還沒有與val acc比較之前的值temp = 0# Each epoch has a training and validation phase# 每輪訓(xùn)練訓(xùn)練包含`train`和`val`的數(shù)據(jù)for phase in ['train', 'val']:if phase == 'train':# 學(xué)習(xí)率步進scheduler.step()# 設(shè)置模型的模式為訓(xùn)練模式(因為在預(yù)測模式下,采用了`Dropout`方法的模型會關(guān)閉部分神經(jīng)元)model.train() # Set model to training modeelse:# 預(yù)測模式model.eval() # Set model to evaluate moderunning_loss = 0.0running_corrects = 0# Iterate over data.# 遍歷數(shù)據(jù),這里的`dataloaders`近似于一個迭代器,每一次迭代都生成一批`inputs`和`labels`數(shù)據(jù),# 一批有四個圖片,一共有dataset_sizes['train']/4或dataset_sizes['val']/4批# 這里循環(huán)幾次就看有幾批數(shù)據(jù)for inputs, labels in dataloaders[phase]:inputs = inputs.to(device) # 當(dāng)前批次的訓(xùn)練輸入 labels = labels.to(device) # 當(dāng)前批次的標(biāo)簽輸入# print('input : ', inputs)# print('labels : ', labels)# 將梯度參數(shù)歸0optimizer.zero_grad()# 前向計算# track history if only in trainwith torch.set_grad_enabled(phase == 'train'):# 相應(yīng)輸入對應(yīng)的輸出outputs = model(inputs)# print('outputs : ', outputs)# 取輸出的最大值作為預(yù)測值preds,dim=1,得到每行中的最大值的位置索引,用來判別其為0或1_, preds = torch.max(outputs, 1)# print('preds : ', preds)# 計算預(yù)測的輸出與實際的標(biāo)簽之間的誤差loss = criterion(outputs, labels)# backward + optimize only if in training phaseif phase == 'train':# 對誤差進行反向傳播loss.backward()#scheduler.step(loss) #當(dāng)使用的學(xué)習(xí)率遞減函數(shù)為optim.lr_scheduler.ReduceLROnPlateau時,使用在這里# 執(zhí)行優(yōu)化器對梯度進行優(yōu)化optimizer.step()# loss_meter.add(loss.item())# confusion_matrix.add(outputs.detach(), labels.detach()) # statistics# 計算`running_loss`和`running_corrects`#loss.item()得到的是此時損失loss的值#inputs.size(0)得到的是一批圖片的數(shù)量,這里為4#兩者相乘得到的是4張圖片的總損失#疊加得到所有數(shù)據(jù)的損失running_loss += loss.item() * inputs.size(0)#torch.sum(preds == labels.data)判斷得到的結(jié)果中有幾個正確,running_corrects得到四個中正確的個數(shù)#疊加得到所有數(shù)據(jù)中判斷成功的個數(shù)running_corrects += torch.sum(preds == labels.data)# 當(dāng)前輪的損失,除以所有數(shù)據(jù)量個數(shù)得到平均loss值epoch_loss = running_loss / dataset_sizes[phase]# 當(dāng)前輪的精度,除以所有數(shù)據(jù)量個數(shù)得到平均準(zhǔn)確度epoch_acc = running_corrects.double() / dataset_sizes[phase]print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))# deep copy the model# 對模型進行深度復(fù)制 if phase == 'train' and epoch_acc > best_train_acc:temp = epoch_accif phase =='val' and epoch_acc > 0 and epoch_acc < temp:best_train_acc = tempbest_val_acc = epoch_accbest_iteration = epochbest_model_wts = copy.deepcopy(model.state_dict())# 計算訓(xùn)練所需要的總時間time_elapsed = time.time() - sinceprint('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))print('Best epoch: {:4f}'.format(best_iteration)) print('Best train Acc: {:4f}'.format(best_train_acc)) print('Best val Acc: {:4f}'.format(best_val_acc))# load best model weights# 加載模型的最優(yōu)權(quán)重model.load_state_dict(best_model_wts)return modelif __name__ == '__main__':model_train = train_model(model_conv, criterion, optimizer_conv, exp_lr_scheduler)torch.save(model_train, 'GenderTest.pkl')

?

2.測試

使用上面生成的GenderTest.pkl進行測試:

測試數(shù)據(jù)集dataset_test.py的設(shè)計為:

# coding:utf8 import os from torchvision import transforms as T from PIL import Image from torch.utils import dataclass GenderData(data.Dataset):def __init__(self, root, transforms=None):#將圖片路徑存儲在imgs列表中imgs = [os.path.join(root, img) for img in os.listdir(root)]self.imgs = imgsif transforms is None:#設(shè)置對數(shù)據(jù)進行轉(zhuǎn)換的transformnormalize = T.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])self.transforms = T.Compose([T.Resize(224),T.CenterCrop(224),T.ToTensor(),normalize])def __getitem__(self, index):img_path = self.imgs[index]#得到圖片數(shù)據(jù)data = Image.open(img_path)#對數(shù)據(jù)進行轉(zhuǎn)換data = self.transforms(data)return datadef __len__(self):return len(self.imgs)

?

測試代碼test.py為:

# coding:utf8 import visdom from datasets_test import GenderData from torch.utils import data from torchvision.utils import make_grid import torchdef visualize(data, preds):viz = visdom.Visdom(env='main')# print(data.size()) #一開始的大小為torch.Size([4, 3, 224, 224])out = make_grid(data) #這樣得到的輸出的數(shù)據(jù)就是將四張圖合成了一張圖的大小,為# print(out.size()) #torch.Size([3, 228, 906])#因為反標(biāo)準(zhǔn)化時需要將圖片的維度從(channels,imgsize,imgsieze)變成(imgsize,imgsieze,channels),這樣才能與下面的std,mean正確計算inp = torch.transpose(out, 0, 2)# print(inp.size()) #返回torch.Size([906, 228, 3])mean = torch.FloatTensor([0.485, 0.456, 0.406])std = torch.FloatTensor([0.229, 0.224, 0.225])inp = std * inp + mean#計算完后還是要將維度變回來,所以再進行一次轉(zhuǎn)換inp = torch.transpose(inp, 0, 2)# print(inp.size()) #返回torch.Size([3, 228, 906])#注意,這里是因為設(shè)置了batch_size為四,所以title中才這樣,如果你的batch_size不是4這里需要做一些更改viz.images(inp, opts=dict(title='{},{},{},{}'.format(preds[0].item(), preds[1].item(), preds[2].item(), preds[3].item())))#比如下面這個就是將batch_size改成1的結(jié)果# viz.images(inp, opts=dict(title='{}'.format(preds[0].item())))def self_dataset():data_test_root = './data/test1' #測試數(shù)據(jù)集所在的路徑test_data = GenderData(data_test_root)
#如果只測試一張圖片,這里batch_size要改成1dataloaders
= data.DataLoader(test_data, batch_size=4 ,shuffle=True,num_workers=4)for inputs in dataloaders:inputs = inputs.to(device) # 當(dāng)前批次的訓(xùn)練輸入 outputs = model_test(inputs)_, preds = torch.max(outputs, 1)visualize(inputs,preds)if __name__ == '__main__':device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')print(device)#導(dǎo)入上面訓(xùn)練得到的效果最佳的網(wǎng)絡(luò),因為測試是在只有cpu的機器上跑的,所以這里要添加map_location='cpu'model_test = torch.load('./GenderTest.pkl',map_location='cpu')#如果你是在有GPU的機器上跑的,可以刪掉map_location='cpu',并添加一行#model_test.to(device)model_test.eval()dataloaders = self_dataset()

?要將visdom打開:

python -m visdom.server

然后運行:

python test.py

即可以在visdom中看見結(jié)果,如下面的圖片被判斷為女生,右上角顯示1:

?當(dāng)然,這其實是國榮哥的劇照,只能說天生麗質(zhì)的,應(yīng)該不是我訓(xùn)練的效果問題


測試時出現(xiàn)一個問題:

OSError: cannot identify image file './data/test/.DS_Store'

這是因為mac系統(tǒng)中會自動生成一個.DS_Store隱藏文件,這里保存著針對這個目錄的特殊信息和設(shè)置配置,例如查看方式、圖標(biāo)大小以及這個目錄的一些附屬元數(shù)據(jù)

而當(dāng)我們想要打開圖片的時候它會被當(dāng)作一個圖片文件路徑加載,進而報錯,因為它并不是一個圖片文件,解決辦法是在該圖片文件夾下輸入刪除命令:

sudo find / -name ".DS_Store" -depth -exec rm {} \;

?或者更簡單的方法是到圖片文件夾處直接運行:

rm .DS_Store

?

后面換成使用resnet18也能達到相近的效果,大家可以試試

?

?


?

轉(zhuǎn)載于:https://www.cnblogs.com/wanghui-garcia/p/10679089.html

總結(jié)

以上是生活随笔為你收集整理的pytorch实现性别检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。