深度学习实战-基于EfficientNet的宠物面部表情图像分类识别模型(整理分享)

最近在做优化的时候涉及到了这块内容,觉得值得写下来,方便以后翻阅。

  

🤵‍♂️ 个人主页:@艾派森的个人主页
✍🏻作者简介:Python学习者 🐋 希望大家多多支持,大家一起进步!😄

目录

1.项目背景

2.数据集介绍

3.技术工具

4.实验过程

4.1导入数据

4.2数据预处理

4.3数据可视化

4.4构建模型

4.5训练模型

4.6模型评估

4.7模型预测

5.总结

源代码


1.项目背景

        伴随着家庭宠物保有量的持续增长,宠物在人类生活中早已不再只是纯粹的玩伴,而是逐渐转变为不可或缺的家庭成员与情感寄托。在这种背景下,准确搞懂宠物的情绪状态与心理福利,成为了广大养宠家庭以及动物保护、兽医医疗等领域的共同诉求。然而,由于语言隔阂,人类往往只能通过主观经验来粗略推断宠物的情绪,这在一定程度上限制了人宠之间的深度情感交互,甚至可能延误对宠物反常心理或痛苦状态的及时干预。

        得益于计算机视觉与深度学习技术的长足进步,通过图像识别技术来捕捉并量化生物个体的面部微表情,已经在人脸识别领域取得了高度成熟的应用。将这一技术外推至动物界,通过算法去精准识别狗、猫、兔子、仓鼠乃至马、鸟类等不同动物的快乐、悲伤与愤怒等面部表情,成为了一个极具创新性与实用价值的研究方向。本研究正是切入这一前沿领域,旨在利用先进的深度学习卷积神经网络,构建一套高自动化的宠物面部表情图像分类识别模型。这不仅能为宠物智能硬件开发、创意交互软件设计提供底层的核心算法支持,帮助主人更科学地洞察宠物的情感与个性,更能为动物行为学研究以及动物福利救助事业提供客观的技术评测手段,真正用科技力量搭建起人宠情感沟通的智慧桥梁。

2.数据集介绍

        本实验数据集来源于Kaggle,原始数据集为宠物面部表情图像数据集,该数据集包含1000张各种宠物的面部图像,例如狗、猫、兔子、仓鼠、绵羊、马和鸟类。这些图像捕捉了这些动物可以展现的各种表情,例如快乐、悲伤、愤怒等等。您可以应用机器学习技术来深入了解宠物的情感和个性,利用宠物面部图像创作有趣且富有创意的项目,并为宠物面部识别研究和动物福利事业做出贡献。

潜在应用案例

  • 面部表情识别:该数据集可用于训练和评估可以通过面部表情识别宠物情绪的模型。这有助于宠物主人更好地了解他们的宠物,并改善它们的福祉。
  • 宠物识别:该数据集可用于训练和评估可以从宠物面部图像识别宠物种类和品种的模型。

3.技术工具

Python版本:3.9

代码编辑器:jupyter notebook

4.实验过程

4.1导入数据

在进行模型构建与数据处理之前,大家得先导入项目所需的各类第三方库。这包含用于文件操作的 os、用于数据分析与矩阵运算的 pandas 和 numpy、用于数据可视化的 matplotlib、seaborn 和 plotly,以及构建和训练 EfficientNet 模型所依赖的 sklearn 和 tensorflow.keras 核心组件。

import os
import itertools
import cv2
import numpy as np
import pandas as pd
import seaborn as sns
sns.set_style('darkgrid')
import matplotlib.pyplot as plt
import missingno as msno
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from plotly.offline import iplot
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam, Adamax
from tensorflow.keras.metrics import categorical_crossentropy
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Activation, Dropout, BatchNormalization
from tensorflow.keras import regularizers
from keras.callbacks import EarlyStopping, LearningRateScheduler
import numpy as np
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.efficientnet import preprocess_input
# Ignore Warnings
import warnings
warnings.filterwarnings("ignore") # 忽略警告信息,保持控制台输出整洁

接下来,大家定义数据集的根目录与子目录路径。为了方便后续对图片数据进行结构化管理,我们编写了 generate_data_paths 函数来遍历目录,提取所有图像的绝对路径及其对应的表情标签;随后通过 create_df 函数将这些信息整合到 Pandas 的 DataFrame 中,为后续的数据划分与可视化打下基础。

# 定义训练集、验证集、测试集以及数据集总根目录的路径
train_data_dir = '/kaggle/input/pets-facial-expression-dataset/Master Folder/train'
valid_data_dir = '/kaggle/input/pets-facial-expression-dataset/Master Folder/valid'
test_data_dir = '/kaggle/input/pets-facial-expression-dataset/Master Folder/test'
data_dir = '/kaggle/input/pets-facial-expression-dataset'
ds_name = 'Pets Facial Expression'

# Generate data paths with labels
# 定义函数:通过遍历目录生成包含图片路径和对应标签的列表
def generate_data_paths(data_dir):

    filepaths = [] # 存储所有图片的绝对路径
    labels = []    # 存储每张图片对应的类别标签

    folds = os.listdir(data_dir) # 获取数据集根目录下的所有子文件夹名称
    for fold in folds:
        # 略过 Master Folder 目录,防止重复读取数据
        if fold == 'Master Folder':
            continue

        foldpath = os.path.join(data_dir, fold) # 拼接得到分类文件夹的完整路径
        filelist = os.listdir(foldpath)        # 获取该类别文件夹下的所有文件名
        for file in filelist:
            fpath = os.path.join(foldpath, file) # 拼接得到单张图片的完整路径
            filepaths.append(fpath)             # 将路径添加到列表中
            labels.append(fold)                 # 将类别名称作为标签添加到列表中

    return filepaths, labels # 返回路径列表和标签列表

# 调用函数获取所有图片的路径和标签
filepaths, labels = generate_data_paths(data_dir)

# 定义函数:将路径列表和标签列表组合并转换为 DataFrame 格式
def create_df(filepaths, labels):

    Fseries = pd.Series(filepaths, name= 'filepaths') # 创建路径序列
    Lseries = pd.Series(labels, name='labels')        # 创建标签序列
    df = pd.concat([Fseries, Lseries], axis= 1)       # 沿列方向拼接成 DataFrame
    return df

# 调用函数创建 DataFrame 并在控制台查看前5行数据结构
df = create_df(filepaths, labels)
df.head()

4.2数据预处理

在动手训练模型之前,我们先来看得对数据集的整体规模、类别数量以及每个具体类别的样本分布有一个清晰的认识。为此,我们编写了三个辅助统计函数:num_of_examples 用于统计样本总数,num_of_classes 用于获取分类标签的数量,classes_count 则用于输出每个表情类别下的图像数量,以确认是否存在数据不平衡问题。

# 定义函数:打印数据集中的总图像数量
def num_of_examples(df, name='df'):
    print(f"The {name} dataset has {df.shape[0]} images.")

# 调用函数统计当前总 DataFrame 的图像数量
num_of_examples(df, ds_name)

# 定义函数:打印数据集中的类别总数
def num_of_classes(df, name='df'):
    print(f"The {name} dataset has {len(df['labels'].unique())} classes")

# 调用函数统计当前总 DataFrame 的类别数量
num_of_classes(df, ds_name)

# 定义函数:详细统计并打印每个分类标签下的图像数量
def classes_count(df, name='df'):

    print(f"The {name} dataset has: ")
    print("="*70) # 打印分割线
    print()
    # 遍历所有唯一的类别名称
    for name in df['labels'].unique():
        # 计算当前类别下的样本总数
        num_class = len(df['labels'][df['labels'] == name])
        print(f"Class '{name}' has {num_class} images")
        print('-'*70) # 打印项分割线

# 调用函数输出详细的类别样本分布情况
classes_count(df, ds_name)

为了保证模型的泛化能力并防止过拟合,我们用 train_test_split 将原始数据按照 8:2 的比例切分出训练集与临时数据集,再将临时数据集按照 6:4 的比例划分为验证集与测试集。

随后,我们配置了图像的基础几何参数(如 224x224 的输入尺寸),并计算出最适合测试集的 Batch Size。最后,利用 Keras 的 ImageDataGenerator 为训练集和验证集构建了包含旋转、平移、亮度调节及翻转等多种策略的数据增强流水线,并最终生成了用于模型训练的三个 Data Generator。

```

train dataframe


先来看将整个数据集划分为训练集(80%)和临时数据集 dummy_df(20%),开启乱序并设置随机种子


train_df, dummy_df = train_test_split(df, train_size= 0.8, shuffle= True, random_state= 123)

valid and test dataframe

再将临时数据集进一步划分为验证集(60%,即总体的12%)与测试集(40%,即总体的8%)

valid_df, test_df = train_test_split(dummy_df, train_size= 0.6, shuffle= True, random_state= 123)

统计并打印划分后训练集、验证集和测试集的样本数量

num_of_examples(train_df, "Training "+ds_name) num_of_examples(valid_df, "Validation "+ds_name) num_of_examples(test_df, "Testing "+ds_name)

验证并打印划分后各数据集的类别数量,确保分类标签完整未丢失

num_of_classes(train_df, "Training "+ds_name) num_of_classes(valid_df, "Validation "+ds_name) num_of_classes(test_df, "Testing "+ds_name)

crobed image size

设置常规训练的批次大小(Batch Size)以及图像尺寸、通道数和形状信息

batch_size = 16 img_size = (224, 224) # 适配 EfficientNet 的标准输入尺寸 channels = 3 img_shape = (img_size[0], img_size[1], channels)

Recommended : use custom function for test data batch size, else we can use normal batch size.

为测试集动态计算一个能够整除总样本数且不超过 80 的最佳 Batch Size,以确保评估时不多不少刚好处理完所有样本

ts_length = len(test_df) test_batch_size = max(sorted([ts_length // n for n in range(1, ts_length + 1) if ts_length%n == 0 and ts_length/n
以上就是这次整理的全部内容,希望对你有所启发。如果有不同见解,欢迎在评论区交流讨论。

评论 (0)

暂无评论