尧图精选

从CNN图像分类到PyQt部署:猫行为识别实战全流程拆解

🕒 发布时间:2026/10/1 13:11:20 📁 来源:尧图网络
简介针对PyTorch环境下的猫行为识别任务这份压缩包提供了完整的CNN分类实践代码与图片数据集适合希望从数据准备、模型训练到界面部署全流程入门的深度学习者。资源共544个文件以jpg图片为主搭配3个Python脚本和3个txt说明文件压缩包大小41.35MB。其中数据集包含多类猫行为图片脚本利用短边补灰边、随机旋转等方式对图片进行预处理和扩增01脚本负责生成训练验证标签文本02脚本执行深度学习模型训练并保存本地模型03脚本提供PyQt可视化界面配合requirements.txt可快捷搭建环境。目前已有102人学习下载适合具基础Python与深度学习概念、想快速跑通CNN图像分类项目的同学参考。1. 猫行为识别资源拆解把CNN图片分类从数据到训练再到界面完整跑通把一只猫的图片丢进CNN模型让它判断当前是伸懒腰、磨爪子还是睡觉——听起来带点玄学但当你手上有一批按类别整理好的猫行为图片数据集时这件事就变成一个标准的PyTorch图片分类工程。这份资源正好就是干这个的它不只给了CNN训练代码还配了经过预处理和增强的猫行为图片数据集并且把训练完成的模型接进了一个PyQt界面。适合正在学PyTorch、想拿真实数据集完整跑一遍图像分类流程的人也适合课程设计或小竞赛需要快速出活的人。拆解它不需要GPU集群一张普通显卡甚至CPU都能把流程走完关键是把数据处理、模型训练、部署验证这三段关系理顺。2. 从requirement.txt到01数据集脚本先读懂灰边正方形和旋转扩增2.1 解压后别急着跑训练先把目录结构盘清楚我拆过不少图片分类资源最常看到有人下载后直接双击02训练脚本然后被ModuleNotFoundError打懵。这个项目里写得很清楚环境要自己配给了一个requirement.txt。所以第一步是解压、看文件、再虚拟环境安装。unzip 通过CNN卷积网络对猫行为识别-含图片数据集.zip -d cat_behavior cd cat_behavior ls -la正常情况下你能看到数据集文件夹、三个Python脚本01数据集文本制作、02模型训练、03PyQt界面、requirements.txt或requirement.txt。先别动代码把依赖装进一个独立环境更稳cat requirement.txt python -m venv venv source venv/bin/activate # Windows下是 venv\Scripts\activate pip install -r requirement.txt这里有几个关键点。虚拟环境不是可选项尤其是你已经装过其他PyTorch版本时直接装会把系统环境搅浑后面出现CUDA或版本冲突根本没有后悔药。requirement.txt只是列依赖不会帮你决定装CPU版还是GPU版PyTorch这一步得自己判断。如果机器有NVIDIA显卡先运行python -c import torch; print(torch.cuda.is_available())确认早就装好CUDA版环境再回来跑安装。2.2 01脚本在做什么把图片文件夹变成带标签的txt01数据集文本生成制作.py是整个流程的地基。它的输入是数据集文件夹输出是训练集txt和验证集txt每一行记录一条数据图片绝对路径加空格加标签编号。这个txt直接决定了后续训练时模型能看到哪些图。import os import random data_root 数据集 class_names sorted(os.listdir(data_root)) # 每个子文件夹名是一个类别 class_to_id {name: i for i, name in enumerate(class_names)} train_lines [] valid_lines [] for cls_name in class_names: cls_dir os.path.join(data_root, cls_name) images [f for f in os.listdir(cls_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(images) split_idx int(len(images) * 0.8) for img in images[:split_idx]: img_path os.path.join(cls_dir, img) train_lines.append(f{img_path} {class_to_id[cls_name]}\n) for img in images[split_idx:]: img_path os.path.join(cls_dir, img) valid_lines.append(f{img_path} {class_to_id[cls_name]}\n) with open(train.txt, w, encodingutf-8) as f: f.writelines(train_lines) with open(valid.txt, w, encodingutf-8) as f: f.writelines(valid_lines)上面这段是常见做法和资源里01脚本的目标一致每个子文件夹名就是类别标签按类名排序后生成。要注意排序用sorted()固定顺序否则下次运行类别编号变了加载旧模型时预测结果会错位。txt里写绝对路径还是相对路径也有讲究我一般写绝对路径因为训练时工作目录可能和生成txt时不一样相对路径很容易FileNotFoundError。2.3 短边加灰边变成正方形这个预处理藏着精度差异资源里明确提出数据预处理包括“在较短边增加灰边使得图片变为正方形”这句话很值得细看。很多入门项目图省事直接resize((224, 224))把图片拉伸结果猫被压成扁的或者瘦的CNN学到的形状特征被扭曲训练出来的模型在小图测试时惨不忍睹。而短边补灰边的方式是先按长边缩放到目标尺寸保持宽高比不变再把短边两侧用灰色填充成正方形。from PIL import Image def pad_to_square(img, target_size224, gray_value114): w, h img.size scale target_size / max(w, h) new_w, new_h int(w * scale), int(h * scale) img img.resize((new_w, new_h), Image.BILINEAR) canvas Image.new(RGB, (target_size, target_size), (gray_value, gray_value, gray_value)) x (target_size - new_w) // 2 y (target_size - new_h) // 2 canvas.paste(img, (x, y)) return canvas这段逻辑对应的是“如果图片原本就是正方形则不会增加灰边”。用max(w, h)作缩放基准正方形图缩放后两边都等于target_sizex和y都是0等于没加边。灰边值我习惯用114或128不要用0因为纯黑边会在边界处产生强烈的对比度响应卷积滤波器很容易把注意力吸到边框上。这个函数在后面对接PyQt界面时也要复用它保证训练和预测时看到的是同一种预处理。2.4 旋转翻转扩增文件名里的rotated45和flip是什么解压后你能看到一批egm_rotated45.jpg、ypd_flip.jpg这类文件名这就是增强后的新样本。资源用旋转和翻转来扩增数据集对小数据集来说这是必不可少的操作。猫行为识别和工业缺陷检测不一样缺陷随便转90度仍然算缺陷但猫的行为类别对姿态有一定要求所以我更倾向有限度的增强。from PIL import Image img Image.open(egm.jpg) width, height img.size # 水平翻转 flip_img img.transpose(Image.FLIP_LEFT_RIGHT) flip_img.save(egm_flip.jpg) # 旋转45度expand保证内容不被裁切fill填充灰色背景 rot_img img.rotate(45, expandTrue, fill(114, 114, 114)) rot_img.save(egm_rotated45.jpg)关键点在expandTrue和fill参数。不展开旋转后四个角会被裁掉等于改变图片内容不填灰PIL默认填黑边又回到上一节说的黑边副作用。旋转后的图尺寸变大了所以增强流程里要么先旋转再走灰边正方形要么让旋转后的图再进一遍pad_to_square。01脚本读取数据集文件夹时会把原始图和增强图都写进txt这样训练时这批增强样本才会真正进入DataLoader。2.5 生成txt后必须做的三分钟检查这一步很多人跳过结果训练跑一半发现loss异常。我会把train.txt前几行打印出来随机挑一个图片路径用PIL打开看一眼再确认标签整数和文件夹名是否对应。head -5 train.txt python -c from PIL import Image; imImage.open(数据集/xxx/yyy.jpg); print(im.size, im.mode)如果路径中包含中文或空格注意在训练脚本的Dataset里处理编码问题时建议统一用utf-8读取txt图片路径中的分隔符用os.sep拼接避免Windows和Linux路径翻车。这一步检查做完再往下跑02训练脚本才有意义。3. PyTorch训练脚本拆解CNN结构、超参数、模型落盘三件事3.1 训练脚本的主流程就是标准四步02深度学习模型训练.py做的事情可以归纳成四步读取txt、构造Dataset、定义CNN模型、循环训练保存模型。理解这四步你就不会把03界面脚本误当成训练入口。import torch from torch.utils.data import DataLoader from torchvision import datasets, transforms # 第一步构造Dataset # 实际代码通常从train.txt读路径这里用ImageFolder方式为例 train_dataset datasets.ImageFolder(root数据集, transformtransforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ])) val_dataset datasets.ImageFolder(root数据集, transformtransforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ]))注意我这里是示意。因为资源里要自己从txt读所以Dataset是自定义类迭代时返回(图片tensor, 标签)。有一点容易混淆ImageFolder需要目录结构是“根目录/类别/图片.jpg”它内部自己生成标签而资源里用txt显式指定路径和标签两者不冲突目的都一样。3.2 CNN网络结构从小模型起步理解卷积、池化、全连接图像分类的CNN基础结构就是“卷积池化重复几次最后接全连接”。资源没有明说用的是哪几个卷积层但这种猫行为识别任务图片数量不大网络不必很深VGG16或ResNet50在这个小数据上容易过拟合。我一般按下面的思路去理解资源里可能的CNN结构import torch.nn as nn class CatBehaviorNet(nn.Module): def __init__(self, num_classes5): super().__init__() self.features nn.Sequential( nn.Conv2d(3, 16, kernel_size3, padding1), nn.BatchNorm2d(16), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), nn.Conv2d(16, 32, kernel_size3, padding1), nn.BatchNorm2d(32), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), nn.Conv2d(32, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2), ) self.classifier nn.Linear(64 * 28 * 28, num_classes) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) return self.classifier(x)这个例子输入是3×224×224。经过三次步长为2的池化特征图尺寸变成28×28通道数64全连接层输入维度就是64×28×28。如果数据集里猫行为类别数不是5把这个num_classes改成你的实际类别数即可。用BatchNorm是为了让小批量数据训练更稳定猫图片色彩差异大白猫、橘猫、黑猫的像素分布完全不同不做归一化会导致梯度震荡。3.3 训练集验证集加载与超参数怎么调02脚本里训练集和验证集分别从两个txt读取。它们的DataLoader配置略有不同训练集需要shuffle打乱验证集不需要。train_loader DataLoader(train_dataset, batch_size16, shuffleTrue, num_workers2) valid_loader DataLoader(val_dataset, batch_size16, shuffleFalse, num_workers2) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr0.001)batch_size和lr是这里最常改的两个超参数。我实际跑这类小数据资源时会用下面这张判断表快速定位问题参数常见取值选择依据batch_size16或32显存不够就调小继续报错就调成8learning rate0.001或0.0005用Adam时0.001是安全起点loss发散就降一个数量级epochs30~50小数据30轮足够再久就容易过拟合num_workers0~4Windows下建议设0可避免多进程报错有一类典型翻车是验证集loss降不下去训练loss却很低。这时先把batch_size调小把学习率降到1e-4如果还不行就去检查验证集里是不是包含了增强图可能泄漏了训练分布。另一个常见错误是验证集也做了随机旋转增强这会让验证指标失真验证集预处理应该固定只用resize和标准化。3.4 模型保存只存state_dict还是存整个模型资源里说训练好后会保存模型在本地具体方式通常是保存state_dict也就是网络参数的字典。这个选择和后续PyQt界面加载直接相关保存方式不同加载代码也不一样。best_acc 0.0 for epoch in range(epochs): # train loop ... acc validate(model, valid_loader) if acc best_acc: best_acc acc torch.save(model.state_dict(), best_model.pth) print(fEpoch {epoch}: save best model, acc{acc:.4f})用state_dict的好处是体积小、跨PyTorch小版本兼容性更好。加载时需要先实例化同样结构的模型再调用load_state_dictmodel CatBehaviorNet(num_classes5) model.load_state_dict(torch.load(best_model.pth, map_locationcpu)) model.eval()map_locationcpu这个参数很重要尤其当你用GPU训练、想在只有CPU的机器上跑PyQt界面时少了它会报权重张量在cuda设备上的错。训练脚本里如果只想保存最后一个epoch可以不加判断条件但保存best模型是更稳妥的做法因为CNN训练在第20轮可能就已经是最优最后一轮反而过拟合了。4. 复现避坑猫行为识别资源下载后最容易翻车的5个地方跑这个资源之前先给你提个醒它不是一个“双击就出结果”的黑匣子环境、路径、预处理一致性三个环节每个都有坑。下面按我实际拆过的经验列几条。4.1 现象pip安装后训练脚本一直跑在CPU上loss下降很慢原因pip install -r requirement.txt默认装到PyPI里的PyTorch在Windows上大概率是CPU版即使你有NVIDIA显卡torch.cuda.is_available()也返回False模型根本没在GPU上训练一张224×224的图迭代一次要几百毫秒几十轮下来人直接崩溃。解决先跑python -c import torch;print(torch.cuda.is_available())返回False就说明torch没装对。去PyTorch官方网站用对应CUDA版本的安装命令重新装比如pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这种形式。装完再回到项目目录执行01和02脚本不要反过来先把整个环境删了重来。4.2 现象01脚本生成txt正常但02训练时报FileNotFoundError: No such file or directory: 数据集/xxx.jpg原因txt里存的是相对路径而02脚本运行时工作目录变了比如你在IDE里把工作目录设到了scripts子目录路径就失效了。还有一种可能是图片文件名里有空格或中文读取时被拆错了。解决统一用绝对路径。在01脚本里生成txt时把img_path改成os.path.abspath(img_path)写进去。如果文件名有空格最好在写txt时用\t分隔路径和标签读取时用rsplit(\t, 1)而不是split( )。另外在02脚本Dataset的__init__里加一行assert os.path.exists(path), path这样train能立刻定位坏路径而不是等DataLoader迭代到一半才抛错。4.3 现象旋转45度增强后训练acc反而不如只翻转的版本原因猫行为识别里“磨爪子”和“伸懒腰”这两个类别很大程度依赖猫的身体朝向和四肢位置。45度旋转可能把“坐着”的样本变成接近“侧躺”的视角导致类别边界变得模糊模型学到的特征被噪声干扰测试集上泛化变差。解决增强策略要和任务语义匹配。像工业质检、物体识别可以大力旋转但猫行为分类建议只保留FLIP_LEFT_RIGHT和较小的旋转角度比如±10度。如果一定要保留45度增强就把旋转后的样本单独挑出来肉眼检查确认人眼都能分清类别再放进去。资源里提供了rotated45说明作者做过尝试但如果你发现自己数据集上效果变差不必照单全收直接修改01脚本里的增强角度列表就行。4.4 现象PyQt界面能打开但预测每个图片都是同一个类别原因界面脚本里的预处理和训练时不一致。训练时走了“短边加灰边变成正方形”界面里如果直接resize((224, 224))或者没有把图像从0~255归一化到0~1模型看到的输入分布就和训练完全不同输出全偏向某一类。另一个原因是从txt读到的类别顺序变了训练时类别0对应“A”界面加载时文件夹排序不同类别0变成“B”。解决把2.3里的pad_to_square函数复制到03脚本保证界面复用同一套预处理。预测前固定类别列表不要用os.listdir的动态顺序而是把class_names sorted(os.listdir(data_root))打印出来硬编码到界面里或者保存一份classes.txt。最后做个冒烟测试训练集里挑一张图分别用训练脚本里的预处理和界面脚本里的预处理转成tensor比较结果是否一致。4.5 现象两个类别的训练loss一直不降准确率停在50%左右原因txt里标签错位或者数据集文件里两个类别文件夹的图片内容高度相似。比如“伸懒腰”和“拉伸”本身就比较接近再加上旋转增强的方向不对模型根本学不出区分特征。解决先打印数据集图片肉眼确认图片是否放错了文件夹。再把txt的前几行人工对一遍“路径标签”是否和文件夹名匹配。如果图片没问题但类别确实相似那就把这两个类别合并成一个或者去抓一些关键差异图补充训练。还有一个巧办法用torchvision.models.resnet18预训练权重做迁移学习只改最后一层全连接输出数目往往比从小网络训起更快突破这个准确率瓶颈。5. 把模型接进PyQt界面验证训练结果的两个实用技巧03脚本把训练好的模型接到PyQt里最容易踩的坑就是加载模型后预测结果和训练时不一致。这里分享一个我一直在用的固定验证技巧写一个独立的预测脚本只做“读图-预处理-推理”三步不碰任何界面逻辑。import torch from PIL import Image import torchvision.transforms as transforms def load_model(model_path, num_classes): model CatBehaviorNet(num_classesnum_classes) model.load_state_dict(torch.load(model_path, map_locationcpu)) model.eval() return model def predict_one_image(model, image_path): img Image.open(image_path).convert(RGB) # 复用训练时的灰边正方形预处理 from pad_function import pad_to_square img pad_to_square(img, target_size224, gray_value114) tensor transforms.ToTensor()(img).unsqueeze(0) with torch.no_grad(): logits model(tensor) pred torch.argmax(logits, dim1).item() return pred这个脚本有三个好处第一它能靠着pad_to_square确认预处理一致性第二它把推理和界面解耦界面报错时先怀疑界面本身而不是怀疑模型第三它可以配合混淆矩阵做整体验证。所谓混淆矩阵就是把验证集所有图片预测一遍统计真实类别和预测类别的交叉情况import numpy as np from sklearn.metrics import confusion_matrix y_true, y_pred [], [] for path, label in valid_samples: pred predict_one_image(model, path) y_true.append(label) y_pred.append(pred) cm confusion_matrix(y_true, y_pred) print(cm)这个矩阵能直接看出哪两个类别互相混淆比如“75”出现在第0行第1列说明类别0有75张被错误预测成类别1。资源里的猫行为类别如果少于五个矩阵对角线越集中越好。至于界面本身我的习惯是让PyQt的“打开图片”按钮直接调用predict_one_image界面只负责展示结果不要在里面重写图像缩放逻辑。等预测脚本跑通后再接线界面按钮和显示标签最后加一个阈值判断功能当最大softmax概率小于0.6时界面提示“无法确认类别”这样会比硬给一个结果实用得多。这套流程走完你再回头看资源里的03脚本会发现它的结构基本就是“加载模型、读文件、显示结果”三块。从那以后我每次拿到带PyQt界面的识别项目都强制自己先写一个3行的预测脚本单独验证模型再碰界面代码省下的调试时间够好好看一下数据集里那几张rotated45图片到底拍得清不清楚。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →