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

深度学习实战-基于CNN卷积神经网络的汽车与摩托车图像分类模型

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

1.项目背景

随着智慧交通与自动驾驶技术的快速发展,基于计算机视觉的车辆类型识别已成为智能交通系统(ITS)中不可或缺的核心技术之一。在实际交通场景中,汽车与各类两轮车辆(如摩托车、自行车)常处于混行状态,快速且精准地区分这两类交通工具,对于路况监控、车流量统计、违章检测以及智能停车场管理等应用具有重要的工程价值。然而,现实环境中的图像复杂多变,不同类型的车辆在外观造型、车身尺寸、涂装色彩以及拍摄视角上存在巨大差异,加上光照变化与背景干扰,给基于传统特征工程的图像识别方法带来了不小的挑战。近年来,深度学习在图像处理领域取得了突破性进展,尤其是卷积神经网络(CNN)凭借其出色的局部特征提取能力与非线性表达能力,为复杂视觉场景下的车辆二分类问题提供了更为高效、鲁棒的解决方案。

本项目旨在搭建一套完整且轻量化的 CNN 分类模型,从数据增强、网络构建到模型评估进行全流程探索,以期实现对汽车与两轮车辆的高准确率自动识别,为相关领域的实际落地提供技术参考。

2.数据集介绍

本实验数据集来源于Kaggle,该数据集包含2000 张自行车(摩托车)和汽车图像。在收集这些图像时,我们确保所有类型的自行车(摩托车)和汽车都包含在图像集中。这是因为汽车和自行车(摩托车)内部的种类繁多。也就是说,汽车和自行车的类型各不相同,这给模型带来了一定的挑战,因为模型不仅要理解这些种类繁多的汽车和自行车,还要理解它们之间的差异。

但是,如果您的模型能够理解汽车和自行车的基本结构,它就能区分这两类车辆。数据未经预处理。这样做是为了方便您应用所需的数据增强方法。这2000张图像几乎都是独一无二的。因此,在应用一些数据增强方法后,可以增加数据集的大小。

3.技术工具

Python版本:3.9

代码编辑器:jupyter notebook

4.实验过程

4.1导入数据

在搭建并训练汽车与摩托车分类模型之前,首先需要准备好所需的开发环境,并将存储在磁盘中的数据集路径进行初始化。在本阶段,我们集中导入了后续数据处理、图像增强、神经网络构建以及模型评估所需的各类核心依赖库,涵盖了数据分析常用库、图像处理组件以及 TensorFlow/Keras 框架模块。随后,我们指定了存储摩托车与汽车图像的根目录路径,并编写了一个轻量化的抽样加载函数,该函数能够从对应的类别文件夹中随机抽取固定数量的图片并加载为图像对象,以便我们在后续步骤中对原始图像数据进行初步的视觉直观检查。

# 导入数据分析与矩阵运算的核心依赖库import pandas as pdimport numpy as np# 导入数据可视化与绘图库,用于后续结果与图像展示import matplotlib.pyplot as pltimport seaborn as sns# 导入文件拆分与系统路径操作模块import splitfoldersimport os# 导入 TensorFlow 与 Keras 图像预处理生成器模块from tensorflow.keras.preprocessing.image import ImageDataGeneratorimport tensorflowfrom tensorflow import keras# 导入构建卷积神经网络(CNN)所需的各核心层组件from keras.models import Sequentialfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Dense, Flatten# 导入数据批处理与神经网络结构图生成工具from keras.utils import image_dataset_from_directoryfrom keras.utils import plot_model# 导入分类模型性能评估指标工具函数from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score# 导入图像加载与处理模块from tensorflow.keras.preprocessing import imagefrom PIL import Image# 导入随机数生成模块与系统警告屏蔽模块import randomimport warningswarnings.filterwarnings('ignore') # 忽略代码执行过程中不必要的警告信息# 定义并存储摩托车与汽车数据文件夹的绝对路径bike_path = '/kaggle/input/car-vs-bike-classification-dataset/Car-Bike-Dataset/Bike'car_path = '/kaggle/input/car-vs-bike-classification-dataset/Car-Bike-Dataset/Car'# 定义图像随机抽样加载函数,默认提取 5 张样本图像def load_sample_images(folder_path, sample_size = 5):    # 遍历文件夹,过滤并获取所有文件路径列表    all_files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]    # 从文件列表中无放回地随机抽取指定数量(默认5张)的文件名    sample_files = random.sample(all_files, sample_size)    images = []    # 循环打开抽样出的图像文件并追加到列表中返回    for file in sample_files:        img_path = os.path.join(folder_path, file)        img = Image.open(img_path)        images.append(img)    return images# 分别调用函数从摩托车与汽车路径中随机加载样本图像对象bike_sample_img = load_sample_images(bike_path)car_sample_img = load_sample_images(car_path)

通过执行上述代码,系统成功载入了解析和处理图像所需的全部类库,完成了对数据集存储位置的精准锚定,同时创建了专门用于测试的图片抽取实例。该过程为后续的数据可视化检查、数据增强策略制定以及卷积神经网络的构建奠定了稳定的基础。

4.2数据可视化

为了更直观地观察和对比数据集中的图像质量、拍摄视角以及两类车辆的视觉特征,有必要在建立预处理流水线前对抽样图像进行集中绘图展示。在此步骤中,我们将上一小节随机提取的摩托车与汽车样本图像汇总为二维列表,并利用 Matplotlib 库创建多行多列的网格画布。通过遍历样本数据,逐一将各类别的车辆图片渲染在对应的子图区域,同时统一设置子图标题、隐藏无关的坐标轴边框,并调整画布排版布局,最终生成一幅对比鲜明、结构清晰的车辆样本图像对比图。

# 将上一阶段抽样得到的摩托车和汽车图像对象整合为列表all_img_sample = [bike_sample_img, car_sample_img]# 创建 2 行 N 列(N 为抽样数量)的子图画布,统一设置画布宽度与高度fig, axes = plt.subplots(2, len(bike_sample_img), figsize=(15,6))# 定义图像绘制对应的类别名称列表title = ['Bike', 'Car']# 嵌套循环遍历两类样本图像,逐行逐列渲染至对应的子图中for row, category in enumerate(all_img_sample):    for i, img in enumerate(category):        axes[row, i].imshow(img) # 在指定位置的子图中绘制图像        axes[row, i].set_title(title[row]) # 为子图添加对应的类别标题(Bike 或 Car)        axes[row, i].axis('off') # 隐藏图像四周的坐标轴刻度线与数字# 为整体网格图设置加粗的全局主标题plt.suptitle('Sample Images of Bikes,and Cars', fontweight='bold')# 自动调整子图间距以防止标题与图像重叠plt.tight_layout()# 渲染并显示最终的样本对比图像plt.show()

4.3数据预处理

为了建立科学严谨的模型评估体系,首先需要将原始图像数据划分为独立的训练集与测试集。在本小节中,我们利用 splitfolders 工具按照 8:2 的比例对原始车辆图像文件夹进行按比例切分,并设置随机种子以确保划分结果的可复现性。划分完成后,我们编写了一个通用的文件统计函数,遍历训练集与测试集(验证集)目录下的各个类别子文件夹,精确计算出每个类别中的图像文件数量。最后,我们将统计数据装载进 Pandas DataFrame,添加数据集类型标记,并将训练集与测试集的数量分布进行合并展示,以便清楚地把控数据规模与样本均衡度。

# 指定原始数据集输入文件夹路径与划分后的输出目标文件夹路径input_folder = '/kaggle/input/car-vs-bike-classification-dataset/Car-Bike-Dataset'output_folder = '/kaggle/working/output'# 调用 splitfolders 按 8:2 的比例将数据集划分为训练集和测试集(即 val 文件夹),指定随机种子保证结果可复现splitfolders.ratio(input_folder, output = output_folder, seed = 1337, ratio = (0.8, 0.2), group_prefix=None)# 定义递归统计指定路径下各个子文件夹内部文件数量的工具函数def count_files_in_folders(base_path):    folder_data = []    # 检查传入的基础路径是否存在    if not os.path.exists(base_path):        print(f"The path {base_path} does not exist.")        return folder_data    # 遍历基础路径下的所有子目录    for folder in os.listdir(base_path):        folder_path = os.path.join(base_path, folder)        if os.path.isdir(folder_path):            num_files = 0            # 统计当前子目录下所有文件的数量            for item in os.listdir(folder_path):                if os.path.isfile(os.path.join(folder_path, item)):                    num_files += 1            folder_data.append((folder, num_files)) # 以元组形式保存文件夹名和对应文件数    return folder_data# 定义划分后的训练集与测试集绝对路径train_path = '/kaggle/working/output/train'test_path =  '/kaggle/working/output/val'# 分别调用统计函数,获取训练集与测试集各类别的图片数量train_data_count = count_files_in_folders(train_path)test_data_count = count_files_in_folders(test_path)# 将统计得到的列表数据转换为 DataFrame 格式,定义列名为 'Folder' 与 'NumFiles'train_df = pd.DataFrame(train_data_count, columns=['Folder', 'NumFiles'])test_df = pd.DataFrame(test_data_count, columns=['Folder', 'NumFiles'])# 为两个 DataFrame 分别新增一列,标明数据所属的集合类型(Train 或 Test)train_df['Type'] = 'Train'test_df['Type'] = 'Test'# 将训练集与测试集的统计数据合并为一个完整的 DataFrame 数据表combined_df = pd.concat([train_df, test_df])combined_df # 输出显示合并后的样本数量分布表

通过这一阶段的数据划分为模型训练打下了坚实的数据结构基础。统计表格清晰呈现了训练集与测试集在不同类别上的具体分布情况,验证了数据集分割按照预设比例精准完成,并且两类车辆在训练与测试环节中保持了良好的样本平衡,有效避免了因样本倾斜而导致的模型偏见问题。

4.4特征工程

在深度学习的图像分类任务中,针对数据层面进行的特征工程主要体现在数据归一化以及数据增强策略的应用上。由于真实场景下的汽车与摩托车图像在光照、角度和缩放比例上存在差异,我们需要通过图像增强技术来人工扩充样本的多样性,从而提升模型的泛化能力。在本小节中,我们实例化了 ImageDataGenerator 对象,对训练集图像施加了像素值归一化、剪切变换、随机缩放、水平翻转以及角度旋转等多种几何变换;对于测试集(验证集),则仅进行像素归一化处理以保证测试环境的真实性。最后,通过 flow_from_directory 方法从指定目录实时加载图像,将图片统一调整为 224 x 224 像素的尺寸,并按照批次生成二分类所需的数据流。

# 实例化训练集数据增强生成器,配置多维度图像变换参数以增加样本多样性train_datagen = ImageDataGenerator(rescale = 1./255,          # 将 RGB 像素值从 [0, 255] 归一化映射到 [0, 1] 范围                                    shear_range = 0.2,         # 施加错切变换(剪切强度为 0.2)                                    zoom_range = 0.2,          # 施加随机缩放变换(缩放范围 20%)                                    horizontal_flip = True,    # 开启随机水平翻转                                    rotation_range=15)         # 开启随机旋转变换(旋转角度上限为 15 度)# 实例化测试集(验证集)数据生成器,测试集仅执行像素归一化,不添加人为噪声test_datagen =  ImageDataGenerator(rescale = 1./255)# 构建训练集数据批次迭代生成器,从训练集目录按批次读取图像数据train_generator = train_datagen.flow_from_directory(    directory = train_path,         # 训练集图像所在的根目录路径    target_size = (224, 224),       # 将所有读取的图像统一缩放调整为 224x224 尺寸    batch_size = 32,                # 设置训练批次大小(Batch Size)为 32    class_mode = 'binary'           # 设置分类模式为二分类(Binary))# 构建测试集数据批次迭代生成器,从验证集目录按批次读取图像数据validation_generator = test_datagen.flow_from_directory(    directory= test_path,           # 测试集(验证集)图像所在的根目录路径    target_size=(224, 224),         # 将所有读取的图像统一缩放调整为 224x224 尺寸    batch_size=32,                  # 设置测试批次大小为 32    class_mode='binary'             # 设置分类模式为二分类(Binary))

经过上述增强与规范化处理,图像数据被转化为适合深度卷积神经网络高效吞吐的标准化数据流。数据增强策略的引入能够有效阻断模型对特定图像位置或固定视角特征的死记硬背,逼迫网络去学习更具鲁棒性的车辆轮廓与局部关键特征,为下一步构建高性能的卷积神经网络分类器奠定了坚实的基础。

4.5构建模型

在完成了数据的清洗、划分与特征增强后,我们需要搭建用于提取图像特征并进行二分类预测的卷积神经网络(CNN)架构。在本小节中,我们采用 Keras 的 Sequential 顺序模型结构,自顶向下堆叠了三组“卷积层 + 最大池化层”的特征提取单元,通道数依次设为 56、28 和 16,利用渐进式的感受野与通道缩减机制捕获车辆的低阶边缘与高阶语义特征。特征图提取完毕后,通过 Flatten 层拉平为一维向量,并引入两层轻量化的全连接层进行高维特征整合,同时配置 Dropout 层以降低过拟合风险。最后的输出层采用 Sigmoid 激活函数,输出单一概率值以完成汽车与摩托车的二分类判定,并通过 model.summary() 打印出网络的整体参数结构。

# 初始化 Sequential 顺序神经网络模型实例model = Sequential()# 第一组特征提取层:56个 3x3 卷积核,ReLU 激活函数,输入形状为 (224, 224, 3) 的三通道彩图model.add(Conv2D(56, kernel_size = (3,3), activation = 'relu', input_shape=(224, 224, 3)))model.add(MaxPooling2D((2,2))) # 2x2 最大池化,对特征图进行下采样以降低空间尺寸# 第二组特征提取层:28个 3x3 卷积核,进一步提取深层抽象视觉特征model.add(Conv2D(28, kernel_size = (3,3), activation = 'relu'))model.add(MaxPooling2D((3,3))) # 3x3 最大池化,快速压缩特征图尺寸并保留核心响应# 第三组特征提取层:16个 3x3 卷积核,精炼高阶特征表示model.add(Conv2D(16, kernel_size = (3,3), activation = 'relu'))model.add(MaxPooling2D((2,2))) # 2x2 最大池化下采样# 展平层:将三维特征图矩阵拉平转化为一维特征向量,以便接入后续的全连接层model.add(Flatten())# 全连接分类网络:32 个神经元的全连接隐藏层,使用 ReLU 激活函数model.add(Dense(32, activation = 'relu'))# 全连接隐藏层:14 个神经元,进一步做高维特征组合model.add(Dense(14, activation = 'relu'))# Dropout 正则化层:在训练过程中随机断开 20% 的神经元连接,防止模型对训练集过拟合model.add(Dropout(0.2))# 二分类输出层:单个神经元搭配 Sigmoid 激活函数,输出图像属于某一类别(如汽车)的预测概率值model.add(Dense(1, activation = 'sigmoid'))# 打印模型的网络结构摘要,展示每一层的输出形状与可训练参数总量model.summary()

通过网络结构的构建与层次信息的输出,我们可以清晰地看到数据在网络中的流转与降维过程。这种层级递进的卷积与池化组合能够极大地减少可训练参数的规模,在保障特征提取能力的前提下降低计算复杂度,全连接层与 Dropout 的协同运作则保证了模型在分类判别时的稳定度与泛化性能。

4.6训练模型

在完成神经网络架构的设计后,需要对模型进行编译配置并启动拟合训练过程。在本小节中,我们选用二元交叉熵(Binary Cross-Entropy)作为损失函数,该函数能够精准衡量二分类输出概率与真实标签之间的偏差;优化器则选用自适应学习率的 Adam 算法,以确保梯度下降过程高效且平稳;同时指定准确率(Accuracy)作为训练过程中的核心监控指标。随后,我们将准备好的训练集与验证集数据生成器传入 model.fit 函数中,设置迭代训练轮数为 10 轮,并将训练过程中产生的损失值与准确率变化数据完整记录在 history 对象中,以便后续对模型的收敛轨迹进行定量可视化分析。

# 编译模型:配置二分类交叉熵损失函数、Adam 自适应优化器以及准确率评估指标model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['accuracy'])# 启动模型训练:传入训练集与验证集生成器,设置迭代轮数为 10 轮,并将训练历史记录保存在 history 变量中history = model.fit(    train_generator,     validation_data=validation_generator,    epochs=10)

4.7模型评估

模型训练完成后,首先需要对训练过程中的动态指标进行可视化诊断,以直观评估网络的收敛状态与泛化能力。在本小节中,我们利用 matplotlib 与 seaborn 构建双子图画布,分别绘制训练集与验证集(测试集)在 10 个 Epoch 期间的 Loss(损失值)和 Accuracy(准确率)演变曲线。通过观察曲线的下行与上升趋势,可以清晰判断模型是否存在过拟合或欠拟合现象,并验证优化算法在训练过程中的稳定性。

# 创建 1 行 2 列的子图画布,设置图像整体尺寸为 14x5fig, axes = plt.subplots(1, 2, figsize = (14, 5))# 在第一个子图中绘制训练集与测试集的损失(Loss)变化曲线sns.lineplot(ax = axes[0], data = history.history['loss'], label = 'training loss')sns.lineplot(ax = axes[0], data = history.history['val_loss'], label = 'testing loss')axes[0].set_title('Loss')        # 设置子图标题为 Lossaxes[0].set_xlabel('Epochs')    # 设置横坐标为训练轮次 Epochsaxes[0].set_ylabel('Loss')      # 设置纵坐标为损失值 Lossaxes[0].legend()                # 显示图例# 在第二个子图中绘制训练集与测试集的准确率(Accuracy)变化曲线sns.lineplot(ax = axes[1], data = history.history['accuracy'], label = 'training accuracy')sns.lineplot(ax = axes[1], data = history.history['val_accuracy'], label = 'testing accuracy')axes[1].set_title('Accuracy')   # 设置子图标题为 Accuracyaxes[1].set_xlabel('Epochs')    # 设置横坐标为训练轮次 Epochsaxes[1].set_ylabel('Accuracy')  # 设置纵坐标为准确率 Accuracyaxes[1].legend()                # 显示图例# 自动调整子图间距,展示绘制好的指标变化曲线图plt.tight_layout()plt.show()

除了整体的准确率指标外,对于二分类任务而言,还需要通过多维度的量化指标综合考量模型的判别精度。在本小节中,我们编写了 get_true_and_predicted_labels 提取函数,遍历验证集生成器以获取完整的真实标签与预测概率,并设定 0.5 作为二分类阈值将连续概率转化为离散类别。随后,利用 Scikit-Learn 库计算混淆矩阵(Confusion Matrix)、精确率(Precision)、召回率(Recall)以及 F1 分数(F1 Score),以全面评估模型对车辆类别的辨识性能。

# 定义用于提取生成器中全量真实标签与模型预测标签的工具函数def get_true_and_predicted_labels(generator, model, threshold=0.5):    true_labels = []    pred_labels = []    # 遍历数据生成器中的图片与对应标签批次    for images, labels in generator:        preds = model.predict(images)                # 将模型输出的连续概率值按阈值(0.5)转换为 0 或 1 的二分类标签        pred_labels.extend((preds > threshold).astype(int))                # 处理并保存真实标签,兼容不同维度的标签数组格式        if len(labels.shape) > 1:            true_labels.extend((labels > threshold).astype(int))        else:            true_labels.extend(labels)        # 当提取样本数达到生成器总样本量时终止遍历,防止数据生成器无限循环        if len(true_labels) >= generator.samples:            break    return np.array(true_labels), np.array(pred_labels)# 调用函数获取验证集上的真实标签数组与预测标签数组true_labels, pred_labels = get_true_and_predicted_labels(validation_generator, model)# 计算混淆矩阵以及二分类评估的核心指标:精确率、召回率、F1分数conf_matrix = confusion_matrix(true_labels, pred_labels)precision = precision_score(true_labels, pred_labels, average='binary')recall = recall_score(true_labels, pred_labels, average='binary')f1 = f1_score(true_labels, pred_labels, average='binary')# 格式化输出量化评估结果,保留四位小数print(f'Confusion Matrix:n{conf_matrix}')print(f'Precision: {precision:.4f}')print(f'Recall: {recall:.4f}')print(f'F1 Score: {f1:.4f}')

为了进一步直观展现模型在不同类别(汽车与摩托车)上的细分预测分布,我们将数值形态的混淆矩阵转化为直观的热力图(Heatmap)。在本小节中,我们封装了 plot_confusion_matrix 函数,从验证集生成器中提取类索引字典作为坐标轴标签,并使用 seaborn 的 heatmap 组件绘制带有数值标注的热力图,将真正例(TP)、假正例(FP)、真负例(TN)与假负例(FN)的分布情况进行视觉呈现。

# 定义混淆矩阵热力图绘制函数,接收混淆矩阵和类别名称列表作为参数def plot_confusion_matrix(cm, class_names):    plt.figure(figsize=(8, 6)) # 设置画布尺寸为 8x6    # 使用 seaborn 绘制热力图,显示具体数值 (fmt='d'),采用 Blues 蓝色调渐变映射    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)    plt.xlabel('Predicted Label') # 设置横轴为预测类别标签    plt.ylabel('True Label')      # 设置纵轴为真实类别标签    plt.title('Confusion Matrix') # 设置图像标题为 Confusion Matrix    plt.show()                    # 展示混淆矩阵热力图# 从验证集生成器的 class_indices 字典中提取类别名称列表class_names = list(validation_generator.class_indices.keys())# 调用绘图函数,将计算得到的混淆矩阵进行可视化展示plot_confusion_matrix(conf_matrix, class_names)

4.8模型预测

在完成了模型的批量量化评估后,通常需要通过直观的单样本推理来检验模型在实际场景下的预测表现。在本小节中,我们定义了 process_image 单图预处理函数,将输入的单张图像统一缩放至 224 x 224 像素,并进行维度扩展(增加 Batch 维度)与像素值归一化,使其符合模型的输入张量要求。随后,我们分别从验证集的汽车(Car)和摩托车(Bike)文件夹中随机抽样若干图片,使用已训练好的卷积神经网络模型依次进行前向推理计算。最后,利用 Matplotlib 构建多行多列的网格画布,将原图与其对应的真实标签(Actual)和模型预测标签(Predicted)组合展示,从而直观验证模型在不同真实图像上的泛化辨识能力。

# 定义用于推理预测的单张图像预处理函数,输入可为文件路径或 PIL Image 对象def process_image(img, target_size=(224, 224)):    # 如果传入的是字符串路径,则从路径加载图像并缩放至指定尺寸    if isinstance(img, str):        img = image.load_img(img, target_size=target_size)    else:        # 如果已是图像对象,则直接执行尺寸调整        img = img.resize(target_size)    # 将 PIL 图像对象转换为 NumPy 数组格式    img_array = image.img_to_array(img)    # 在第 0 维增加批次维度 (Batch Dimension),将形状由 (224, 224, 3) 扩展为 (1, 224, 224, 3)    img_array = np.expand_dims(img_array, axis=0)    # 将 RGB 像素值从 [0, 255] 归一化映射到 [0, 1] 范围    img_array /= 255.0  # Normalize to [0, 1]    return img_array# 指定验证集下汽车与摩托车子文件夹的路径car_test_path = '/kaggle/working/output/val/Car'bike_test_path = '/kaggle/working/output/val/Bike'# 调用样本加载函数,分别读取汽车和摩托车的测试样本图像列表img_car = load_sample_images(car_test_path)img_bike = load_sample_images(bike_test_path)# 将两类测试图片组合为嵌套列表,准备进行网格可视化展示test_img = [img_car, img_bike]# 创建 2 行 N 列的子图画布(N 为加载的样本数量),设置整体图像尺寸为 20x12fig, axes = plt.subplots(2, len(img_car), figsize=(20,12))# 定义两行对应的真实类别标题前缀title = ['Actual: Car', 'Actual: Bike']# 嵌套循环遍历类别与对应图像,逐张进行推理预测与子图绘制for row, category in enumerate(test_img):  for i, img in enumerate(category):    # 对当前单张图像进行前向推理前的标准预处理    processed_img = process_image(img)    # 输入模型进行前向传播预测,输出 Sigmoid 概率值    pred = model.predict(processed_img)    # 根据概率值(以 0.5 为界)判定预测类别,拼装预测标题文本    pred_title = ' | Predicted: Bike' if pred[0][0] < 0.5 else ' | Predicted: Car'    # 在对应的子图位置绘制原始图像    axes[row, i].imshow(img)    # 设置子图标题为:真实类别 + 模型预测类别    axes[row, i].set_title(title[row] + pred_title)    # 隐藏坐标轴刻度线以美化展示效果    axes[row, i].axis('off')# 设置整张大图的主标题,加粗显示plt.suptitle('Predcition from Test Data', fontweight='bold')plt.tight_layout() # 自动调整子图布局间距plt.show()          # 显示可视化的推理结果网格

5.总结

本实验基于 Kaggle 提供的 2000 张包含多样化视角与款式的汽车与摩托车无预处理图像数据集,通过科学划分数据集并应用针对性的图像增强技术,成功构建并训练了一个基于 Sequential 架构的卷积神经网络(CNN)二分类模型。实验评估结果显示,模型在测试集上表现出了优异的特征提取能力与泛化性能,不仅取得了 0.9367 的精确率和 0.9250 的召回率,其综合评估指标 F1 分数也达到了 0.9308,同时混淆矩阵的预测分布也进一步印证了网络对于两类车辆核心结构特征的高效捕捉。这表明该模型不仅能够克服复杂背景与车型多样性带来的判别挑战,也为后续在轻量化图像分类及实际边缘设备部署等场景中的应用奠定了坚实的技术基础。

相关推荐

数据科学领域优质创作者,全网粉丝26w+,专注于数据分析、数据挖掘,感谢关注与支持。

微信公众号