赞
踩
新书速览|PyTorch深度学习与企业级项目实战-CSDN博客
本书案例比较丰富、比较完整,可以用于课题研究、毕业论文素材,值得大家收藏。
人脸表情是人类信息交流的重要方式,它所包含的人体行为信息与人的情感状态、精神状态、健康状态等有着极为密切的关联。因此,通过对人脸表情的识别可以获得很多有价值的信息,从而分析人类的心理活动和精神状态,并为各种机器视觉和人工智能控制系统的应用提供解决方案。 所以本项目在研究人脸面部表情识别的过程中,借助人工智能算法的优势开展基于深度神经网络的图像分类实验。
借助MobileNetv3模型进行迁移学习,经过足够多次的迭代,分类准确率可以达到90%。这里使用的MMAFEDB数据集包含128 000张幅MMA面部表情图像,数据集 MMAFEDB数据集还包含用于培训练、验证和测试的目录。 每个目录包含对应7个面部表情类别的7个子目录。
MMAFEDB数据集数据说明如下:
MMAFEDB数据集数据来源如下:
https://www.kaggle.com/mahmoudima/mma-facial-expression?select=MMAFEDB
相对重量级网络而言,轻量级网络的特点是参数少、计算量小、推理时间短,更适用于存储空间和功耗受限的场景,例如移动端嵌入式设备等边缘计算设备。因此,轻量级网络受到了广泛的关注,其中MobileNet可谓是其中的佼佼者。MobileNetV3经过了V1和V2前两代的积累,性能和速度都表现优异,受到学术界和工业界的追捧,无疑是轻量级网络的“抗把子”。
本项目这里加载预训练的MobileNetv3模型,由于预训练的模型与我们的任务需要不一样,因此需要修改最后的全连接层,将输出维度修改为我们的任务要求中的7个分类(7种面部表情)。 但是需要注意冻结其他层的参数,防止训练过程中将其改动,然后训练微调最后一层即可。
由于我们的任务为多分类问题,因此损失函数需要使用交叉熵损失函数(Cross Entropy),但是这里没有采用框架自带的损失函数,而是自己实现了一个损失函数。虽说大多数情况下,框架自带的损失函数就能够满足我们的需求,但是对于一些特定任务是无法满足的,需要我们进行自定义。自定义函数需要继承 nn.Module 子类,然后定义好参数和所需的变量,在forward方法中编写计算损失函数的过程,然后PyTorch会自动计算反向传播需要的梯度,不需要我们自己进行计算。
- ###########expression_on_face.py#####################
- import torchvision
- from torch import nn
- import numpy as np
- import os
- import pickle
- import torch
-
- from torchvision import transforms, datasets
- import torchvision.models as models
- from tqdm import tqdm
- from PIL import Image
- import matplotlib.pyplot as plt
-
- epochs = 10
- lr = 0.03
- batch_size = 32
- image_path = './The_expression_on_his_face/train'
- save_path = './chk/expression_model.pkl'
-
- device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
-
- # 1.数据转换
- data_transform = {
- # 训练中的数据增强和归一化
- 'train': transforms.Compose([
- transforms.RandomResizedCrop(224), # 随机裁剪
- transforms.RandomHorizontalFlip(), # 左右翻转
- transforms.ToTensor(),
- transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 均值方差归一化
- ])
- }
-
- # 2.形成训练集
- train_dataset = datasets.ImageFolder(root=os.path.join(image_path),
- transform=data_transform['train'])
-
- # 3.形成迭代器
- train_loader = torch.utils.data.DataLoader(train_dataset,
- batch_size,
- True)
-
- print('using {} images for training.'.format(len(train_dataset)))
-
- # 4.建立分类标签与索引的关系
- cloth_list = train_dataset.class_to_idx
- class_dict = {}
- for key, val in cloth_list.items():
- class_dict[val] = key
- with open('class_dict.pk', 'wb') as f:
- pickle.dump(class_dict, f)
-
- print(class_dict.values())
-
- # 自定义损失函数,需要在forward中定义过程
- class MyLoss(nn.Module):
- def __init__(self):
- super(MyLoss, self).__init__()
-
- # 参数为传入的预测值和真实值,返回所有样本的损失值
- # 自己只需定义计算过程,反向传播PyTroch会自动记录
- def forward(self, pred, label):
- # pred:[32, 4] label:[32, 1] 第一维度是样本数
-
- exp = torch.exp(pred)
- tmp1 = exp.gather(1, label.unsqueeze(-1)).squeeze()
- tmp2 = exp.sum(1)
- softmax = tmp1 / tmp2
- log = -torch.log(softmax)
- return log.mean()
-
- # 5.加载MobileNetv3模型
- #加载预训练好的MobileNetv3模型
- model = torchvision.models.mobilenet_v3_small(
- weights=models.MobileNet_V3_Small_Weights.DEFAULT)
- # 冻结模型参数
- for param in model.parameters():
- param.requires_grad = False
-
- # 修改最后一层的全连接层
- model.classifier[3] = nn.Linear(model.classifier[3].in_features, 7)
-
- # 将模型加载到cpu中
- model = model.to('cpu')
-
- # criterion = nn.CrossEntropyLoss() # 损失函数
- criterion = MyLoss()
- optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 优化器
-
- # 6.模型训练
- best_acc = 0 # 最优精确率
- best_model = None # 最优模型参数
-
- for epoch in range(epochs):
- model.train()
- running_loss = 0 # 损失
- epoch_acc = 0 # 每个epoch的准确率
- epoch_acc_count = 0 # 每个epoch训练的样本数
- train_count = 0 # 用于计算总的样本数,方便求准确率
- train_bar = tqdm(train_loader)
- for data in train_bar:
- images, labels = data
- optimizer.zero_grad()
- output = model(images.to(device))
- loss = criterion(output, labels.to(device))
- loss.backward()
- optimizer.step()
-
- running_loss += loss.item()
- train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
- epochs,
- loss)
- # 计算每个epoch正确的个数
- epoch_acc_count += (output.argmax(axis=1) == labels.view(-1)).sum()
- train_count += len(images)
-
- # 每个epoch对应的准确率
- epoch_acc = epoch_acc_count / train_count
-
- # 打印信息
- print("【EPOCH: 】%s" % str(epoch + 1))
- print("训练损失为%s" % str(running_loss))
- print("训练精度为%s" % (str(epoch_acc.item() * 100)[:5]) + '%')
-
- if epoch_acc > best_acc:
- best_acc = epoch_acc
- best_model = model.state_dict()
-
- # 在训练结束保存最优的模型参数
- if epoch == epochs - 1:
- # 保存模型
- torch.save(best_model, save_path)
-
- print('Finished Training')
-
- # 加载索引与标签映射字典
- with open('class_dict.pk', 'rb') as f:
- class_dict = pickle.load(f)
-
- # 数据变换
- data_transform = transforms.Compose(
- [transforms.Resize(256),
- transforms.CenterCrop(224),
- transforms.ToTensor()])
-
- # 图片路径
- img_path = r'./The_expression_on_his_face/test.jpg'
-
- # 打开图像
- #为了避免通道数不匹配,使用灰度图像(1通道),使用RGB图像(3通道)
- #解决方式:加载图像时,做一下转换
- img = Image.open(img_path).convert('RGB')
-
- # 对图像进行变换
- img = data_transform(img)
-
- plt.imshow(img.permute(1, 2, 0))
- plt.show()
-
- # 将图像升维,增加batch_size维度
- img = torch.unsqueeze(img, dim=0)
-
- # 获取预测结果
- pred = class_dict[model(img).argmax(axis=1).item()]
- print('【预测结果分类】:%s' % pred)
代码运行结果如下:
- using 851 images for training.
- dict_values(['angry', 'disgust', 'fear', 'happy', 'neutral', 'sad', 'surprise'])
- train epoch[1/10] loss:1.943: 100%|██████████| 27/27 [00:10<00:00, 2.65it/s]
- 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】1
- 训练损失为54.592151284217834
- 训练精度为23.14%
- train epoch[2/10] loss:1.906: 100%|██████████| 27/27 [00:10<00:00, 2.50it/s]
- 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】2
- 训练损失为51.95514786243439
- 训练精度为27.96%
- train epoch[3/10] loss:1.873: 100%|██████████| 27/27 [00:10<00:00, 2.68it/s]
- 【EPOCH: 】3
- 训练损失为54.413649916648865
- 训练精度为29.96%
- train epoch[4/10] loss:1.508: 100%|██████████| 27/27 [00:10<00:00, 2.60it/s]
- 【EPOCH: 】4
- 训练损失为51.14111852645874
- 训练精度为30.66%
- train epoch[5/10] loss:1.816: 100%|██████████| 27/27 [00:13<00:00, 2.05it/s]
- 【EPOCH: 】5
- 训练损失为52.17003357410431
- 训练精度为32.07%
- train epoch[6/10] loss:1.833: 100%|██████████| 27/27 [00:11<00:00, 2.31it/s]
- 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】6
- 训练损失为51.988134145736694
- 训练精度为31.37%
- train epoch[7/10] loss:1.907: 100%|██████████| 27/27 [00:10<00:00, 2.49it/s]
- 【EPOCH: 】7
- 训练损失为51.65321123600006
- 训练精度为32.54%
- train epoch[8/10] loss:1.993: 100%|██████████| 27/27 [00:11<00:00, 2.40it/s]
- 【EPOCH: 】8
- 训练损失为51.17294144630432
- 训练精度为33.72%
- train epoch[9/10] loss:1.682: 100%|██████████| 27/27 [00:13<00:00, 2.02it/s]
- 【EPOCH: 】9
- 训练损失为52.21281313896179
- 训练精度为29.49%
- train epoch[10/10] loss:1.926: 100%|██████████| 27/27 [00:15<00:00, 1.75it/s]
- 【EPOCH: 】10
- 训练损失为50.530142426490784
- 训练精度为32.43%
- Finished Training
- 【预测结果分类】:angry
注意,这里只是列出计算10个周期,如果需要提高训练精度,需要增加训练周期100个以及扩大训练样本量。读者可以自行尝试。
《PyTorch深度学习与企业级项目实战(人工智能技术丛书)》(宋立桓,宋立林)【摘要 书评 试读】- 京东图书 (jd.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。