☰
基于Python与CNN的猫体型三分类识别系统实现
2026/10/20 4:19:13 网站建设 项目流程

这个标题我特别眼熟,几乎每年都会在毕业设计的选题清单里看到一版类似的。用一句话翻译过来就是:用Python搭一个卷积神经网络(CNN),让模型拿到一张猫的照片后,判断这只猫的体型属于偏瘦、正常还是偏胖。很多同学第一反应是“这能算课题吗”,但把任务拆开以后,你会发现它完整覆盖了数据标注、图像预处理、模型设计、迁移学习、训练调参、指标评估这整条链路,当毕设完全撑得住,而且后续稍微改一改,也能迁移到狗、牛羊的体况评分场景里。

这篇文章我就按这个题目的完整流程来讲,从任务定义、数据准备,到模型选型、训练细节,再到最后评估和扩展方向。每个环节我都会说清楚“为什么这么做”,尽量让没系统学过深度学习的同学也能照着复现出来。

1. 这个题目的本质:一个典型的三分类图像任务

1.1 “猫的体型识别”不是玄学:从BCS评分到三分类

很多同学拿到题目时第一反应是懵:体型这东西怎么定义?是不是得看猫胖不胖、肚子有没有下垂?其实兽医临床上已经有了一套相对成熟的判断标准,叫体况评分(Body Condition Score,简称BCS),一般是9分制:1分是严重消瘦,5分是理想体态,9分是重度肥胖。实际判断时会看腰线、腹部是否下垂、肋骨能不能摸到、尾巴根部有没有脂肪堆积等。

放到计算机视觉任务里,我们不可能让模型去“摸”猫,只能靠图像上的视觉特征。所以最稳妥的做法,是把9分制简化成三分类:1~3分映射为“偏瘦”,4~5分映射为“正常”,6~9分映射为“偏胖”。这样一来,问题就变成了一个标准的图像三分类任务,卷积网络的输出层只需要三个神经元,接softmax得到概率分布,再接交叉熵损失就能训练。

这个简化过程很重要,它决定了数据标注和模型输出的口径。如果你直接把9个分数当成9个类别去做,数据量不够的情况下模型基本学不动,而且相邻分数之间本身就很模糊,标注员也难以稳定区分“6分”和“7分”。三分类则给了人工标注足够的容错空间,也让模型的任务边界更清晰。

1.2 为什么深度学习方案能胜任:对比传统手工特征

可能有人会问,判断体型是不是用传统图像处理就够了?比如先把猫从背景里分割出来,再算一下身体的长宽比、腹部轮廓曲率、轮廓填充度之类的几何特征。这类方法在纯色背景、正面标准姿势下确实能跑通,一旦照片变成家庭环境里的随手拍,背景杂乱、姿势千奇百怪、毛发长短不一,手工规则就非常脆弱。

CNN方案的核心优势是端到端。我们不手工设计特征,而是让网络从训练数据中自动学习“什么样的轮廓特征代表偏瘦、什么样的纹理特征代表偏胖”。卷积层通过局部感受野提取边缘、纹理、形状等底层特征,逐层抽象出“腰线是否明显”“腹部是否下垂”“整体是否圆润”这类高层语义信息。这跟你写一堆if-else规则不一样,只要数据够多,网络能自己学到泛化性更好的判断依据。

1.3 两条技术路线:自建小CNN和迁移学习怎么选

在实际项目中,路线基本分两条。一条是从零自建一个小型CNN,结构自己写,卷积层、池化层、全连接层都手搭出来,优点是结构完全透明,答辩时每个参数都能讲清楚来龙去脉,很适合用来解释卷积原理;缺点是参数量小、数据不够时精度往往一般。另一条是迁移学习,用预训练好的ResNet18、MobileNetV3等模型做特征提取,只替换最后的全连接分类头,优点是收敛快、精度高,是现在绝大多数图像分类项目的主流做法。

我个人的建议是,毕设不要只走一条路。先用自建小网络把全流程跑通,让每个环节都心里有数,再切换到迁移学习刷一轮指标,把两种方案的结果做成对比,这样既有原理讲解又有实验深度,答辩时的素材也丰富得多。两种方案的对比我整理成了一张表:

对比项自建小CNN迁移学习(ResNet18等)
结构透明性极高,每层可解释中,特征层来自预训练模型
小数据集表现一般,容易欠拟合好,预训练特征通用性强
训练成本低,几十分钟到几小时中,微调也需要一定轮次
答辩友好度高,方便讲原理较高,方便讲工程思路
推荐用法跑通流程、可视化特征刷指标、做最终效果

2. 数据准备:整个项目里最容易被低估的一步

2.1 数据从哪来:公开数据集和自建采集两手准备

猫体型识别不是一个大热门的公开任务,所以很难直接找到一个现成的“猫体况分类数据集”。通用的做法是两个来源结合:一是先从深度学习竞赛平台上常见的宠物图像数据集中筛选猫科照片,这类数据量大、背景多样,适合作为基础素材;二是自行采集和标注,身边朋友的猫、宠物店的猫、网上可合法使用的开放图片,都可以在确认授权的前提下纳入。

重点在于确认授权问题。我接触过一些项目,直接用爬虫抓了几千张图就开训,最后准备写毕业论文时才发现版权和授权说不清楚,只能把数据部分重写一遍,非常折腾。稳妥起见,自建部分尽量用自己拍摄或明确标注可自由使用的图库,公开部分要记录好来源和许可信息,这在毕设查重和后续公开时会少很多麻烦。

2.2 标注规范:把“胖瘦”变成可操作的标准

标注这件事看起来简单,实际是项目最影响效果的一环。我给一个可以抄作业的标注规范:优先选择猫的侧面站立照,要求身体完整可见,躯干没有被遮挡,尾巴不遮住腹部;正面照和趴卧照单独处理,不要和侧面照混在一起标注,因为姿态差异会直接影响轮廓特征;照片里最好只有一只主体猫,多只猫混在一起会给模型引入大量无关信息。

另一个容易犯的错是只按“看起来胖不胖”凭感觉标。更好的做法是先让标注员理解BCS三分类判据,比如偏瘦类主要看腰线凹进、肋骨轮廓明显;正常类看腰线略收、腹部平滑;偏胖类看腰线消失、腹部下垂呈梨形。有条件的话,让两个人分别标一批,再对不一致的样本讨论修正,能明显提升标注稳定性。

类别平衡也要提前控制。实际喂养环境下正常体型的猫大概占多数,偏瘦和偏胖的相对少一些,如果训练集里“正常”占了70%,模型很容易学成“无脑输出正常”。建议在采集时有意识地控制三个类别比例在1:1:1附近,实在不平衡,后面训练时再配合类别权重来兜底。

2.3 预处理和数据增强:不要让猫在输入阶段就已经“变形”

图像预处理里有一个关键细节:不要简单粗暴地把所有图Resize成正方形。直接拉伸会改变猫的宽高比,而体型判断恰恰依赖身体的比例关系,拉成方图之后,原本偏瘦的猫可能在视觉上变“宽”了,模型学到的东西就是错的。正确做法是等比缩放后做边缘填充,也就是常说的Letterbox方式,把图片放到统一的224×224画布里,多余部分填充灰色或黑色。

数据增强方面,常用的组合是随机水平翻转、随机旋转正负15度、随机亮度对比度扰动、随机裁剪缩放。不要轻易用垂直翻转,猫不会头朝下站着,这个增强会引入不符合现实的样本。分类任务里也可以用一点随机擦除,模拟猫被遮挡的场景,但擦除面积不要超过30%,否则会破坏整体轮廓信息。

3. 模型设计:卷积层、特征图和参数量怎么定

3.1 自建小CNN:重复的Conv-BN-ReLU-Pool结构

如果你打算先自建一个小模型练手,我建议按这个思路搭:输入层是224×224×3的RGB图像,经过几组卷积块提取特征。每个卷积块内部是卷积层、批归一化(BatchNorm)、ReLU激活、最大池化四件套。卷积负责提取局部特征,BN负责稳定训练分布,ReLU负责引入非线性,池化负责下采样、扩大感受野。

为什么要用BN?因为深层网络训练时,每层输入分布会随着前层参数变化而漂移,BN在每个mini-batch内做归一化,把数据拉回稳定范围,这样可以用更大的学习率、收敛更快。ReLU激活函数则比较简单,正区间梯度恒为1,能缓解梯度消失。

3.2 特征图尺寸变化计算:手算一遍心里就有底

自建网络的设计不是随便叠层数,特征图的尺寸变化要能算清楚。卷积层的输出尺寸公式是:

W_out = (W_in − F + 2P) / S + 1

其中F是卷积核大小,P是padding,S是步长。以一个224×224×3的输入为例,16通道的3×3卷积加padding=1,输出尺寸保持224×224;经过2×2最大池化后变成112×112。按这个逻辑往下走,特征图尺寸减半,通道数翻倍,这是经典的“通道数增加、空间尺寸缩小”设计模式。

我整理了一个示例参数表,方便你对照着算:

网络层输入尺寸卷积核/padding/stride输出尺寸通道数
Conv1 + BN + ReLU + Pool224×224×33×3, p=1, s=1112×11232
Conv2 + BN + ReLU + Pool112×112×323×3, p=1, s=156×5664
Conv3 + BN + ReLU + Pool56×56×643×3, p=1, s=128×28128
Conv4 + BN + ReLU + Pool28×28×1283×3, p=1, s=114×14256
Conv5 + BN + ReLU + Pool14×14×2563×3, p=1, s=17×7512
全局平均池化7×7×512—1×1512
全连接分类层512—3—

最后用全局平均池化把7×7变成1×1,再接三个神经元的全连接层,参数量会远小于直接把7×7×512拉平成一个大向量的做法,也不容易过拟合。

3.3 迁移学习实践:ResNet18替换分类头

如果你想用迁移学习,代码上只需要做一件小事:加载预训练模型,把最后一层全连接替换成输出3类的新全连接层。PyTorch里类似这样:

import torch.nn as nn import torchvision.models as models model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) in_features = model.fc.in_features model.fc = nn.Linear(in_features, 3)

这里有个新版PyTorch的细节要注意:旧代码里常见的是pretrained=True,新版本已经推荐用weights参数来指定权重版本,不然会报警告,而且以后维护也不方便。另外一个实用策略是分两阶段微调:先冻结特征提取层,只训练新加的全连接分类头,用一个稍大的学习率跑几个epoch,让分类头先适应新任务;然后解冻整个网络,把学习率调小到原来的十分之一,端到端微调,效果通常比一上来就全量训练要稳。

3.4 损失函数和优化器:为什么是交叉熵和AdamW

分类任务里最标准的损失函数是交叉熵(CrossEntropyLoss)。它做的事情是:对正确类别对应的预测概率取负对数。如果模型对真实类别的预测概率很接近1,损失就很小;如果预测概率很小,损失就非常大。这种梯度信号比均方误差更适合分类问题,因为梯度的大小和“错误程度”直接挂钩。

优化器方面我推荐AdamW而不是普通Adam。Adam本身对学习率不太敏感、收敛很快,但权重衰减的写法在原生Adam里会和梯度相关项耦合,导致正则化效果不稳定;AdamW把权重衰减独立出来,直接在参数更新时减去一个固定比例,正则效果更干净。实际项目里设weight_decay=1e-4就能有效抑制过拟合。

4. 训练流程与调参记录:从超参数到损失曲线

4.1 数据划分和超参配置:按猫个体分,不按照片分

数据集划分有一个特别容易踩的坑:如果同一只猫不同姿势的照片既出现在训练集又出现在测试集,模型等于“见过”这只猫,测试准确率会被严重虚高。正确的划分方式是按照“猫个体”来分,最好先给每只猫一个编号,然后把同一编号的所有照片分到同一个集合里,尽量保证训练集和测试集里是不同个体。

超参数方面,我给一套可以直接作为起点的配置:输入尺寸224×224,Batch Size 32或64,初始学习率1e-3(迁移学习微调阶段用1e-4~3e-4),优化器AdamW,权重衰减1e-4,训练轮次30到50,早停patience设为10个epoch。训练集、验证集、测试集按7:1.5:1.5划分,验证集用来做早停和调参,测试集最后才碰。

4.2 训练过程观察:loss下降和过拟合信号

训练时要盯的曲线主要是两条:训练集损失和验证集损失。理想情况是训练损失一路下降,验证损失先下降后在一个平台期稳定。如果训练损失还在降,验证损失却开始反弹,那就是典型的过拟合信号,这时候应该停下来,把模型回滚到验证损失最低的那个checkpoint,而不是等最后一个epoch的权重。

PyTorch里做early stopping可以手动保存验证集表现最好的状态,类似这样:

best_val_loss = float("inf") for epoch in range(num_epochs): train_one_epoch() val_loss = evaluate() if val_loss < best_val_loss: best_val_loss = val_loss torch.save(model.state_dict(), "best_model.pth")

用早停恢复最佳权重后,再用测试集评估一次,这样得到的准确率才是可信的最终结果。

4.3 实用技巧组合:多尺度、类别权重和测试期增强

训练技巧不需要太多,有三招在实践中性价比很高。第一招是余弦退火学习率调度,让学习率按余弦曲线从初始值衰减到接近0,比固定学习率在后期更容易收敛到更优的局部最小点。第二招是类别不均衡时给损失函数加权重,比如偏胖样本少,就在计算交叉熵时把偏胖类别的权重调高一点,PyTorch的CrossEntropyLoss(weight=...)直接支持。第三招是测试期的简单增强,把同一张图和它的水平翻转都过一遍模型,两个概率取平均再预测,通常能带来1到2个百分点的提升。

多尺度训练也是一个可选项,比如每一轮随机让模型看到大小在200到260之间缩放的图片再裁剪到224,相当于免费扩充了数据。但这个操作会显著增加训练时间,毕设项目里如果时间不是特别充裕,可以先不加。

5. 评估结果与常见问题排查

5.1 评估指标:准确率之外还要看混淆矩阵

很多同学做完项目只报一个整体准确率,比如“模型最终准确率87%”,这在答辩时很容易被追问。更严谨的做法是报告每类别的精确率(Precision)、召回率(Recall)、F1值,以及一个混淆矩阵。假设测试集有400张图,某次实验的结果形态大致可以是这样:

真实/预测偏瘦正常偏胖召回率
偏瘦11814884.3%
正常12131986.2%
偏胖769588.0%

从这个表格可以很直观地看到误判主要发生在相邻类别之间,“正常”和“偏瘦”之间、以及“正常”和“偏胖”之间的混淆最严重,这是符合直觉的,等模型能力提升到一定程度后,再往上扣准确率就会非常吃力。这种分析性表述比单纯报一个数字有说服力得多。

5.2 典型翻车场景与排查指南

我把实际项目里比较高发的几类问题整理成了速查表:

现象可能原因排查与解决
训练准确率卡在60%左右不动类别严重不均衡、模型欠拟合检查各类别样本数,给loss加类别权重,增加模型容量
loss变成NaN学习率过大、数据里有NaN像素调低学习率,检查数据预处理管道,确认归一化正确
验证集指标高、测试集指标低按照片划分导致同个体泄漏、过拟合验证集改为按猫个体编号划分数据,降低正则强度,别用验证集反复调参
对长毛猫系统性误判训练集中长毛猫数量不足单独补充长毛猫样本,或做分层抽样确保毛发长度分布平衡
对“趴卧”照片全部输出正常训练集里趴卧姿势占比过高去掉趴卧姿势或单独建类,模型对姿势敏感的锅别让体型背

5.3 一个容易被低估的坑:长毛猫和拍摄角度

这个项目里最容易出问题的不是网络结构,而是长毛猫。一只毛量蓬松的猫,即使体重在正常范围,视觉上也很容易被判断成偏胖。应对方法有三个层次:第一层次是采集数据时保证长毛和短毛样本均衡,模型需要见过足够多的“长毛但体型正常”的例子,才能学会不把毛发量当胖;第二层次是在评估时按毛发长度分别统计准确率,如果长毛组明显低于短毛组,就说明模型还没学到该学的东西;第三层次是给网络加辅助输入,比如额外标注毛发长度,做成双分支网络,或者用传统图像处理估计毛发覆盖程度再作为额外特征拼进去。

拍摄角度的影响也一样。侧面照是最标准的判断角度,但很多数据集里混杂了大量正面照、斜上方俯拍照,这些角度下腰线信息天然缺失。如果这类非标准照片很多,模型就会被迫找其他特征来猜,结果往往不理想。我的建议是标注时给每张照片加一个“视角”标签,训练时先只用侧面照训练一个主模型,再用其他角度照片微调,或者在数据增强阶段固定只保留侧面主导的照片。

6. 从毕设到落地:后面还能怎么扩展

6.1 轻量化和边缘部署

如果想把项目从“能跑”变成“能演示”,一个很自然的扩展是模型轻量化。训练阶段可以用大一点的网络,但演示的时候可以换成MobileNetV3这类轻量网络,或者把训练好的模型导出成ONNX格式,再用量化手段把权重复制成8位整数。这样模型体积可以从几百MB缩到几十MB,在普通笔记本CPU上也能做到几十毫秒推理一张图。

导出ONNX在PyTorch里非常方便,一句话就行。真正需要注意的反而是输入预处理的一致性:训练时用的是Letterbox加归一化,导出推理时要保证输入的图片也走完全一样的流程,否则模型在部署时表现会和训练时有很大偏差。这点我在不少项目里见过人踩,说起来小事,排查起来很费时间。

6.2 从“分类”到“检测+识别”

体型识别本质上是在“猫已经出现在画面里”的前提下工作的。真实应用场景里,照片可能是一整面墙、一个房间,猫在里面只占据很小一块。这时候可以把框架升级成两阶段:先用目标检测模型把猫框出来,再把框出来的区域送入体型分类网络。检测可以用现成的轻量检测模型,训练成本可控,和体型分类串起来就成了一条能落地的推理链路。

这个扩展方向对毕设很友好,因为它不需要改分类模型的核心原理,只是加了一个上游模块。答辩时你可以讲清楚整个链路:检测负责定位,分类负责判断,两部分的误差会叠加,所以检测框质量对最终结果有直接影响。这种系统级思考很加分。

6.3 多模态融合:图像之外再给一点结构化信息

纯图像能获取的信息其实有限,很多体型判断需要知道猫的品种、年龄、是否绝育、体重历史记录。绝育后的猫更容易发胖,长毛猫视觉上自带“膨胀”效果,老年猫肌肉流失更多。如果手上能拿到这些结构化信息,把它们和图像特征拼在一起,再接一个简单的分类头,往往比只用图像精度更高,同时还让项目显得更有思考深度。

具体实现也不复杂:图像经过CNN得到特征向量,结构化信息经过一个几层的MLP编码成另一个向量,两个向量拼接后过全连接层输出三类概率。数据组织上只需要每只猫对应一条结构化的标签表。做这个方向的时候要特别注意,结构化信息不能泄露测试时拿不到的数据,比如未来体重变化、是否已经知道诊断结果之类的字段。

最后分享一点实操体会

这类毕设项目我最深的体会就是,前期数据工作偷懒,后期模型再怎么调都补不回来。见过不少同学上来先把模型搭好跑通,然后发现训练集里偏胖样本没几张、长毛猫全是同一个姿势,回头再补数据,工期全部浪费。宁可第一周把标注规范、类别平衡、按个体划分这三件事做扎实,后面训练就是顺水推舟。

还有一个小技巧,训练过程中把损失曲线截图、混淆矩阵和每个类别的错误示例都留存好。答辩时把这些东西整理出来,比背概念讲理论有用得多。最后再提醒一下,如果你的机器只有CPU,那就用轻量网络跑小尺寸输入,先把流程走通,再去想办法用预训练权重刷高指标,别一上来就开一个ResNet101的训练任务,等着你的是漫长的黑夜。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询