简介:这份资源是理工大学本科毕业设计项目——基于深度学习的行人重识别系统Python源码,面向计算机相关专业正在准备毕业设计的学生,以及需要项目实战练习的学习者。项目经导师指导并通过评审,获得98分,源码均经过本地编译与严格调试,可正常运行,难度适中,适合作为毕设参考或深度学习入门实践。压缩包为zip格式,共12个文件,包含11个py源码文件与1个md说明文档,整体约18KB,体量轻便。源码围绕行人重识别任务展开,涵盖数据加载与预处理、ResNet骨干网络、损失函数、优化器、距离度量、训练主流程及评估指标等模块,结构清晰,便于理解深度学习项目的完整组织方式。目前已有120人学习下载,读者可借此掌握从数据管理到模型训练与性能评估的实现思路,并在此基础上进行二次开发或功能扩展。
1. 行人重识别系统到底在做什么:从一张抓拍图到跨镜追踪
行人重识别(Person Re-Identification,简称 ReID)要解决的问题很具体:给你一张某个摄像头拍到的行人照片,让你在另一个摄像头的画面里把同一个人找出来。听起来像人脸识别,但区别很大——ReID 不依赖人脸,靠的是整个人体的外观特征,包括衣着颜色、体型轮廓、背包、发型这些线索。这意味着即使目标背对镜头、戴着口罩,系统依然有办法匹配。
这套理工大学本科毕业设计资源,核心就是一套基于深度学习的行人重识别系统 Python 源码。它适合正在做计算机毕业设计、需要一套能跑通、能改、能写进论文的完整工程的同学,也适合想入门深度学习落地项目的开发者。你拿到的不是一段孤立的算法脚本,而是一个包含数据加载、模型定义、训练流程、特征提取和检索评估的完整链路。下面我按实际拆包和复现的顺序,把这份源码讲透。
2. 源码结构与技术栈拆解:先搞清楚每个文件在干什么
2.1 典型目录布局与模块职责
拿到一个深度学习毕业设计源码包,最忌讳上来就python train.py。先花十分钟把目录结构看清楚,能省掉后面几个小时的血泪排查。行人重识别项目的目录结构通常长这样:
ReID_Project/ ├── config.py # 全局配置:数据集路径、超参数、模型选择 ├── train.py # 训练入口 ├── test.py # 测试/评估入口 ├── demo.py # 单张图片推理演示 ├── datasets/ # 数据集加载与预处理 │ ├── __init__.py │ └── market1501.py # Market1501 数据集读取 ├── models/ # 网络结构定义 │ ├── __init__.py │ ├── resnet.py # 骨干网络 │ └── reid_model.py # ReID 头部(特征嵌入层) ├── utils/ # 工具函数 │ ├── metrics.py # mAP、CMC 评估指标 │ └── transform.py # 图像增强 ├── checkpoints/ # 模型权重保存目录 └── data/ # 数据集存放目录这个布局是学术界 ReID 项目的常见做法,模块划分清晰。config.py是整个项目的控制中心,改数据集路径、换骨干网络、调学习率都在这里。models/下面通常会把骨干网络(如 ResNet50)和 ReID 特有的头部结构分开写,因为 ReID 需要在分类网络的基础上做特征嵌入,不是简单拿 ImageNet 预训练模型就能用的。
2.2 技术栈与依赖版本
这套源码的技术栈以 PyTorch 为主,配合 torchvision 做图像预处理。常见依赖清单如下:
| 依赖包 | 推荐版本 | 作用 |
|---|---|---|
| Python | 3.8 ~ 3.10 | 运行环境 |
| PyTorch | 1.10 ~ 2.0 | 深度学习框架 |
| torchvision | 对应版本 | 预训练模型与图像变换 |
| numpy | 1.21+ | 数值计算 |
| Pillow | 8.0+ | 图像读取 |
| scikit-learn | 1.0+ | 距离计算与评估辅助 |
| matplotlib | 3.4+ | 可视化(可选) |
| tqdm | 4.60+ | 训练进度条 |
安装时最容易翻车的是 PyTorch 版本和 CUDA 的匹配。如果你有 NVIDIA 显卡,先去 PyTorch 官网查对应 CUDA 版本的安装命令,不要直接pip install torch,那样装的是 CPU 版本,训练会慢到让你怀疑人生。没有显卡也能跑,但建议把 batch size 调小,训练轮数减少,先验证流程通不通。
# 有 CUDA 11.3 的环境(示例,按自己 CUDA 版本调整) pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html # 其余依赖 pip install numpy pillow scikit-learn matplotlib tqdm这段命令的逻辑是:先装 PyTorch 和 torchvision 的 GPU 版本,再补其余工具库。参数上,cu113表示 CUDA 11.3 编译版本,你要根据自己的驱动版本替换。装完后用torch.cuda.is_available()验证,返回True才算 GPU 环境配好了。
2.3 数据集准备:Market1501 的目录规范
行人重识别最常用的公开数据集是 Market1501,这套源码大概率也是基于它设计的。数据集下载后不能直接丢进data/就完事,目录结构必须符合代码里的读取逻辑:
data/Market1501/ ├── bounding_box_train/ # 训练集,751 个 ID ├── bounding_box_test/ # 测试集,750 个 ID ├── query/ # 查询集,3368 张 └── gt_bbox/ # 检测框(评估时用)文件名有固定格式:0002_c1s1_000451_03.jpg,其中0002是行人 ID,c1s1是摄像头编号,000451是帧号,03是检测框序号。代码在读取时会解析文件名来构建 ID 标签和摄像头标签,所以千万别重命名文件。如果你用自己的数据,要么按这个格式改名,要么改datasets/里的解析逻辑。
提示:Market1501 数据集需要自行下载,源码包里通常不含数据。下载后先检查文件数量,训练集应该是 12936 张,测试集 19732 张,query 集 3368 张,数量对不上说明解压不完整。
3. 训练流程跑通:从配置文件到模型收敛
3.1 配置文件关键参数逐项说明
config.py是训练前必须过一遍的文件。以下是典型 ReID 项目的关键参数:
# config.py 关键参数示例 class Config: # 数据集 DATASET_NAME = 'market1501' DATA_ROOT = './data/Market1501' # 模型 BACKBONE = 'resnet50' # 骨干网络选择 PRETRAINED = True # 是否加载 ImageNet 预训练权重 LAST_STRIDE = 1 # 最后下采样步长,ReID 常用 1 保留空间分辨率 FEAT_DIM = 2048 # 特征向量维度 NUM_CLASSES = 751 # 训练集行人 ID 数量 # 训练 BATCH_SIZE = 64 # 每批样本数 NUM_EPOCHS = 60 # 训练轮数 LR = 3.5e-4 # 初始学习率 WEIGHT_DECAY = 5e-4 # 权重衰减 MARGIN = 0.3 # Triplet Loss 的 margin # 采样策略 NUM_INSTANCES = 4 # 每个 ID 采样几张图LAST_STRIDE这个参数值得单独说。ResNet50 原始设计最后阶段 stride 为 2,特征图会被下采样 32 倍。ReID 任务需要更细粒度的空间信息,所以常见做法是把最后 stride 改成 1,特征图只下采样 16 倍,代价是计算量增加但精度提升明显。NUM_INSTANCES配合BATCH_SIZE决定采样策略:batch 64、每 ID 采 4 张,意味着每批覆盖 16 个不同行人,这是 triplet loss 能有效工作的前提——每个 batch 里必须有同一个人的多张图,否则三元组根本组不起来。
3.2 训练命令与日志解读
配置改好后,训练入口通常是这样:
python train.py --config config.py --gpu 0训练开始后,终端会输出每轮的 loss 和评估指标。你需要关注三个数:
- ID Loss:分类损失,衡量模型能否正确分类行人 ID,正常应该从 5 左右降到 0.1 以下
- Triplet Loss:度量学习损失,让同一人的特征靠近、不同人的远离,正常降到 0.2~0.5 区间
- mAP / Rank-1:评估指标,Market1501 上好的模型 mAP 能到 80% 以上,Rank-1 到 94% 左右
如果训练几轮后 loss 不降,先检查学习率是不是太大,或者数据加载有没有问题。如果 mAP 一直很低但 loss 在降,可能是评估代码的匹配逻辑有 bug,比如特征没有做归一化。
# utils/metrics.py 中特征归一化的关键逻辑 import torch.nn.functional as F def extract_features(model, dataloader): model.eval() features = [] with torch.no_grad(): for imgs, _ in dataloader: imgs = imgs.cuda() feat = model(imgs) # 关键:L2 归一化,否则欧氏距离和余弦距离不等价 feat = F.normalize(feat, p=2, dim=1) features.append(feat.cpu()) return torch.cat(features, dim=0)这段代码的核心是F.normalize。ReID 检索时用余弦距离或欧氏距离衡量特征相似度,如果特征向量没有归一化,向量模长会干扰距离计算,导致检索结果不稳定。这是很多新手自己改代码时容易漏掉的一步,也是 mAP 异常偏低的常见原因。
3.3 评估与指标含义
训练完成后跑评估:
python test.py --config config.py --checkpoint checkpoints/best.pth评估输出通常包含 mAP 和 CMC 曲线。mAP 是平均精度均值,综合考虑了检索结果中所有正确匹配的排序位置;Rank-1 是首位命中率,即检索结果第一张就是正确目标的概率。毕业设计论文里这两个指标都要报告,Rank-1 直观,mAP 更全面。如果导师要求对比实验,你可以改BACKBONE为resnet34或换采样策略,跑几组对比数据。
4. 避坑与常见问题排查:那些让你卡半天的坑
4.1 显存不够导致训练中断
现象:训练开始几秒后报RuntimeError: CUDA out of memory。
原因:BATCH_SIZE设太大,或者LAST_STRIDE=1导致特征图变大、显存占用增加。
解决:先把 batch size 降到 32 或 16,观察能否跑通。如果还不行,检查是不是同时开了多个 Python 进程占着显存,用nvidia-smi看一下。另外可以在 config 里加梯度累积,用小 batch 模拟大 batch 的效果。
4.2 数据加载报 FileNotFoundError
现象:FileNotFoundError: [Errno 2] No such file or directory: './data/Market1501/bounding_box_train/...'
原因:数据集路径不对,或者解压后多了一层目录。比如解压出来是Market1501/Market1501/bounding_box_train,而代码找的是Market1501/bounding_box_train。
解决:用ls data/Market1501/确认目录层级,多一层就移出来。路径最好用绝对路径,避免相对路径在不同工作目录下解析不一致。
4.3 训练 loss 正常但 mAP 极低
现象:loss 降到很低,但评估 mAP 只有 10% 左右。
原因:最常见的是评估时 query 和 gallery 的特征没有做归一化,或者摄像头 ID 过滤逻辑写反了。Market1501 评估时要排除同一摄像头下的匹配,如果这个过滤没做,指标会虚高或虚低。
解决:检查metrics.py里的距离计算和排序逻辑,确认特征做了 L2 归一化,确认同摄像头样本被正确排除。可以先用少量数据手动验证几张图的检索结果,看返回的是不是同一个人。
4.4 预训练权重加载失败
现象:RuntimeError: Error(s) in loading state_dict for ResNet。
原因:PyTorch 版本差异导致 state_dict 的 key 名称不一致,或者下载的预训练权重不完整。
解决:用model.load_state_dict(state_dict, strict=False)跳过不匹配的层,或者打印 key 对比差异。如果是下载中断导致的权重损坏,删掉重新下载。
4.5 训练速度异常慢
现象:一个 epoch 要跑几十分钟甚至更久。
原因:用了 CPU 训练,或者num_workers设为 0 导致数据加载成为瓶颈。
解决:确认torch.cuda.is_available()为 True,DataLoader 的num_workers设为 4 或 8(Windows 下有时要设 0 避免多进程问题),pin_memory=True加速数据传输。
5. 进阶技巧:用 demo 脚本做单图检索与特征可视化
5.1 单张图片推理:从 query 到检索结果
训练好的模型最终要能实际用起来。demo.py通常提供单图检索功能,逻辑是:输入一张行人图,提取特征,和 gallery 库中所有特征算距离,返回最相似的几张图。
# demo.py 核心检索逻辑 import torch import torch.nn.functional as F from PIL import Image from utils.transform import test_transform def search(query_path, gallery_feats, gallery_paths, model, topk=5): model.eval() # 读取并预处理查询图 img = Image.open(query_path).convert('RGB') img_tensor = test_transform(img).unsqueeze(0).cuda() # 提取特征并归一化 with torch.no_grad(): query_feat = model(img_tensor) query_feat = F.normalize(query_feat, p=2, dim=1) # 余弦距离 = 1 - 余弦相似度 similarity = torch.mm(query_feat, gallery_feats.t()) distances = 1 - similarity.squeeze(0) # 排序返回 topk indices = distances.argsort()[:topk] results = [(gallery_paths[i], distances[i].item()) for i in indices] return results这段代码的关键在于torch.mm做矩阵乘法计算相似度。gallery_feats是预先提取好的 gallery 特征矩阵,形状为(N, 2048),query_feat形状为(1, 2048),相乘后得到(1, N)的相似度向量。距离越小表示越相似。实际使用时,gallery 特征只需提取一次存下来,后续每次查询直接算距离,不用重复过模型。
5.2 特征可视化与 t-SNE 降维
毕业设计论文里如果能放一张特征分布可视化图,说服力会强很多。用 t-SNE 把 2048 维特征降到 2 维,不同行人的点用不同颜色标注,好的模型应该呈现明显的聚类效果。
from sklearn.manifold import TSNE import matplotlib.pyplot as plt # feats: (N, 2048) 特征矩阵, labels: (N,) ID 标签 tsne = TSNE(n_components=2, perplexity=30, random_state=42) feats_2d = tsne.fit_transform(feats.numpy()) plt.figure(figsize=(10, 8)) for i in range(10): # 取前 10 个 ID 可视化 mask = labels == i plt.scatter(feats_2d[mask, 0], feats_2d[mask, 1], label=f'ID {i}', s=10) plt.legend() plt.title('t-SNE Visualization of ReID Features') plt.savefig('tsne_result.png', dpi=150)perplexity参数控制降维时考虑的近邻数量,一般设 5~50,数据量大就调大。如果可视化出来所有点混在一起,说明模型没学好,回去检查训练流程。如果同类点聚成一团、不同类分开,说明特征判别力不错,这张图可以直接放进论文。
5.3 模型导出与推理加速
如果答辩时需要现场演示,建议把模型导出为 ONNX 格式,推理速度会快一些,也方便部署到没有 PyTorch 环境的机器上。
# 导出 ONNX 模型 dummy_input = torch.randn(1, 3, 256, 128).cuda() torch.onnx.export( model, dummy_input, "reid_model.onnx", input_names=['input'], output_names=['feature'], dynamic_axes={'input': {0: 'batch'}, 'feature': {0: 'batch'}}, opset_version=11 )导出时注意输入尺寸要和训练时一致,ReID 常用256x128(高 x 宽)。dynamic_axes让 batch 维度可变,方便批量推理。导出后用onnxruntime加载验证一下输出是否和 PyTorch 一致,差异在 1e-4 以内算正常。
从那以后我每次拿到新的 ReID 源码,都强制先跑一遍单图 demo 确认推理链路通,再开始训练。因为训练能跑不代表推理没问题,评估指标高也不代表实际检索结果合理。这套毕业设计源码的价值在于链路完整,你可以在它基础上换数据集、换骨干网络、加注意力模块,把论文的实验部分撑起来。希望帮到你。
本文还有配套的精品资源,点击获取