当前位置:   article > 正文

PyTorch面部表情识别项目实战

PyTorch面部表情识别项目实战

新书速览|PyTorch深度学习与企业级项目实战-CSDN博客

本书案例比较丰富、比较完整,可以用于课题研究、毕业论文素材,值得大家收藏。

人脸表情是人类信息交流的重要方式,它所包含的人体行为信息与人的情感状态、精神状态、健康状态等有着极为密切的关联。因此,通过对人脸表情的识别可以获得很多有价值的信息,从而分析人类的心理活动和精神状态,并为各种机器视觉和人工智能控制系统的应用提供解决方案。 所以本项目在研究人脸面部表情识别的过程中,借助人工智能算法的优势开展基于深度神经网络的图像分类实验。

借助MobileNetv3模型进行迁移学习,经过足够多次的迭代,分类准确率可以达到90%。这里使用的MMAFEDB数据集包含128 000MMA面部表情图像数据集 MMAFEDB数据集包含用于、验证和测试的目录。 每个目录包含对应7个面部表情类别的7个子目录。

MMAFEDB数据集数据说明如下:

  1. Angry:愤怒。
  2. Disgust:厌恶。
  3. Fear:恐惧。
  4. Happy:快乐。
  5. Neutral:中性。
  6. Sad:悲伤。
  7. Surprise:惊讶。

MMAFEDB数据集数据来源如下:

https://www.kaggle.com/mahmoudima/mma-facial-expression?select=MMAFEDB

相对重量级网络而言,轻量级网络的特点是参数少、计算量小、推理时间短,更适用于存储空间和功耗受限的场景,例如移动端嵌入式设备等边缘计算设备。因此,轻量级网络受到了广泛的关注,其中MobileNet可谓是其中的佼佼者。MobileNetV3经过了V1和V2前两代的积累,性能和速度都表现优异,受到学术界和工业界的追捧,无疑是轻量级网络的“抗把子”。

本项目这里加载预训练的MobileNetv3模型,由于预训练的模型与我们的任务需要不一样,因此需要修改最后的全连接层,将输出维度修改为我们的任务要求中的7个分类(7种面部表情)。 但是需要注意冻结其他层的参数,防止训练过程中将其改动,然后训练微调最后一层即可。

由于我们的任务为多分类问题,因此损失函数需要使用交叉熵损失函数(Cross Entropy),但是这里没有采用框架自带的损失函数,而是自己实现了一个损失函数。虽说大多数情况下,框架自带的损失函数就能够满足我们的需求,但是对于一些特定任务是无法满足的,需要我们进行自定义。自定义函数需要继承 nn.Module 子类,然后定义好参数和所需的变量,在forward方法中编写计算损失函数的过程,然后PyTorch会自动计算反向传播需要的梯度,不需要我们自己进行计算。

  1. ###########expression_on_face.py#####################
  2. import torchvision
  3. from torch import nn
  4. import numpy as np
  5. import os
  6. import pickle
  7. import torch
  8. from torchvision import transforms, datasets
  9. import torchvision.models as models
  10. from tqdm import tqdm
  11. from PIL import Image
  12. import matplotlib.pyplot as plt
  13. epochs = 10
  14. lr = 0.03
  15. batch_size = 32
  16. image_path = './The_expression_on_his_face/train'
  17. save_path = './chk/expression_model.pkl'
  18. device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
  19. # 1.数据转换
  20. data_transform = {
  21. # 训练中的数据增强和归一化
  22. 'train': transforms.Compose([
  23. transforms.RandomResizedCrop(224), # 随机裁剪
  24. transforms.RandomHorizontalFlip(), # 左右翻转
  25. transforms.ToTensor(),
  26. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 均值方差归一化
  27. ])
  28. }
  29. # 2.形成训练集
  30. train_dataset = datasets.ImageFolder(root=os.path.join(image_path),
  31. transform=data_transform['train'])
  32. # 3.形成迭代器
  33. train_loader = torch.utils.data.DataLoader(train_dataset,
  34. batch_size,
  35. True)
  36. print('using {} images for training.'.format(len(train_dataset)))
  37. # 4.建立分类标签与索引的关系
  38. cloth_list = train_dataset.class_to_idx
  39. class_dict = {}
  40. for key, val in cloth_list.items():
  41. class_dict[val] = key
  42. with open('class_dict.pk', 'wb') as f:
  43. pickle.dump(class_dict, f)
  44. print(class_dict.values())
  45. # 自定义损失函数,需要在forward中定义过程
  46. class MyLoss(nn.Module):
  47. def __init__(self):
  48. super(MyLoss, self).__init__()
  49. # 参数为传入的预测值和真实值,返回所有样本的损失值
  50. # 自己只需定义计算过程,反向传播PyTroch会自动记录
  51. def forward(self, pred, label):
  52. # pred:[32, 4] label:[32, 1] 第一维度是样本数
  53. exp = torch.exp(pred)
  54. tmp1 = exp.gather(1, label.unsqueeze(-1)).squeeze()
  55. tmp2 = exp.sum(1)
  56. softmax = tmp1 / tmp2
  57. log = -torch.log(softmax)
  58. return log.mean()
  59. # 5.加载MobileNetv3模型
  60. #加载预训练好的MobileNetv3模型
  61. model = torchvision.models.mobilenet_v3_small(
  62. weights=models.MobileNet_V3_Small_Weights.DEFAULT)
  63. # 冻结模型参数
  64. for param in model.parameters():
  65. param.requires_grad = False
  66. # 修改最后一层的全连接层
  67. model.classifier[3] = nn.Linear(model.classifier[3].in_features, 7)
  68. # 将模型加载到cpu中
  69. model = model.to('cpu')
  70. # criterion = nn.CrossEntropyLoss() # 损失函数
  71. criterion = MyLoss()
  72. optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 优化器
  73. # 6.模型训练
  74. best_acc = 0 # 最优精确率
  75. best_model = None # 最优模型参数
  76. for epoch in range(epochs):
  77. model.train()
  78. running_loss = 0 # 损失
  79. epoch_acc = 0 # 每个epoch的准确率
  80. epoch_acc_count = 0 # 每个epoch训练的样本数
  81. train_count = 0 # 用于计算总的样本数,方便求准确率
  82. train_bar = tqdm(train_loader)
  83. for data in train_bar:
  84. images, labels = data
  85. optimizer.zero_grad()
  86. output = model(images.to(device))
  87. loss = criterion(output, labels.to(device))
  88. loss.backward()
  89. optimizer.step()
  90. running_loss += loss.item()
  91. train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
  92. epochs,
  93. loss)
  94. # 计算每个epoch正确的个数
  95. epoch_acc_count += (output.argmax(axis=1) == labels.view(-1)).sum()
  96. train_count += len(images)
  97. # 每个epoch对应的准确率
  98. epoch_acc = epoch_acc_count / train_count
  99. # 打印信息
  100. print("【EPOCH: 】%s" % str(epoch + 1))
  101. print("训练损失为%s" % str(running_loss))
  102. print("训练精度为%s" % (str(epoch_acc.item() * 100)[:5]) + '%')
  103. if epoch_acc > best_acc:
  104. best_acc = epoch_acc
  105. best_model = model.state_dict()
  106. # 在训练结束保存最优的模型参数
  107. if epoch == epochs - 1:
  108. # 保存模型
  109. torch.save(best_model, save_path)
  110. print('Finished Training')
  111. # 加载索引与标签映射字典
  112. with open('class_dict.pk', 'rb') as f:
  113. class_dict = pickle.load(f)
  114. # 数据变换
  115. data_transform = transforms.Compose(
  116. [transforms.Resize(256),
  117. transforms.CenterCrop(224),
  118. transforms.ToTensor()])
  119. # 图片路径
  120. img_path = r'./The_expression_on_his_face/test.jpg'
  121. # 打开图像
  122. #为了避免通道数不匹配,使用灰度图像(1通道),使用RGB图像(3通道)
  123. #解决方式:加载图像时,做一下转换
  124. img = Image.open(img_path).convert('RGB')
  125. # 对图像进行变换
  126. img = data_transform(img)
  127. plt.imshow(img.permute(1, 2, 0))
  128. plt.show()
  129. # 将图像升维,增加batch_size维度
  130. img = torch.unsqueeze(img, dim=0)
  131. # 获取预测结果
  132. pred = class_dict[model(img).argmax(axis=1).item()]
  133. print('【预测结果分类】:%s' % pred)

代码运行结果如下:

  1. using 851 images for training.
  2. dict_values(['angry', 'disgust', 'fear', 'happy', 'neutral', 'sad', 'surprise'])
  3. train epoch[1/10] loss:1.943: 100%|██████████| 27/27 [00:10<00:00, 2.65it/s]
  4. 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】1
  5. 训练损失为54.592151284217834
  6. 训练精度为23.14%
  7. train epoch[2/10] loss:1.906: 100%|██████████| 27/27 [00:10<00:00, 2.50it/s]
  8. 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】2
  9. 训练损失为51.95514786243439
  10. 训练精度为27.96%
  11. train epoch[3/10] loss:1.873: 100%|██████████| 27/27 [00:10<00:00, 2.68it/s]
  12. 【EPOCH: 】3
  13. 训练损失为54.413649916648865
  14. 训练精度为29.96%
  15. train epoch[4/10] loss:1.508: 100%|██████████| 27/27 [00:10<00:00, 2.60it/s]
  16. 【EPOCH: 】4
  17. 训练损失为51.14111852645874
  18. 训练精度为30.66%
  19. train epoch[5/10] loss:1.816: 100%|██████████| 27/27 [00:13<00:00, 2.05it/s]
  20. 【EPOCH: 】5
  21. 训练损失为52.17003357410431
  22. 训练精度为32.07%
  23. train epoch[6/10] loss:1.833: 100%|██████████| 27/27 [00:11<00:00, 2.31it/s]
  24. 0%| | 0/27 [00:00<?, ?it/s]【EPOCH: 】6
  25. 训练损失为51.988134145736694
  26. 训练精度为31.37%
  27. train epoch[7/10] loss:1.907: 100%|██████████| 27/27 [00:10<00:00, 2.49it/s]
  28. 【EPOCH: 】7
  29. 训练损失为51.65321123600006
  30. 训练精度为32.54%
  31. train epoch[8/10] loss:1.993: 100%|██████████| 27/27 [00:11<00:00, 2.40it/s]
  32. 【EPOCH: 】8
  33. 训练损失为51.17294144630432
  34. 训练精度为33.72%
  35. train epoch[9/10] loss:1.682: 100%|██████████| 27/27 [00:13<00:00, 2.02it/s]
  36. 【EPOCH: 】9
  37. 训练损失为52.21281313896179
  38. 训练精度为29.49%
  39. train epoch[10/10] loss:1.926: 100%|██████████| 27/27 [00:15<00:00, 1.75it/s]
  40. 【EPOCH: 】10
  41. 训练损失为50.530142426490784
  42. 训练精度为32.43%
  43. Finished Training
  44. 【预测结果分类】:angry

注意,这里只是列出计算10个周期,如果需要提高训练精度,需要增加训练周期100个以及扩大训练样本量。读者可以自行尝试。

《PyTorch深度学习与企业级项目实战(人工智能技术丛书)》(宋立桓,宋立林)【摘要 书评 试读】- 京东图书 (jd.com)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/848673
推荐阅读
相关标签
  

闽ICP备14008679号