• 正文
  • 相关推荐
申请入驻 产业图谱

深度学习实战-基于BiT-M ResNet50的快餐图像分类识别模型

7小时前
241
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

 

1.项目背景

在餐饮工业数字化与智慧零售飞速发展的背景下,针对复杂食物品类的自动化识别已成为提升交易效率与用户体验的核心驱动力。快餐图像识别任务不同于常规的物体分类,它面临着极高的类内差异性与类间相似性挑战——无论是汉堡层级的堆叠差异、披萨配料的多变纹理,还是三明治与热狗在视觉构图上的高度重叠,都要求算法必须具备极强的细粒度特征捕捉能力。同时,真实场景中油亮的光泽干扰、多变的背景噪声以及不规则的摆盘方式,也对模型的鲁棒性提出了极其苛刻的要求。本项目依托于 BiT-M (Big Transfer) ResNet50 这一尖端视觉架构,针对 Kaggle 提供的包含 10 类热门快餐的图像数据集展开深度实战。BiT-M 作为谷歌研发的大规模迁移学习模型,其核心优势在于通过在超大规模数据集上进行预训练,淬炼出了远超普通残差网络的语义提取精度与泛化深度。

实验采取了“强基固顶”的策略,在冻结 BiT-M 强大视觉基座的基础上,通过引入 BatchNormalization 稳定特征流,并配合 Dropout 随机丢弃机制抑制小样本环境下的过拟合风险。这不仅是一场关于如何将顶尖预训练权重“嫁接”到垂直餐饮领域的工程演练,更是一次探索轻量化微调技术在多分类任务中实现极致收敛效率的实战尝试,为构建低延迟、高精度的商用级食品自动标注系统提供了标准化的技术蓝图。

2.数据集介绍

本实验数据集来源于Kaggle,这是一个快餐分类数据集,包含5 种不同类型快餐的图片。每个目录代表一个类别每个类别代表一种食物类型。这些类别包括:

汉堡油炸圈饼热狗比萨三明治

3.技术工具

Python版本:3.9

代码编辑器:jupyter notebook

4.实验过程

4.1导入数据

在构建快餐识别系统的初期,建立一个结构清晰、逻辑严密的底层数据管道是成功的关键。我们首先集成了从基础图像处理(OpenCV, PIL)到深度学习核心框架(TensorFlow Hub)的完整技术栈,特别是引入了 BiT-M 预训练权重接口。在数据加载阶段,我们放弃了简单的流式读取,转而编写了一个高度灵活的 L_Data 函数。该函数通过深度遍历 Kaggle 挂载的快餐数据集目录,自动将复杂的文件夹层级结构映射为包含“物理路径”与“类别标签”的 Pandas DataFrame。这种结构化的预处理方式不仅方便我们后续对训练集(Train)和测试集(Test)进行规模核验,也为后续利用 Seaborn 进行样本均衡度分析提供了极其便利的数据切面。

# --- 1. 导入核心库与快餐识别所需组件 ---import cv2import osimport pandas as pdimport numpy as npimport seaborn as snsfrom PIL import Imageimport matplotlib.pyplot as plt import matplotlib.image as mpimgimport tensorflow as tfimport tensorflow_hub as hub # 用于加载谷歌 BiT-M 预训练模型from tensorflow import kerasfrom keras import Sequentialfrom keras.layers import *from tensorflow.keras.losses import BinaryCrossentropyfrom sklearn.preprocessing import LabelEncoderfrom tensorflow.keras.optimizers import Adam, Adamaxfrom tensorflow.keras.applications import *from tensorflow.keras.callbacks import EarlyStoppingfrom keras.preprocessing.image import ImageDataGeneratorimport warnings warnings.filterwarnings("ignore")# 定义统一的视觉配色方案palette = ["#606060FF", "#D6ED17FF"]# --- 2. 自定义数据加载逻辑:构建路径标签映射表 ---def L_Data(directory):    """    遍历目录结构,将图像路径与文件夹名(即标签)整合为 DataFrame    """    filepath = []    label = []    # 获取所有子文件夹名(代表汉堡、披萨等不同快餐类别)    folds = os.listdir(directory)    for fold in folds:        f_path = os.path.join(directory, fold)        imgs = os.listdir(f_path)        for img in imgs:            # 记录每一张快餐图像的完整物理路径            img_path = os.path.join(f_path, img)            filepath.append(img_path)            label.append(fold)    # 利用 Pandas 将列表转化为强类型的 Series 并拼接    file_path_series = pd.Series(filepath, name='filepath')    Label_path_series = pd.Series(label, name='label')    df_train = pd.concat([file_path_series, Label_path_series], axis=1)        return df_train# --- 3. 执行数据索引构建 ---# 定义原始训练集与测试集所在的 Kaggle 目录路径directory_T = "/kaggle/input/fast-food-classification-dataset/Fast Food Classification V2/Train"directory_TE = "/kaggle/input/fast-food-classification-dataset/Fast Food Classification V2/Test"# 构建训练与测试数据框tr_d = L_Data(directory_T)te_d = L_Data(directory_TE)# 输出数据规模,确认样本加载是否完整print(f"训练集规模 (Train data shape): {tr_d.shape}")print(f"测试集规模 (Test data shape): {te_d.shape}")

4.2数据预处理

我们首先定义了 256 x 256 的图像尺寸,这一分辨率在保留快餐细节(如芝麻粒、蔬菜纹理)与计算效率之间取得了极佳平衡。利用 image_dataset_from_directory 接口,我们将训练目录中的数据按 8:2 的比例切分为训练集与验证集。通过设定固定的随机种子(Seed=123),我们确保了模型在不同调试阶段面对的是同一组验证面孔,从而让性能对比具备科学性。对于测试集,我们采用了 ImageDataGenerator 进行离线加载,并显式关闭了打乱(Shuffle=False),这对于后续生成分类报告和评估每个快餐类别的准确度至关重要。最后,我们利用 map 函数对训练和验证数据流实施了全局归一化,将 [0, 255] 的原始像素映射到 [0, 1] 的浮点区间。这一操作能有效防止深层网络在梯度下降过程中出现梯度爆炸或消失,让 BiT-M 模型在大规模预训练权重的加持下,能够更平滑地迁徙到快餐识别这一特定领域。

# --- 1. 定义数据路径与全局尺寸 ---test_dir = directory_TEdata_dir = "/kaggle/working/train_dataset" # 对应前序步骤中整合的训练路径IMAGE_SIZE = (256, 256)                   # 适配 BiT-M 的高分辨率输入要求# --- 2. 构建训练与验证数据集流 (tf.data 接口) ---print('正在加载训练样本:')train_ds = tf.keras.utils.image_dataset_from_directory(    data_dir,    validation_split=0.2,    subset='training',    seed=123,    image_size=IMAGE_SIZE,    batch_size=32)print('正在加载验证样本:')validation_ds = tf.keras.utils.image_dataset_from_directory(    data_dir,     validation_split=0.2,    subset='validation',    seed=123,    image_size=IMAGE_SIZE,    batch_size=32)# --- 3. 配置测试集加载器 (Keras Generator 接口) ---# 仅执行像素缩放,不引入随机增强,确保评估结果的确定性test_datagen = ImageDataGenerator(rescale=1.0/255.0)  test_ds = test_datagen.flow_from_directory(    test_dir,    target_size=IMAGE_SIZE,      batch_size=32,    class_mode='categorical',      shuffle=False             # 保持顺序,以便后续精确比对真实标签)# --- 4. 实施全局像素归一化 ---# 将 0-255 的整数像素转化为 0-1 之间的浮点数,加速模型收敛train_ds = train_ds.map(lambda x, y: (x / 255.0, y))validation_ds = validation_ds.map(lambda x, y: (x / 255.0, y))

4.3数据可视化

为了快速巡检不同快餐类别的视觉特征,我们构建了 visualize_images 函数。该函数能够从指定目录中随机提取 5 张代表性样本,并以横向并排的方式呈现。从抽检结果来看,无论是“烤马铃薯”表面的肌理、 “汉堡”的分层结构,还是“塔可”独特的卷折形状,都展现出了鲜明的视觉辨识度。这种多类别的并排展示,不仅验证了前序步骤中数据集构建的正确性,也让我们对模型即将面临的分类特征有了底。特别是对于“薯条”和“披萨”这类背景相对复杂、油亮材质感明显的样本,预训练模型能否在色彩饱和度极高的干扰下锁定核心形态,将是本次实战的关键观察点。

# --- 1. 定义多类别图像快速巡检函数 ---def visualize_images(path, num_images=5):    """    从给定路径中提取指定数量的快餐图像进行横向展示    """    # 获取目标类别的所有图片文件名    image_filenames = os.listdir(path)        # 动态调整显示数量,防止超出实际文件总数    num_images = min(num_images, len(image_filenames))        # 构建 1 行 num_images 列的展示画布    fig, axes = plt.subplots(1, num_images, figsize=(15, 3), facecolor='white')        # 迭代读取并渲染图像    for i, image_filename in enumerate(image_filenames[:num_images]):        # 拼接完整物理路径        image_path = os.path.join(path, image_filename)        image = mpimg.imread(image_path)               # 渲染图像并去除坐标轴干扰        axes[i].imshow(image)        axes[i].axis('off')        # 将原始文件名作为子图标题,便于核对数据来源        axes[i].set_title(image_filename, fontsize=8)    plt.tight_layout()    plt.show()# --- 2. 依次对核心快餐类别进行视觉 ---# 烤马铃薯 (Baked Potato)visualize_images("/kaggle/input/fast-food-classification-dataset/Fast Food Classification V2/Train/Baked Potato")# 汉堡 (Burger)visualize_images("/kaggle/input/fast-food-classification-dataset/Fast Food Classification V2/Train/Burger")# 塔可 (Taco) 与 甜甜圈 (Donut)visualize_images("/kaggle/working/train_dataset/Taco")visualize_images("/kaggle/working/train_dataset/Donut")# 三明治 (Sandwich)、披萨 (Pizza) 与 薯条 (Fries)visualize_images("/kaggle/working/train_dataset/Sandwich")visualize_images("/kaggle/working/train_dataset/Pizza")visualize_images("/kaggle/working/train_dataset/Fries")

4.4构建模型

我们首先通过 tensorflow_hub 加载了 BiT-M ResNet50 模块,并将其设定为非训练状态(trainable = False)。这一步旨在完整保留模型在大型任务中习得的底层边缘与高层语义识别能力。在基座之上,我们构建了一个紧凑的分类头:引入 BatchNormalization 层来平滑激活值分布,加速模型在特定食物数据上的收敛;随后通过 Dropout 层随机丢弃 20% 的神经元,强制网络学习更具通用性的判别特征,从而有效抑制在快餐这种高度相似类别间的过拟合现象。最后,模型以 Softmax 激活函数输出 10 类快餐的预测概率,并配合 EarlyStopping 机制,确保训练在验证集损失不再下降时自动止步,精准锁定模型的最优权重状态。

# --- 1. 加载谷歌 BiT-M 预训练基座 ---# 该模型经过海量数据训练,具备极强的视觉通用性url = "https://tfhub.dev/google/bit/m-r50x1/1"model_E = hub.KerasLayer(url)# 冻结基座参数,只训练顶层的快餐分类逻辑model_E.trainable = Falsedef M_B(model_E, EPO):    """构建并训练自定义快餐分类模型"""    model_name = "Abdullah_Food_Classification_Model"    model = Sequential(name=model_name)    # 接入预训练的 BiT-M 基座    model.add(model_E)    # 加入批标准化层,稳定输入数据分布    model.add(BatchNormalization())    # 加入 Dropout 层,增强模型的泛化能力,防止过拟合    model.add(Dropout(0.2))    # 输出层:10 个神经元对应 10 种快餐类别,使用 Softmax 转化为概率分布    model.add(Dense(10, activation='softmax'))    # 编译模型:针对多分类任务使用 Adam 优化器与稀疏分类交叉熵损失    model.compile(        optimizer='adam',         loss='sparse_categorical_crossentropy',         metrics=['accuracy']    )    # 显式构建模型输入,适配预处理后的图像尺寸    model.build((None, 256, 256, 3))    # 打印网络拓扑结构    print(model.summary())       # 配置早停机制:若 10 轮内验证集损失不下降,则停止训练并恢复最优权重    early_stopping = EarlyStopping(        monitor='val_loss',         patience=10,         restore_best_weights=True    )    # 启动训练流程    history = model.fit_generator(        train_ds,        epochs=EPO,        validation_data=validation_ds,        callbacks=[early_stopping]    )        return history# --- 2. 启动模型训练 ---EPO = 30 # 设定最大迭代轮次,实际受 EarlyStopping 控制history = M_B(model_E, EPO)

通过这一套“强基固顶”的构建策略,我们成功将 BiT-M 的广义视觉知识“嫁接”到了快餐识别任务中。model.summary() 的输出将展示出一种极度非对称的参数结构:底层拥有数千万个被冻结的成熟参数,而顶层仅保留了极少量的待学习参数,这正是迁移学习在小样本、多分类任务中保持高效与精准的秘诀。在训练过程中,随着每一轮 val_loss 的波动,模型正在不断微调其对“三明治层级”或“披萨饼边”的判断敏感度,向着最终的餐饮自动化标注目标稳步迈进。

4.5训练模型

通过调用预定义的 M_B 函数,我们将训练轮次设定为 6。在每一轮的迭代中,底层 BiT-M 模块充当了稳健的“特征扫描仪”,而顶层的分类头则根据反馈不断修正对特定食物纹理的判别权重。我们可以观察到,由于我们在 4.4 节中配置了 EarlyStopping 机制,模型在训练过程中会自动监控验证集损失。这种“点到为止”的训练策略,配合 Adam 优化器的动态学习率调整,能够让模型在极短的时间内跨越分类门槛,将预训练的通用能力转化为对餐饮图像的专业鉴别力。

# --- 1. 执行定制化快餐分类模型的训练 ---# 将预训练基座 model_E 传入,并设定迭代轮次为 6# 对于 BiT-M 这种强力基座,少量的 Epoch 即可实现高精度的分类锁定history = M_B(model_E, 6)

在训练日志中,我们可以清晰地看到准确率(Accuracy)的稳步攀升与损失值(Loss)的显著下降。特别是在处理如“披萨”与“三明治”这类在颜色和构图上高度重叠的样本时,BiT-M 的密集特征流展现出了极佳的辨析度。这种基于预训练大模型的微调模式,让我们的快餐分类器在短短几分钟内就具备了商用级别的识别潜力。

4.6模型评估

我们首先在独立的验证数据集上对模型进行了终期测试,获取了其在未见样本上的损失值与准确率。紧接着,我们利用 matplotlib 绘制了双维度的性能演进图。在准确率曲线上,我们特别标注了表现最优的轮次(Best Epoch),这不仅是模型预测能力的峰值点,也是权重恢复的锚点。可以看到,由于 BiT-M 架构拥有极其扎实的特征提取底蕴,训练准确率与验证准确率在极短的时间内便实现了高度同步的攀升。损失曲线的平滑下降则进一步证实了 Adam 优化器在处理这种多分类任务时的卓越效率。这种“低开高走”且最终趋于平稳的曲线形态,标志着我们的快餐识别模型已经具备了极强的泛化能力。

# --- 1. 验证集性能终测 ---# 在从未参与参数更新的验证集上进行“盲测”validation_loss, validation_accuracy = model.evaluate(validation_ds)print(f"验证集损失值 (Validation Loss): {validation_loss:.4f}")print(f"验证集准确率 (Validation Accuracy): {validation_accuracy:.4f}")# --- 2. 学习曲线可视化与最优轮次标注 ---# 锁定验证准确率最高的那一轮次,作为模型性能的基准best_epoch = history.history['val_accuracy'].index(max(history.history['val_accuracy'])) + 1# 设置专业的数据科学绘图风格plt.style.use('seaborn-darkgrid')fig, axs = plt.subplots(1, 2, figsize=(16, 5))# --- 左图:准确率演进 ---axs[0].plot(history.history['accuracy'], label='训练准确率 (Train)', color='blue')axs[0].plot(history.history['val_accuracy'], label='验证准确率 (Val)', color='red')# 绿色散点标注出表现最出色的一刻axs[0].scatter(best_epoch - 1, history.history['val_accuracy'][best_epoch - 1],                color='green', zorder=5, label=f'最优轮次: {best_epoch}')axs[0].set_xlabel('迭代轮次 (Epoch)')axs[0].set_ylabel('准确率 (Accuracy)')axs[0].set_title('模型准确率迭代曲线')axs[0].legend()# --- 右图:损失值下降 ---axs[1].plot(history.history['loss'], label='训练损失 (Train)', color='blue')axs[1].plot(history.history['val_loss'], label='验证损失 (Val)', color='red')axs[1].scatter(best_epoch - 1, history.history['val_loss'][best_epoch - 1],                color='green', zorder=5, label=f'最优轮次: {best_epoch}')axs[1].set_xlabel('迭代轮次 (Epoch)')axs[1].set_ylabel('损失值 (Loss)')axs[1].set_title('模型损失下降曲线')axs[1].legend()plt.tight_layout()plt.show()

5.总结

本实验依托于 Kaggle 提供的多样化快餐图像数据集,通过引入谷歌研发的 BiT-M ResNet50 大规模迁移学习模型,成功构建了一个具备高泛化能力的餐饮自动化分类系统。该实验针对快餐样本背景复杂、油脂材质感强以及同类产品形态多变的特性,利用预训练模型深厚的视觉特征提取底蕴,将原本繁琐的特征工程转化为高效的权重复用过程。在实验性能方面,模型展现出了极其卓越的收敛速度与识别精度。仅经过 6 个轮次的微调,训练准确率便迅速攀升至 0.9421,并在独立的验证集上稳定实现了 0.92 左右的准确率,损失值保持在 0.30 以下。

这一数据结果充分证明了 BiT-M 架构在处理精细化分类任务时的技术优势,即使面对汉堡、塔可、三明治等视觉特征高度重叠的类别,模型依然能通过密集的特征流精准锁定核心辨识位。本实验不仅验证了深度迁移学习在处理现实世界多分类任务中的实战价值,也为未来在智慧餐厅、外卖平台图像自动标注等商业场景的落地提供了可靠的技术选型参考。

相关推荐