ARTICLE DETAIL

资讯详情

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

基于机器学习的猫狗识别源码实战:从环境配置到模型训练与推理

基于机器学习的猫狗识别源码实战:从环境配置到模型训练与推理 简介这份资源是面向计算机、人工智能、大数据、数学及电子信息等相关专业学生的机器学习实战项目源码适用于课程设计、期末大作业与毕业设计等场景也可作为技术学习者理解图像分类流程的参考案例。压缩包共12个文件约359KB以py脚本、jpg与png图片、md说明文档及gitignore配置为主其中Python代码承担猫狗识别算法的核心逻辑图片文件用于样本展示与训练结果可视化README则提供项目说明与运行指引。资源内代码经过严格调试下载后即可运行但需要具备一定机器学习基础才能读懂并进一步调试。内容涵盖数据预处理、模型构建、训练过程与预测结果展示等环节并附有模型处理、预测效果及损失曲线等可视化图片便于读者直观理解算法表现。目前已有329人学习适合希望快速获取完整可运行项目、对照源码梳理图像分类实现思路的学习者参考使用。1. 从一份猫狗识别源码包说起它到底能不能直接跑起来很多人第一次拿到「基于机器学习的猫狗识别算法源码.zip」这种资源心里其实是打鼓的里面到底是能跑的工程还是几段拼凑的 demo我拆过不少类似的课程设计包这个包的结构算是比较典型的——project_code_0628目录下放着6029907.py和cat_dog.py两个主脚本images文件夹里有pic1.jpg到pic4.jpg四张测试图根目录还有README.md、.gitignore以及result、model_prosess.png、predict.png、paddle.png、costlost.png这几张训练过程与预测结果的可视化图。从文件构成看它走的是「训练脚本 推理脚本 样例图 结果截图」的路线不是那种只有一个.ipynb的裸 notebook。这份资源适合谁如果你正在做机器学习、人工智能方向的课程设计、期末大作业或者需要一个能跑通、能改、能写进报告里的猫狗二分类 baseline它省掉了你自己搭目录、找样例图、调可视化那一步。但要注意摘要里写得很清楚——「需要具备一定基础才能看懂并调试代码」它不是一键 exe你得有 Python 环境、会看报错、知道什么是训练集和验证集。下面我按「先跑通、再拆解、最后避坑」的顺序把这份包的实际用法和边界讲清楚。2. 环境准备与首次运行把 zip 变成能出预测结果的工程2.1 依赖判断从 import 反推需要装什么拿到包先别急着pip install一堆东西。我的习惯是先把主脚本的 import 段扫一遍看它到底依赖哪些库。cat_dog.py和6029907.py这类命名通常一个是训练入口、一个是推理或数据处理入口。你打开后大概率会看到paddle、numpy、PIL、matplotlib这些。paddle.png这个文件名基本坐实了它用的是百度飞桨PaddlePaddle而不是 PyTorch 或 TensorFlow这点很关键——装错框架后面全白搭。常见做法是先建一个干净虚拟环境避免和你机器上已有的 torch、tensorflow 打架# 创建独立环境Python 版本建议 3.8~3.10飞桨对高版本支持有滞后 conda create -n catdog python3.9 -y conda activate catdog # 安装飞桨 CPU 版如果你没有配好 CUDA先用 CPU 版跑通流程 pip install paddlepaddle2.5.2 -i https://pypi.tuna.tsinghua.edu.cn/simple # 补齐常见依赖 pip install numpy pillow matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple这里参数说明一下paddlepaddle2.5.2是一个相对稳定、和多数课程设计代码兼容的版本如果你装最新版部分旧 API比如paddle.fluid可能已经移除会直接报AttributeError。-i后面跟的是国内镜像源能明显加快下载。CPU 版虽然训练慢但胜在不用折腾显卡驱动第一次跑通流程足够用。2.2 数据与路径images 文件夹和脚本里的路径要对上这个包里images目录只有pic1.jpg到pic4.jpg四张图说明它自带的不是完整训练集而是推理演示图。真正的训练数据要么在脚本里通过下载接口获取飞桨常见做法是调用paddle.vision.datasets里的猫狗数据集要么需要你自己准备。你运行前先确认脚本里读图的路径写法常见有两种# 写法一相对路径依赖你从哪个目录执行脚本 img_path ./images/pic1.jpg # 写法二拼接当前脚本所在目录更稳 import os BASE_DIR os.path.dirname(os.path.abspath(__file__)) img_path os.path.join(BASE_DIR, images, pic1.jpg)如果你在project_code_0628目录外执行python cat_dog.py写法一就会报FileNotFoundError。解决办法要么cd进目录再跑要么把脚本里的路径改成写法二。这是新手翻车最多的地方没有之一。2.3 首次运行先跑推理再碰训练我的建议是先跑推理脚本用自带的四张图验证环境和模型加载没问题再去跑训练。因为训练动辄几十分钟如果环境有问题你等半天才报错时间全浪费。推理脚本一般会加载一个预训练权重或已保存的模型然后对pic1.jpg到pic4.jpg逐张预测输出类别和置信度最后生成predict.png这样的结果图。# 进入代码目录 cd project_code_0628 # 先跑推理具体脚本名以你解压后为准可能是 cat_dog.py python cat_dog.py跑完看两样东西终端有没有打印出每张图的预测类别以及目录里有没有新生成或更新predict.png。如果predict.png里四张图都被正确标成 cat 或 dog说明模型和推理链路是通的。如果报ModuleNotFoundError回到 2.1 补装对应库如果报权重文件找不到检查脚本里加载模型的路径是不是指向了包内不存在的文件——这种情况你需要先跑训练脚本生成权重。3. 训练脚本拆解模型结构、损失曲线与 costlost.png 怎么读3.1 网络结构CNN 堆叠还是迁移学习打开训练脚本重点看模型定义部分。课程设计级别的猫狗识别常见两种写法一种是手写几层卷积 池化 全连接另一种是直接调用飞桨内置的预训练模型如 ResNet、MobileNet做迁移学习。从包里有paddle.png和model_prosess.png来看它很可能用了飞桨的高层 API 来搭网络并保存了模型结构图。如果是手写 CNN你会看到类似这样的结构import paddle.nn as nn class CatDogNet(nn.Layer): def __init__(self, num_classes2): super().__init__() # 输入 3 通道输出 32 通道卷积核 3x3 self.conv1 nn.Conv2D(3, 32, kernel_size3, padding1) self.pool nn.MaxPool2D(kernel_size2, stride2) self.conv2 nn.Conv2D(32, 64, kernel_size3, padding1) self.conv3 nn.Conv2D(64, 128, kernel_size3, padding1) self.fc nn.Linear(128 * 16 * 16, num_classes) # 假设输入图 128x128 def forward(self, x): x self.pool(nn.functional.relu(self.conv1(x))) x self.pool(nn.functional.relu(self.conv2(x))) x self.pool(nn.functional.relu(self.conv3(x))) x paddle.flatten(x, start_axis1) return self.fc(x)参数说明num_classes2对应猫和狗两类padding1保证卷积后尺寸不变方便你算全连接输入维度128 * 16 * 16这个数字取决于输入图像尺寸和池化次数如果你把输入改成 224x224这个数就得重算否则Linear会报维度不匹配。这是改代码时最容易忽略的连锁反应。3.2 训练循环与 costlost.png损失不降先查这三处costlost.png顾名思义是 cost/loss 曲线图。训练脚本里通常每个 epoch 记录一次 loss最后用 matplotlib 画出来。你跑完训练后打开这张图如果曲线一路震荡不下降或者直接是一条水平线按下面顺序排查第一学习率是不是太大。常见默认learning_rate0.001如果手写 CNN 且没做归一化0.001 都可能炸可以降到 0.0001 试。第二数据有没有做归一化。飞桨的Normalize或手动除以 255 都行但如果输入是 0~255 的原始像素网络很难收敛。第三标签有没有对错。猫狗二分类如果标签映射反了loss 会卡在 0.69 附近下不去二分类随机猜的交叉熵。# 训练循环骨架关注 loss 记录和保存 optimizer paddle.optimizer.Adam(learning_rate0.001, parametersmodel.parameters()) loss_fn nn.CrossEntropyLoss() for epoch in range(10): model.train() for batch_id, (data, label) in enumerate(train_loader): pred model(data) loss loss_fn(pred, label) loss.backward() optimizer.step() optimizer.clear_grad() print(fepoch {epoch}, loss {loss.numpy()}) # 这里通常会 append 到列表最后画 costlost.png逻辑说明optimizer.clear_grad()不能省否则梯度会累加loss 曲线会异常。loss.numpy()只是为了打印实际画图时要把每个 epoch 的平均 loss 存进列表。如果你发现costlost.png是空的或者只有一条直线先确认画图代码是不是在训练循环外、且列表里确实有数据。3.3 模型保存与复用result 目录和权重文件包里有个result条目可能是目录也可能是文件。训练脚本一般在最后会保存模型参数常见写法是paddle.save(model.state_dict(), result/model.pdparams)。你训练完要确认这个文件生成了否则推理脚本加载不到权重只能随机初始化预测结果就是瞎猜。如果result是个目录但里面空的说明训练没跑完或者保存路径写错了。这时候别急着重跑先看终端有没有Permission denied或路径不存在的报错。4. 推理与可视化predict.png 和 model_prosess.png 的生成逻辑4.1 单图推理从 pic1.jpg 到类别输出推理脚本的核心就三步加载模型结构、加载权重、对图片做同样的预处理。预处理必须和训练时一致训练用了Resize((128,128))和归一化推理也得一样否则精度会掉得莫名其妙。from PIL import Image import numpy as np def preprocess(img_path, size(128, 128)): img Image.open(img_path).convert(RGB) img img.resize(size) arr np.array(img).astype(float32) / 255.0 # 从 HWC 转 CHW再加 batch 维度 arr arr.transpose((2, 0, 1))[np.newaxis, ...] return paddle.to_tensor(arr) model.eval() logits model(preprocess(images/pic1.jpg)) pred_class paddle.argmax(logits, axis1).numpy()[0] print(cat if pred_class 0 else dog)参数说明convert(RGB)防止有些 jpg 是灰度或带 alpha 通道导致通道数不对/255.0是归一化transpose是因为飞桨卷积要求 CHW 格式。model.eval()会关闭 dropout 和 batch norm 的训练行为推理时必加否则同一张图每次预测结果可能不一样。4.2 批量预测与 predict.png四张图怎么排布predict.png通常是把pic1.jpg到pic4.jpg拼成一张大图每张下面标注预测类别和置信度。生成逻辑一般是 matplotlib 的 subplotimport matplotlib.pyplot as plt fig, axes plt.subplots(1, 4, figsize(16, 4)) for ax, name in zip(axes, [pic1.jpg, pic2.jpg, pic3.jpg, pic4.jpg]): img Image.open(fimages/{name}) ax.imshow(img) ax.set_title(predict(fimages/{name})) # 返回 cat 0.98 这类字符串 ax.axis(off) plt.savefig(predict.png)如果你跑完发现predict.png里标题全是乱码或方块那是 matplotlib 中文字体没配改成英文标签或者设置plt.rcParams[font.sans-serif]即可。这个不影响模型本身但影响你截图放进报告。4.3 model_prosess.png 与 paddle.png过程图的作用model_prosess.png一般是训练过程的准确率/loss 双曲线paddle.png可能是飞桨框架的 logo 或模型结构可视化。这两张图在课程设计报告里很有用——老师看的不只是最终精度还有你有没有真的跑过训练、有没有分析过程。如果你要写报告建议把costlost.png和model_prosess.png都放进去配上「第 3 个 epoch 后 loss 明显下降第 8 个 epoch 趋于平稳」这样的描述比只贴一个准确率数字有说服力。5. 避坑与常见问题跑不通时先查这几条5.1 报错 ModuleNotFoundError: No module named paddle现象一运行就提示找不到 paddle。原因没装飞桨或者装到了另一个 Python 环境里。解决确认conda activate catdog后pip list | grep paddle能看到paddlepaddle。如果用的是系统 Python 而不是虚拟环境很可能装串了。另外注意包名是paddlepaddle不是paddlepip install paddle装出来的是另一个东西。5.2 训练 loss 一直不降costlost.png 是条平线现象跑了十几个 epochloss 在 0.69 附近晃。原因标签映射反了、学习率过大、或者数据没归一化。解决先打印一个 batch 的 label 看是不是 0 和 1 都有再把学习率降到 0.0001最后检查预处理有没有除以 255。这三步能解决八成不收敛问题。5.3 推理结果每次都不一样现象同一张pic1.jpg跑两次一次 cat 一次 dog。原因忘了model.eval()dropout 还在起作用或者权重根本没加载成功每次都是随机初始化。解决推理前加model.eval()并打印一行确认权重加载的日志比如print(weight loaded)放在paddle.load之后。5.4 FileNotFoundError: images/pic1.jpg现象找不到图片。原因执行目录不对脚本用的是相对路径。解决cd到project_code_0628再执行或者把脚本里的路径改成基于__file__的绝对路径。这个坑在 Windows 和 Linux 之间切换时尤其常见因为路径分隔符不一样用os.path.join最稳。5.5 显存不足或训练中途卡死现象跑着跑着报Out of memory或者进度条不动。原因batch size 太大或者用了 GPU 但显存不够。解决把batch_size从 64 降到 16 或 8如果用的是 CPU 版检查是不是数据加载num_workers设太高导致卡死改成 0 试试。课程设计的图通常不大CPU 也能跑别硬上 GPU。6. 进阶技巧把这份源码改成你自己的课程设计6.1 换数据集从猫狗到其他二分类这份代码的骨架是二分类你完全可以把images换成自己的数据集比如「戴口罩/不戴口罩」「苹果/橘子」。关键改动有三处一是数据加载部分把读死四张图改成遍历文件夹二是num_classes保持 2 不变三是标签映射要和你文件夹结构对应。常见做法是按类别建两个子目录用paddle.io.Dataset自定义读取。import os from paddle.io import Dataset class MyDataset(Dataset): def __init__(self, root, transformNone): self.samples [] # 假设 root/class0 和 root/class1 两个目录 for label, cls in enumerate([class0, class1]): cls_dir os.path.join(root, cls) for name in os.listdir(cls_dir): self.samples.append((os.path.join(cls_dir, name), label)) self.transform transform def __getitem__(self, idx): path, label self.samples[idx] img Image.open(path).convert(RGB) if self.transform: img self.transform(img) return img, label def __len__(self): return len(self.samples)这样你就不用改模型结构只换数据源报告里还能写「在自建数据集上验证了模型泛化能力」。6.2 提升精度的三个低成本手段第一数据增强。飞桨的paddle.vision.transforms里有RandomHorizontalFlip、RandomRotation加进去能明显缓解过拟合尤其是你数据量小的时候。第二迁移学习。把手写 CNN 换成paddle.vision.models.resnet18(pretrainedTrue)只训练最后的全连接层精度通常比从零训高一大截。第三学习率衰减。用paddle.optimizer.lr.StepDecay每几个 epoch 降一次loss 曲线会更平滑。6.3 验证方法别只看训练准确率课程设计最容易犯的错是只报训练集准确率。你至少要把数据切成训练集和验证集每个 epoch 后在验证集上算一次准确率。如果训练准确率 99%、验证准确率 60%那就是过拟合报告里要分析原因数据少、模型复杂、没做增强。model_prosess.png如果画的是双曲线正好能体现这一点。我一般会强制自己没有验证集结果的模型不写进报告。6.4 一个具体技巧固定随机种子机器学习里有个玄学——同样的代码两次跑结果不一样。这通常是随机种子没固定。在脚本开头加上import paddle import numpy as np import random paddle.seed(42) np.random.seed(42) random.seed(42)这样数据打乱顺序、权重初始化都一致你调参时才能判断「精度变化」到底是改代码带来的还是随机波动。从那以后我每次跑课程设计代码第一件事就是固定种子不然调参调到最后自己都糊涂。希望这份拆解能帮你把这份猫狗识别源码真正跑起来、改起来而不是解压完就放在硬盘里吃灰。本文还有配套的精品资源点击获取
返回列表