利用Pytorch实现一个完整的基于深度学习的人脸表情识别项目

简介: 利用Pytorch实现一个完整的基于深度学习的人脸表情识别项目

9c6c95759f9de96d3bc0754b71cef88f.jpg该任务基于图像分类网络Alex实现。


✨1 train脚本

从设备,数据集,模型,优化器,损失函数,进度条,模型评估和参数保存等方面进行总结说明。

🌭1.1 设备

cpu或者单卡gpu

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

多卡gpu待补充…

🍕1.2 数据集

这部分包含数据增强,重载DataSet类,DataLoader打包三项操作,下面一一介绍:

🎆 1.2.1 图像增强

表情识别属于分类任务,数据预处理比较简单:

  1. ToTensor将数据转化为Tensor数据。
  2. RandomResizedCrop将图像裁剪到224的大小(这是网络要求的)。
  3. RandomHorizontalFlip增强图像的泛化性。
  4. Normalize归一化使得数据的分布更加均匀,减少模型学到数据分布的可能性。
data_transform = {
    "train": transforms.Compose([
        transforms.ToTensor(),
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    "val": transforms.Compose([
        transforms.ToTensor(),
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

需要注意的是,cv2打开的图像数据类型是numpy,不能进行ToTensor之外的图像增强操作。因此,该步必须放在第一个。

🍔1.2.2 MMAFEDB表情识别数据集介绍

百度网盘(5pi5)

22ec56274cc948818acd20892e938541.png

下载数据集并解压后,内容如下:

  1. labels.txt:标签种类
  2. train_list.txtval_list.txtval_list.txt:分别是训练数据,验证数据和测试数据,每条内容未图像路径 标签
  3. 各文件夹名称即分类标签,内部是该分类的图像数据。

🌭1.2.3 重载DataSet

点击此处进入之前总结过的自定义数据集的总结

处理MMAFEDB的详细代码见第二节。导入数据集代码为:

train_dataset = MMAFEDB(root_path, is_type="train", transform=data_transform["train"])
val_dataset = MMAFEDB(root_path, is_type="eval", transform=data_transform["val"])

其中root_pathtxt文件的父路径。is_type可选参数,为"train"或"eval"或"test",即导入的是什么数据。transform是图像增强操作。

🎃1.2.4 DataLoader打包

假设已经创建DataSet的重载类,即数据集导入完成。打包操作为:

# 打包
train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=512,
    shuffle=True,
    # num_workers=nw,
)
val_loader = torch.utils.data.DataLoader(
    val_dataset,
    batch_size=512,
    shuffle=True
)

更具体的参数见1.2.3链接第二节

🎄1.3 模型

分类模型有很多:Alex,GooleNet,ResNet,MobileNet…这里选用AlexNet,其它后续也会进行尝试,待补充…

🎈1.4 优化器和损失函数

损失函数的一些总结

优化器待补充…梯度下降算法推荐看刘建平老师的博客

这里是使用了Pytorch包装好的Adam优化器和交叉熵损失函数

optimizer = torch.optim.Adam(model.parameters(), lr=0.0002)  # 总结
loss_function = torch.nn.CrossEntropyLoss()

✨1.5 模型及参数的加载和保存

🍕1.5.1 模型的加载和保存

保存模型用到torch.save(model, save_dir)函数,其中model是自定义的模型对象,save_dir是保存路径:

save_dir = ""  # 保存路径,自定义
torch.save(model, save_dir)

而加载该模型应该是:

torch.load(save_path)  # save_path是保存的模型的路径

🎆1.5.2 权重的加载和保存

保存权重分为两步:获取权重和保存参数:

  1. model.state_dict()获取参数:
paramters = model.state_dict()
  1. torch.save保存
torch.save(paramters, save_path)  # save_path是保存路径,自定义

加载模型,仍然用torch.load

paramters = torch.load(save_path)  # save_path是权重文件的保存路径

只是后面,我们需要load_state_dict将参数赋予模型

model.load_state_dict(paramters)

🍔1.6 模型评估

这里先简单采用正确率

    # 验证部分
    model.eval()
    acc = 0.0
    best_acc = 0.0
    with torch.no_grad():
        for i, data in enumerate(val_loader):
            img, label = data
            output = model(img.to(device))
            pred = torch.max(output, dim=1)[1]
            acc += torch.eq(pred, label.to(device)).sum().item()  # TODO 1 累加batch个中预测和标签一致的数量
    acc = acc / len(val_dataset)  # TODO 2 所有数据acc累加除所有数据的数量
    print("acc: {}".format(acc))
    if acc > best_acc:
        best_acc = acc
        torch.save(model.state_dict(), "./weights/best.pth")

代码中两行注释即正确率的计算方法。

需要注意的是,len(val_dataset)即可得到所有数据的数量,在其它任务中肯定会用到。

✨2 重载DataSet(代码)

from torch.utils.data import Dataset
import os
import cv2
from torchvision import transforms
import torch
class MMAFEDB(Dataset):
    def __init__(self, path: str, is_type: str, transform=None):
        """
        :param path: Parent path of the dataset
        :param transform:
        """
        assert os.path.exists(path), "no path:{}".format(path)
        self.path = path
        self.type = is_type
        self.transform = transform
        self.img_path = []
        self.label = []
        self.load_path()
    def __len__(self):
        return len(self.img_path)
    def __getitem__(self, index):
        img_path = self.img_path[index]
        label = self.label[index]
        img = cv2.imread(img_path)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        if self.transform is not None:
            img = self.transform(img)
        label = torch.as_tensor(int(label))
        return img, label
    def load_path(self):
        try:
            if self.type == "train":
                with open(os.path.join(self.path, "train_list.txt"), "r", encoding="utf-8") as file:
                    lines = file.readlines()
            elif self.type == "eval":
                with open(os.path.join(self.path, "val_list.txt"), "r", encoding="utf-8") as file:
                    lines = file.readlines()
            elif self.type == "test":
                with open(os.path.join(self.path, "test_list.txt"), "r", encoding="utf-8") as file:
                    lines = file.readlines()
        except FileExistsError as e:
            print(e)
        for line in lines:
            img_path, cl = line.split()
            img_path = os.path.join(self.path, img_path)
            self.img_path.append(img_path)
            self.label.append(cl)
if __name__ == "__main__":
    data_transform = {
        "train": transforms.Compose([
            transforms.ToTensor(),
            transforms.RandomResizedCrop(224),
            transforms.RandomHorizontalFlip(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
        "val": "",
    }
    dataset = MMAFEDB("E:/DataSet/MMAFEDB", is_type="train", transform=data_transform["train"])
    for data in dataset:
        print(2)

if __name__ == "__main__"中是用以测试的代码,首要关注MMAFEDB类:

  1. load_path函数将txt文件中的图片数据路径和label提取出来,存入self.img_pathself.label

5cb75b015cfb43a195b5d1d9afe68c74.png__getitem__函数通过index,提取一张图像和对应label。然后进行图像增强操作(img = self.transform(img)),通过label = torch.as_tensor(int(label))将label的数据类型转化为Tensor。这里主要用as_tensor而不是to_tensor,主要是因为to_tensor会将数据除255,as_tensor数据保持不变。因此to_Tensor用于image,给image进行归一化。as_Tensor用于label,保持原有标签。

✨ 4 一些注意点

  1. 模型to设备时不用多赋予一次值,即不用model = model.to(device),只需要执行model.to(device)即可。
  2. 训练前优化器权重要清零optimizer.zero_grad()
  3. 利用model和loss_functional计算式,设备必须统一,数据类型也必须是张量。
  4. model.train()model.eval()作用是开启/关闭dropout和BN操作,如果没有使用与否没有区别。
  5. with torch.no_grad()关闭自动求导,验证时必须开启。


相关文章
|
7天前
|
机器学习/深度学习 PyTorch API
pytorch与深度学习
【5月更文挑战第3天】PyTorch,Facebook开源的深度学习框架,以其动态计算图和灵活API深受青睐。本文深入浅出地介绍PyTorch基础,包括动态计算图、张量和自动微分,通过代码示例演示简单线性回归和卷积神经网络的实现。此外,探讨了模型架构、自定义层、数据加载及预处理等进阶概念,并分享了实战技巧、问题解决方案和学习资源,助力读者快速掌握PyTorch。
29 5
|
9天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【Python机器学习专栏】PyTorch在深度学习中的应用
【4月更文挑战第30天】PyTorch是流行的开源深度学习框架,基于动态计算图,易于使用且灵活。它支持张量操作、自动求导、优化器和神经网络模块,适合快速实验和模型训练。PyTorch的优势在于易用性、灵活性、社区支持和高性能(利用GPU加速)。通过Python示例展示了如何构建和训练神经网络。作为一个强大且不断发展的工具,PyTorch适用于各种深度学习任务。
|
10天前
|
机器学习/深度学习 自然语言处理 算法
PyTorch与NLP:自然语言处理的深度学习实战
随着人工智能技术的快速发展,自然语言处理(NLP)作为其中的重要分支,日益受到人们的关注。PyTorch作为一款强大的深度学习框架,为NLP研究者提供了强大的工具。本文将介绍如何使用PyTorch进行自然语言处理的深度学习实践,包括基础概念、模型搭建、数据处理和实际应用等方面。
|
22天前
|
机器学习/深度学习 并行计算 PyTorch
PyTorch与CUDA:加速深度学习训练
【4月更文挑战第18天】本文介绍了如何使用PyTorch与CUDA加速深度学习训练。CUDA是NVIDIA的并行计算平台,常用于加速深度学习中的矩阵运算。PyTorch与CUDA集成,允许开发者将模型和数据迁移到GPU,利用`.to(device)`方法加速计算。通过批处理、并行化策略及优化技巧,如混合精度训练,可进一步提升训练效率。监控GPU内存和使用调试工具确保训练稳定性。PyTorch与CUDA的结合对深度学习训练的加速作用显著。
|
PyTorch 算法框架/工具 Android开发
PyTorch 深度学习(GPT 重译)(六)(4)
PyTorch 深度学习(GPT 重译)(六)
38 2
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 深度学习(GPT 重译)(六)(3)
PyTorch 深度学习(GPT 重译)(六)
29 2
|
22天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 深度学习(GPT 重译)(六)(2)
PyTorch 深度学习(GPT 重译)(六)
41 1
|
22天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 深度学习(GPT 重译)(六)(1)
PyTorch 深度学习(GPT 重译)(六)
37 1
|
22天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 深度学习(GPT 重译)(五)(4)
PyTorch 深度学习(GPT 重译)(五)
36 5
|
22天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 深度学习(GPT 重译)(五)(3)
PyTorch 深度学习(GPT 重译)(五)
28 3

热门文章

最新文章