人臉表情識別是通過神經(jīng)網(wǎng)絡(luò)從圖像中提取表情特征,并將表情歸為某一類別的學(xué)習(xí)任務(wù),是分類任務(wù)的一種實際應(yīng)用。它能夠更準(zhǔn)確地理解用戶的情感狀態(tài),并提供個性化服務(wù)。目前,人臉表情識別技術(shù)已經(jīng)應(yīng)用于眾多領(lǐng)域,如智能交互、虛擬現(xiàn)實等。隨著技術(shù)的不斷發(fā)展,深度學(xué)習(xí)模型將持續(xù)優(yōu)化,不斷提高識別準(zhǔn)確率和效率,并與其他技術(shù)結(jié)合,如增強學(xué)習(xí)、遷移學(xué)習(xí)等,進一步提升性能,為人機交互帶來更好的體驗。
01、人臉表情數(shù)據(jù)準(zhǔn)備
在本文中,我們使用JAFFE(The Japanese Female Facial Expression)數(shù)據(jù)集。該數(shù)據(jù)集發(fā)布于1998年,是一個小型的人臉圖像數(shù)據(jù)集,共包含213張圖片。JAFFE數(shù)據(jù)集選取了10名日本女學(xué)生,每個人根據(jù)指示在實驗環(huán)境下做出7種表情,包括:憤怒(Angry,AN)、厭惡(Disgust,DI)、恐懼(Fear,F(xiàn)E)、高興(Happy,HA)、悲傷(Sad,SA)、驚訝(Surprise,SU)以及中性(Neutral,NE)。
創(chuàng)建項目文件夾后,假設(shè)將下載好的數(shù)據(jù)集放入該項目文件夾中,目錄地址為"./jaffe"。根據(jù)實驗的需要,我們先對數(shù)據(jù)集進行簡單的劃分,劃分后的地址為"./data/jaffe",后續(xù)訓(xùn)練則使用該劃分后的目錄地址。
首先導(dǎo)入所需要的工具包:
import os
import wandb
import random
import shutil
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader
下面對數(shù)據(jù)集進行劃分。數(shù)據(jù)集按照4:1的比例分別組成互斥的訓(xùn)練集train和測試集test。訓(xùn)練集和測試集的圖片都按照類別分類存儲在不同文件夾中,七個不同的類對應(yīng)七個不同的文件夾。每個類別的圖片在訓(xùn)練集和測試集中的比例都是4:1,以保持數(shù)據(jù)分布的一致性。詳細代碼如下:
# 對應(yīng)其中類別
classes = ['NE','HA','AN','DI','FE','SA','SU']
folder_names = ['train', 'test']
# 未劃分的數(shù)據(jù)集地址
src_data_folder = "./jaffe"
# 劃分后的數(shù)據(jù)集保存地址
target_data_folder = "./data/jaffe"
# 劃分比例
train_scale = 0.8
# 在目標(biāo)目錄下創(chuàng)建訓(xùn)練集和驗證集文件夾
for folder_name in folder_names:
folder_path = os.path.join(target_data_folder, folder_name)
os.mkdir(folder_path)
# 在folder_path目錄下創(chuàng)建類別文件夾
????for class_name in classes:
class_folder_path = os.path.join(folder_path, class_name)
os.mkdir(class_folder_path)
# 獲取所有的圖片
files = os.listdir(src_data_folder)
data = [file for file in files if file.endswith('tiff') and not file.startswith('.')]
# 隨機打亂圖片順序
random.shuffle(data)
# 統(tǒng)計保存各類圖片數(shù)量
class_sum = dict.fromkeys(classes, 0)
for file in data:
class_sum[file[3:5]] += 1
# 記錄訓(xùn)練集各類別圖片的個數(shù)
class_train = dict.fromkeys(classes, 0)
# 記錄測試集各類別圖片的個數(shù)
class_test = dict.fromkeys(classes, 0)
# 遍歷每個圖片劃分
for file in data:
# 得到原圖片目錄地址
????src_img_path = os.path.join(src_data_folder, file)
# 如果訓(xùn)練集中該類別個數(shù)未達劃分數(shù)量,則復(fù)制圖片并分配進入訓(xùn)練集
????if class_train[file[3:5]] < class_sum[file[3:5]]*train_scale:
target_img_path = os.path.join(os.path.join(target_data_folder, 'train'), file[3:5])
shutil.copy2(src_img_path, target_img_path)
class_train[file[3:5]] += 1
# 否則,進入測試集
????else:
target_img_path = os.path.join(os.path.join(target_data_folder, 'test'), file[3:5])
shutil.copy2(src_img_path, target_img_path)
class_test[file[3:5]] += 1
# 輸出標(biāo)明數(shù)據(jù)集劃分情況
for class_name in classes:
print("-"?* 10)
print("{}類共{}張圖片,劃分完成:".format(class_name, class_sum[class_name]))
print("訓(xùn)練集:{}張,測試集:{}張".format(class_train[class_name], class_test[class_name]))
使用上述代碼劃分好的數(shù)據(jù)集格式如圖1所示:
圖1 數(shù)據(jù)集劃分后的格式
通過調(diào)用torchvision.transforms模塊,對上述劃分的數(shù)據(jù)集進行預(yù)處理,并使用ImageFolder數(shù)據(jù)加載器加載數(shù)據(jù)。ImageFolder是一個通用的圖像數(shù)據(jù)加載器,它可以加載如上述格式般分類存儲的數(shù)據(jù),并對圖像類別進行預(yù)處理操作。按照分類后文件夾的順序返回從0到n(n為類別數(shù)量)的索引,該索引就是各類別文件夾中圖像的分類標(biāo)簽。代碼如下:
# 數(shù)據(jù)加載及預(yù)處理
transform_train = transforms.Compose([
transforms.Resize(32),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
transform_test = transforms.Compose([
transforms.Resize(32),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 加載數(shù)據(jù)
train_set = ImageFolder(
root="./data/jaffe/train",
transform=transform_train
)
test_set = ImageFolder(
root="./data/jaffe/test",
transform=transform_test
)
train_loader = DataLoader(
train_set, batch_size=8, shuffle=True)
test_loader = DataLoader(
test_set, batch_size=8, shuffle=False)
02、基于ResNet神經(jīng)網(wǎng)絡(luò)的人臉表情識別
(一)網(wǎng)絡(luò)定義
在本文中,使用ResNet-18網(wǎng)絡(luò)進行訓(xùn)練。因為JAFFE數(shù)據(jù)集中只有七個類別,所以輸出層只需要七個神經(jīng)元,即num_classes等于7。
# ResNet-18生成方法
def ResNet-18(num_classes = 1000):
model = ResNet(BasicBlock, [2, 2, 2, 2], num_classes)
return model
net = ResNet-18(num_classes=7)
網(wǎng)絡(luò)也可以調(diào)用Pytorch中torchvision.models模塊中集成的ResNet網(wǎng)絡(luò),通過簡單的調(diào)用就可以使用,效果與上述代碼是相同的。在調(diào)用torchvision.models模塊中的ResNet網(wǎng)絡(luò)時,輸出層的num_classes參數(shù)也需要設(shè)置為7。代碼如下:
from torchvision.models import ResNet-18
net = ResNet-18(num_classes = 7)
(二)整體訓(xùn)練流程在模型的訓(xùn)練過程中,使用PyTorch中的nn.CrossEntropyLoss()計算損失,使用Adam優(yōu)化器對網(wǎng)絡(luò)參數(shù)進行優(yōu)化。以下是人臉表情識別任務(wù)的訓(xùn)練代碼:
if __name__ == "__main__":
# 定義訓(xùn)練使用的設(shè)備
????device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net = ResNet-18(num_classes=7)
train(net, train_loader, test_loader, device, l_r=0.00003, num_epochs=30)
更多內(nèi)容,敬請關(guān)注下方圖書!
▊《深度學(xué)習(xí)與人工智能實戰(zhàn)》
張重生 編著
本書按照知識由淺入深、循序漸進的規(guī)律編寫而成。內(nèi)容分為三大部分,第一部分是Python和PyTorch編程基礎(chǔ),介紹常用的函數(shù)及其用法;第二部分是初級深度學(xué)習(xí)算法與技術(shù),含基礎(chǔ)卷積神經(jīng)網(wǎng)絡(luò)的實現(xiàn),目標(biāo)識別、人臉表情識別等實戰(zhàn);第三部分是高級深度學(xué)習(xí)算法和技術(shù),含孿生神經(jīng)網(wǎng)絡(luò)、度量學(xué)習(xí)、蒸餾學(xué)習(xí)、目標(biāo)檢測、圖像分割、圖像生成等技術(shù)及實戰(zhàn)。本書的附錄還提供了常用PyTorch函數(shù)速查手冊。本書根據(jù)深度學(xué)習(xí)技術(shù)的特點,將內(nèi)容劃分為數(shù)據(jù)準(zhǔn)備、神經(jīng)網(wǎng)絡(luò)模型實現(xiàn)、損失函數(shù)實現(xiàn)、整體訓(xùn)練流程和效果展示五部分。這種章節(jié)內(nèi)容安排方式邏輯清楚,可操作性強、更易理解。
撰? 稿? 人:楊健亭責(zé)任編輯: 李馨馨審? 核? 人:曹新宇