ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于Keras的猫狗图像分类实战:从数据增强到CNN调参全记录

基于Keras的猫狗图像分类实战:从数据增强到CNN调参全记录 简介一份基于Keras的猫狗分类识别实验报告完整覆盖机器学习期末大作业的常见板块面向需要完成《机器学习》课程报告、图像分类项目或期末答辩的高校学生既可作为高分范文参考也可作为动手复现的实验指南。报告围绕Kaggle的Dogs vs. Cats数据集系统讲解CNN原理、数据组成、损失函数与评价指标并以平衡二分类问题为背景设计完整实验流程内容从数据预处理、模型搭建到结果评估均有细致说明。压缩包内共1个docx文档大小5.16MB附算法流程图、运行结果截图和核心代码便于对照梳理实验思路。全文依次包括摘要、引言、主体内容、实验与结果分析、结论及参考文献特别是对图像尺寸异常、颜色异常和标签标注异常的处理进行了创新性探索利用预训练模型配合自定义阈值筛选错误标签思路清晰。目前已有7899人学习/下载适合需要系统掌握CNN图像分类全流程的大学生与机器学习初学者。 这次大作业做的是机器学习经典入门项目——基于Keras的猫狗分类识别。相信很多同学都在期末报告选题时纠结过既要模型效果拿得出手又要能把原理讲清楚还得在有限的硬件条件下跑得动。猫狗分类恰好是这类题目的理想选择数据公开好获取任务直观不抽象又有足够的技术深度可以展开写。这篇就把我完整做下来的过程记录下来包括环境配置、数据预处理、模型设计、训练调参、结果分析以及踩过的一堆坑给后面选这个题或者做类似图像分类项目的同学一个能直接照着复现的参考。我最终的模型准确率达到了93%以上训练时间在普通笔记本CPU上大约40分钟左右用了GPU会快得多代码只有不到200行整个实验从零到报告完成用了三个晚上。这个投入产出比在大作业里算是相当划算的而且过程中覆盖了数据增强、CNN、过拟合控制、训练曲线分析等高频考点答辩时完全不虚。1. 项目背景与实验目标1.1 为什么选猫狗分类而不是其他题目图像分类是机器学习里最直观也最“出效果”的方向之一而猫狗分类又是图像分类里最经典的数据集。选它的理由其实很实在第一Kaggle上的Dogs vs Cats数据集是公开且规范的无需自己费劲爬数据也避免了标注质量参差不齐的问题第二猫和狗的图像差异体现在毛色、轮廓、五官布局等多方面既能让模型学到纹理特征又能体现卷积神经网络在空间特征提取上的优势第三这个任务做出来可视化效果特别好预测结果用图片一摆老师一眼就能看懂你做了什么。我当时也考虑过用更花哨的CIFAR-10或者交通标志分类但后来放弃了。CIFAR-10类别太多对期末大作业来说训练成本高讲起来也容易散猫狗分类就两类别二分类问题在评价指标、损失函数、决策边界这些概念的讲解上都更聚焦。如果未来还有余力完全可以把猫狗二分类的代码改一改换成猫、狗、鸟三分类正好能顺势写一段“多分类扩展”作为加分项。1.2 实验环境与版本选择环境问题看着简单实际操作时坑最多。我用的组合是Python 3.8 TensorFlow 2.6 Keras 2.6这里有个很重要的点要提醒2.6之后TensorFlow和Keras的集成方式变化比较大网上很多老教程会给出keras.开头的代码新版本跑起来会报错。建议直接安装统一的TensorFlow即可from tensorflow import keras一路写到底兼容性最有保障。硬件方面我的笔记本是i5-9300H处理器、16GB内存、没有NVIDIA独立显卡纯CPU训练。原本担心跑不动实际测下来单epoch大约45到60秒25个epoch全部跑完不到半小时。如果你有NVIDIA显卡装上CUDA和cuDNN之后训练时间会缩短到原来的十分之一甚至更少。这里不建议为了跑得快特意去租云GPU猫狗分类这个小任务不值得花那个钱。数据集我用的Kaggle原始数据集训练集一共25000张图猫狗各12500张。考虑到期末作业不需要追求极致精度我从里面抽了6000张每类3000张做训练再抽2000张每类1000张做验证。这个数据量对CNN来说够用训练速度也适中写报告时还能多一个“数据规模对精度影响”的图表素材。1.3 报告的整体结构规划做实验前我先把报告框架列了出来这是整个项目里我认为最值得偷懒的地方——先定结构再填内容。大作业报告我规划成七个部分问题定义与数据描述、相关技术介绍、数据预处理与增强、模型设计、训练过程与结果分析、常见问题与改进方向、总结。这样做的好处是写代码的时候就知道每一步要保存什么图表、记录什么数据不需要最后补实验。技术选型上我在Keras和纯TensorFlow之间纠结过几天。最后选了Keras因为对这个体量的任务来说Keras把网络搭建、编译、训练封装得很干净让我能把精力放在理解卷积层、池化层、激活函数这些概念上而不是花大量时间在底层API的调试上。如果你后续想往深度学习方向深入建议做完这个大作业后再用纯TensorFlow或PyTorch重写一遍模型感受会很不一样但那是后话期末阶段先把Keras吃透更重要。2. 数据预处理与样本增强2.1 目录结构与代码组织数据预处理的第一步不是写代码而是先把数据目录设计好。我用Keras的ImageDataGenerator来读取数据它有一个硬性要求数据要按类别分文件夹存放并且目录结构直接对应标签。我的目录结构是这样dataset/ ├── train/ │ ├── cat/ # 3000张 │ └── dog/ # 3000张 └── validation/ ├── cat/ # 1000张 └── dog/ # 1000张很多同学图省事把所有图片放在一个大文件夹里然后自己写标签文件这等于绕开了Keras的便捷设计。我建议还是老老实实按目录分类因为flow_from_directory会直接根据子目录名生成标签还能自动统计类别数代码简洁且不容易出错。代码组织上我没有把全部代码压在一个文件里而是分了三个文件data_prepare.py负责从原始数据集抽样并生成上面的目录结构train.py负责模型构建与训练predict.py负责加载模型并对单张图片做预测和可视化。对大作业来说这种划分既符合工程实践习惯又能在报告里展示代码模块化能力属于加分项。2.2 图像归一化与统一尺寸数据读进模型前有两个必须做的操作统一尺寸和归一化。我选的是target_size(150, 150)这个尺寸是Keras官方教程里的经典取值。对于猫狗分类150x150分辨率的图像足够模型提取出猫咪胡须、狗耳朵这些关键特征同时比224x224的ImageNet标准尺寸省不少计算量。如果你显存特别小可以降128x128但不要低于100x100否则狗的耳朵和猫的眼睛这些细节会被压缩到几乎看不见。归一化这一步我见的错误太多了。图像读进来是0到255之间的整数像素值如果不做处理直接喂给网络数值范围过大会导致梯度更新不稳定loss可能出现“原地抖动”的情况。常见做法就是烧掉整张图的数值范围让它变成0到1之间的小数Keras里一句话就能做train_datagen ImageDataGenerator(rescale1./255) validation_datagen ImageDataGenerator(rescale1./255)rescale1./255会将像素值从[0, 255]映射到[0, 1]。很多同学忘了验证集也要做同样的归一化这是一个隐蔽的错误模型训练时看到的输入范围是0-1实际预测时如果输入却是0-255分布直接不一致准确率看起来就会莫名其妙地低。2.3 用数据增强应对小数据集过拟合我手里只有6000张训练图直接训练CNN很容易过拟合。验证集准确率上不去、训练集准确率却接近100%这就是典型的过拟合信号。解决过拟合的办法有很多包括简化模型、加大L2正则、加Dropout但最贴合图像任务的方法还是数据增强——在训练时随机对图片做小角度旋转、平移、翻转让模型“看到”更多样的样本。我用的是Keras的ImageDataGenerator增强参数代码如下train_datagen ImageDataGenerator( rescale1./255, rotation_range40, width_shift_range0.2, height_shift_range0.2, shear_range0.2, zoom_range0.2, horizontal_flipTrue, fill_modenearest )这里每个参数的取值逻辑要说一下rotation_range40表示图片最多随机旋转40度猫狗的朝向变化很大这个范围合理width_shift_range和height_shift_range都是0.2允许图片水平或垂直平移20%模拟拍摄对象不在画面中心的情况horizontal_flipTrue对猫狗分类特别有效因为猫左右脸并没有本质区别而图片水平翻转恰好能扩充双倍样本。我没开vertical_flip因为正常照片里猫狗不会是倒立的用这个反而会生成不符合真实分布的训练样本。增强操作只加在训练集上验证集只做rescale不做增强。这个细节写报告时一定要解释清楚验证集的目的是评估模型在真实数据上的表现如果也跟着做增强评估结果就不再反映真实场景了。我在报告里专门留了一小段说明这个问题作为“数据增强的注意事项”。3. CNN模型的构建与参数选择3.1 网络结构设计的思路我的网络结构参考了VGG的设计思想但做了大幅简化。核心思路是先用卷积层提取低阶特征边缘、颜色块再通过池化层压缩特征图尺寸接着用更多卷积层组合出中高阶特征眼睛、耳朵轮廓最后接入全连接层完成分类。具体结构如下层类型输出尺寸参数细节Conv2D(150, 150, 32)3x3卷积核ReLUMaxPooling2D(75, 75, 32)2x2池化窗口Conv2D(75, 75, 64)3x3卷积核ReLUMaxPooling2D(37, 37, 64)2x2池化窗口Conv2D(37, 37, 128)3x3卷积核ReLUMaxPooling2D(18, 18, 128)2x2池化窗口Conv2D(18, 18, 128)3x3卷积核ReLUMaxPooling2D(9, 9, 128)2x2池化窗口Flatten(10368)展平Dropout(10368)随机失活0.5Dense(512)ReLUDense(1)Sigmoid这个结构有两点按我的实际经验做了调整一是没有一上来就用很多卷积核第一层32个足够了这种规模的分类任务第一层用64甚至128属于浪费算力还可能加剧过拟合二是在Flatten之后加了一个Dropout层失活率取0.5。Dropout是控制过拟合的大杀器它让每次训练随机忽略一半神经元相当于同时训练多个不同的网络再集成泛化能力提升非常明显。卷积核大小固定用3x3这是很多经典网络的共识。两个3x3卷积堆叠的感受野等同于一个5x5卷积但参数量更少非线性表达能力还更强。我在报告里画了示意图来对比这两种做法的区别也让指导老师觉得我对卷积网络的原理理解足够深入。3.2 模型编译损失函数、优化器与评估指标模型搭建完后的编译环节三项配置要权衡清楚。损失函数选的binary_crossentropy因为猫狗分类是二分类问题输出层只有一个神经元用Sigmoid激活加二分类交叉熵是最标准的组合。有些同学会在这里误用categorical_crossentropy那是多分类配Softmax的用到二分类上会出问题。优化器我选了Adam学习率默认是0.001。Adam的好处是自带自适应学习率调整对新手非常友好省去了手动调整学习率的麻烦。试过SGD加动量收敛速度比Adam慢不少对于限时实验不划算。不过Adam也不是万能的它有时会收敛到比精细调过的SGD更低的精度但对于期末大作业这个精度差异完全在可接受范围内。评估指标用的accuracy但如果想在报告里写得更深入建议在预测阶段追加计算精确率Precision、召回率Recall和F1分数。我最终在测试集上的数据是精确率0.935召回率0.927F1分数0.931。这三个指标能看出模型是否存在偏向某一类别的问题写进报告会比单一准确率更有说服力。3.3 训练参数batch_size、epochs与学习率训练参数里面batch_size我定为32。这个是权衡显存和梯度稳定性的结果太小了比如8会导致梯度更新方向不稳定loss曲线大幅度震荡太大了虽然稳定性好但每轮迭代时间明显变长对硬件不友好。32是图像分类任务里适用范围很广的取值如果你用GPU训练可以试试64训练时间会缩短一些准确率不会有明显变化。epochs我设了50个同时配合EarlyStopping回调函数。EarlyStopping的作用是当验证集loss连续多轮不再下降时就自动终止训练避免浪费时间。我设了patience5意思是连续5个epoch验证集loss都没有改善就停止。实际训练时模型在第24轮触发早停结束正好验证了“不是训练轮数越多效果越好”这个关键概念。写报告时我把训练曲线截图放进去可以看到验证集loss在第15轮之后基本进入平台期训练时间再长也只是白白增加过拟合风险。学习率用的默认0.001没有额外设置学习率衰减策略。如果训练后期发现loss在小范围内抖动可以考虑在第15个epoch之后把学习率降到0.0001这个在报告里可以作为“继续优化方向”来写。4. 训练过程与结果分析4.1 训练曲线怎么看训练完成后第一件事不是看准确率而是把训练曲线画出来。我分别画了准确率曲线和损失曲线两条曲线各包含train和validation两个版本。怎么看这些曲线是有门道的训练集和验证集曲线同步上升说明模型正在正常学习如果训练集曲线继续上升但验证集曲线掉头向下说明出现过拟合如果两条曲线都上不去可能是学习率太大或网络结构有问题。我那次训练的准确率曲线大致趋势是前3个epoch快速上升从随机猜测的50%左右直接跳到70%多第5到第15个epoch呈现稳步上升每轮约提升1到2个百分点到第15轮以后涨幅明显收窄最终停在93%附近。这个形态写报告时很有价值因为可以结合“特征提取层先学边缘后学轮廓”的知识点去解释曲线为什么是这个形状。训练曲线的图片在我的报告里占了不小的篇幅但我没有只贴图不解释而是逐段标注了关键转折点。这是期末报告的高分秘诀之一图表要配分析分析要落到“为什么”。4.2 混淆矩阵与示例预测准确率虽然直观但会掩盖类别之间的差异。我额外用验证集2000张图生成了混淆矩阵。猫被识别成狗的数量是68张狗被识别成猫的数量是72张分布比较均匀说明模型没有明显的类别偏好。这个信息量比单独一个93%准确率要大得多比如老师问你“模型对哪个类别更容易出错”你光看准确率答不上来但看了混淆矩阵就能精确地回答。示例预测这部分最有意思我保存了12张验证集图片把模型预测结果和真实标签同时展示出来并特别挑选了4张预测错的图片。分析错误样本的规律比看正确样本更有价值——我这4张错误图片里有两张是猫蜷缩成一团、只露出背部花纹的还有一张是泰迪犬毛发遮挡了眼睛。这类共同特征可以总结成“模型对姿态极度遮挡的图片容易混淆”顺手引出数据增强的改进方向。老师看到你连错误案例都做了归因分数一定不会低。4.3 从实验结果中提炼“高分结论”写完实验数据之后我总结出三个可以用在答辩中的核心结论第一CNN在猫狗分类任务上明显优于传统特征提取HOG/SVM的方案无需人为设计特征就能自动从像素级数据中学习到高层语义信息第二数据增强和Dropout的加入使验证集准确率从大概85%提升到了93%说明在小数据集上正则化策略是决定模型泛化性能的关键因素第三模型对纹理、颜色和轮廓的依赖程度存在明显差异纯色猫的识别准确率显著高于花色复杂的猫。这三个结论不是从论文里抄的是结合自己的训练过程得出的所以答辩时有底气。写报告的时候我把每个结论都对应到了具体的实验证据上第一个结论对应CNN特征图可视化第二个对应有无数据增强的对比实验第三个对应错误样本分析。做到这一点报告就不是实验数据的堆砌而是一条完整的推理论证链。5. 常见问题与排查实录5.1 训练loss降不下去怎么办我最开始跑的时候训练loss在前几个epoch里几乎不变一直徘徊在0.69左右。0.69是个很有意思的数字它接近ln(2)也就是随机二分类的交叉熵理论值这说明模型根本没在学。排查下来原因是学习率设置不合适吗不是真正的原因是我最初忘了把像素归一化像素值范围太大导致梯度更新不稳定。加上rescale1./255之后loss立刻开始下降。如果遇到类似情况排查优先级建议是先看数据归一化是否忘记再看标签是否配对正确然后看网络结构是否有问题比如误用了不合适的激活函数最后才考虑调整学习率。这个顺序是按照修改成本从低到高排的绝大多数新手问题都出在前两步。5.2 验证集准确率震荡厉害怎么处理训练中段我遇到了验证集准确率在72%到81%之间反复波动的情况。训练集准确率一直稳步上升验证集却上蹿下跳这说明模型处于过拟合的边缘。我当时做了三件事第一个是增加了Dropout层从无到0.5第二个是打开了数据增强第三个是把batch_size从16改成32。三个操作叠加后震荡幅度明显减小曲线变得平滑。这里有一个容易混淆的点数据增强并不总是立竿见影。加了增强后训练集准确率会下降几个百分点这是正常的因为模型看到的训练样本变难了但验证集准确率的稳定性会更好。如果只看训练集准确率就以为模型变差了那就被表面现象骗了。5.3 常见报错与排查速查表实际操作过程中遇到的报错我整理成了一个速查表后续同学可以直接对照排查报错信息常见原因解决方案Data cardinality is ambiguous训练数据与标签数量不一致检查目录下图片数量确保数据加载路径正确ValueError: Input 0 of layer ... incompatible输入尺寸与网络第一层不匹配统一target_size与模型输入尺寸CUDA out of memorybatch_size过大或GPU显存不足调小batch_size降分辨率Unknown image file format数据集中包含损坏或不支持格式的图片用os.listdir检查并过滤异常文件或用PIL统一转换NotFoundError: No such file or directory路径配置错误检查相对路径与工作目录用绝对路径最保险AttributeError: module tensorflow has no attribute kerasTensorFlow版本过旧或安装不完整升级TensorFlow到2.x使用from tensorflow import keras最隐蔽的坑是“Unknown image file format”Kaggle原始数据集里有少量损坏图片和无法识别的格式训练到中途突然报错。我在data_prepare.py里加了一段预处理代码用Pillow逐张打开确认能正常读取后才保留这样就彻底规避了这个问题。5.4 训练时间太长怎么办如果你和我一样用CPU训练一个epoch要一分多钟完整跑下来确实煎熬。三个亲测有效的方案一是把图片分辨率降到120x120甚至128x128精度损失不大但训练速度提升明显二是把训练集缩减到4000张准确率大概会掉2到3个百分点但对大作业分数影响有限三是先小规模试跑3个epoch确认代码没问题后再全量训练避免跑到一半才发现bug的尴尬。补充一点如果实验室有GPU机器可以把代码原封不动搬过去跑TensorFlow会自动检测到GPU。唯一要注意的是GPU版的CUDA和cuDNN版本必须匹配否则会报“Could not load dynamic library”的错误这个坑我帮同学排查了不少次。6. 模型效果提升方向与报告写作心得6.1 如果想继续提升准确率我的模型在验证集上达到93%左右已经满足期末大作业的要求。如果你时间充裕想冲击95%以上的准确率我有三个方向的建议按性价比排序第一使用迁移学习加载在ImageNet上预训练好的VGG16或ResNet50冻结前几层只训练后面的分类层训练速度快且精度提升非常明显95%以上是常规操作第二做交叉验证和模型集成多个模型的投票结果通常比单个模型更稳定第三做更精细的超参数搜索比如用keras-tuner自动搜索学习率和卷积核数量。迁移学习是大作业里很讨巧的加分项代码改动不大效果却非常直观。我当时没选这个方案是因为想重点展示自己从零搭建网络的完整思路如果你之前的报告里已经有过CNN的内容这次用迁移学习反而显得技术面更广。6.2 写报告时哪些图和表格必不可少交期末报告前我总结了一份“必备图表清单”任何一个内容都可以直接用于任何类似的深度学习大作业。网络结构图必须要有可以用Keras的plot_model生成也可以用绘图工具手绘训练过程的准确率曲线和loss曲线必须要有这是一条完整的证据链归一化前后的图片对比要有让阅读者对预处理有直观认识数据增强前后样本对比图强烈建议要有这是体现你对过拟合有深入理解的证明混淆矩阵和示例预测图也建议加上后者能让枯燥的数据分析瞬间变得生动。这些图表之外硬件配置和实验耗时建议写清楚老师会据此判断实验的可复现性。报告的文字部分也有技巧不要大段粘贴代码而是挑关键片段配合注释讲解完整代码放到附录或提供链接。每个小节尽量以“结论证据分析”三步来组织比如“使用数据增强后验证集准确率提升了8个百分点证据原因是分析”这样整份报告的结构会非常清晰。6.3 这次实验留给我的一些思考最后说点做完整轮实验的个人感受。我在跑完整个项目之后反而更加理解了为什么二分类是深度学习的入门任务因为它能让所有核心概念都在最简形式下展开不会因为任务本身的复杂性干扰对原理的把握。猫狗分类看起来很简单但数据加载、预处理、模型构建、训练调参、评估分析这一整套流程走完深度学习项目的骨架就扎实了之后无论换到人脸识别还是文本分类核心方法论都是一样的。再补充一个小技巧训练过程中实时观察loss变化很有帮助。Keras的History对象会自动记录每个epoch的loss和准确率训练结束用matplotlib一条命令就能画出曲线不用自己在训练过程中手动记录任何数值。当时我在控制台看到每个epoch结束都会自动打印一行数据这反而成了判断训练是否正常的核心依据。如果后续有时间我打算把这个模型移植到移动端跑实时猫狗识别顺便研究一下模型量化和剪枝那是深度学习中跟工程化结合很紧密的方向也是目前行业里很受关注的话题。不过那就是下一个阶段的事了先把这次大作业的完整流程吃透对你来说就已经是往前走了一大步。本文还有配套的精品资源点击获取
返回列表