简介:面向计算机视觉方向的课程设计与毕业设计场景,这份资源围绕基于深度学习的场景语义分割任务,整合了模型训练与测试脚本、数据加载与预处理工具、项目配置文件及说明文档。内容覆盖从数据整理、数据增强,到模型迭代、损失函数与优化器设置,再到IoU等指标评估和结果可视化的关键步骤,适合需要快速搭建完整分割实验流程或研究工程实现细节的本科生、研究生。压缩包共24个文件,主体为10个Python脚本,承担训练、推理、数据读取等核心功能;辅以6个XML配置、2个TXT说明、2张PNG结果预览图,以及gitignore、iml等IDE辅助文件,整体约820KB,结构清晰,便于按目录快速定位。目前已有158人学习/下载。虽然体积不大,但围绕语义分割给出了可运行的模型定义、训练流程、数据处理与展示环节,附带的说明和预览图也降低了上手门槛,可作为毕业设计或课程作业的起点模板,也能为理解分割网络和调参提供直接参考。
1. 它是3D点云语义分割,不是2D像素涂色
打开这个zip之前,我以为它又是一个对着街景图片做像素分类的2D分割Demo——那种把汽车和行人涂上不同颜色的入门作业。真正扫了一遍文件列表才发现完全不是这么回事:train_SUPnet.py、train_FG_F1F2.py、train_PW-ATM.py三个训练脚本,配一套data_utils,跑的是斯坦福S3DIS室内点云数据,属于深度学习场景语义分割里偏3D的那条线。它解决的是“给一整栋楼的数百万个三维点,判断每个点属于天花板、地板、墙面还是桌椅”的问题,对毕设和课程作业来说信息量很大:网络结构、数据预处理、训练评估、可视化全部闭环,桌面级显卡就能复现。适合正在开题、需要快速跑通一个完整深度学习项目的学生,也适合想拿室内点云分割练手的工程师。
2. 解开压缩包后的第一件事:按文件角色分组读代码
2.1 文件清单里藏着项目骨架
把压缩包里的文件按用途过一次,项目结构就基本清晰了。我列了一张表,按“入口、数据处理、模型工具、辅助信息”四类归档:
| 文件/目录 | 角色定位 |
|---|---|
| train_SUPnet.py / test_SUPnet.py | 主训练与测试入口 |
| train_FG_F1F2.py | 第二套训练目标,FG相关特征监督 |
| train_PW-ATM.py | 第三套训练入口,PW-ATM分支 |
| data_utils/collect_indoor3d_data.py | 从S3DIS原始数据提取点云块 |
| data_utils/indoor3d_util.py | npy样本生成、坐标与标签对齐 |
| data_utils/S3DISDataLoader.py | 定义Dataset类与采样策略 |
| data_utils/meta/DataLoader.py | 元数据读取辅助 |
| models/pointnet2_utils.py | PointNet++核心算子层 |
| provider.py | 数据增强(旋转、抖动等) |
| README.md / 结果.png | 说明文档与训练效果示例 |
这个分布是典型的“课程作业级但结构完整”的写法:入口清晰,数据脚本独立成目录,模型层集中在models文件夹。你不需要改动底层算子就能换数据集跑,这点对复现很友好。拿到包后不要急着启动训练,先按上面这张表把每个文件首尾读一遍,标注出哪几个是入口、哪几个是被import的模块,后面改代码时才知道动哪里。
2.2 SUPnet、FG_F1F2、PW-ATM三条线是什么关系
从命名看,这三套训练脚本对应同一种骨干网络的不同训练目标。SUPnet是主模型名,train_FG_F1F2里的F1、F2更像是两个特征分支——FG往往指前景分组或特征分组,PW-ATM是逐点注意力机制之类的模块。这类项目最常见的设计是:一个PointNet++风格的特征提取骨干,加上若干辅助监督分支,主分支输出逐点分类,辅助分支帮助网络更快收敛。
我一般会这样理解:train_SUPnet.py负责主线训练,训练完生成模型权重;train_FG_F1F2.py用FG约束让特征图在类别边界处更干净;train_PW-ATM.py则强化逐点注意力权重,适合最终精度调优。三个脚本共用同一份数据管道,意味着你不需要为每个脚本单独准备数据,换一个入口就能重复利用之前生成的npy文件。你完全可以选择只跑通主入口,把另外两个当作进阶对照实验,这比一次吃三个模型稳妥。
2.3 复现前先做环境自检
这类项目的依赖通常很常规,但缺一个包就可能在数据加载阶段翻车。标准的深度学习环境配置顺序是:先装PyTorch,再补numpy、scipy、h5py、open3d这类工具库。我在新机器上一般这样走一遍:
conda create -n s3dis python=3.8 -y conda activate s3dis pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install numpy scipy h5py open3d环境装完后不要急着训练,先用最短路径验证模型能否前向传播。代码里如果没提供smoke test,就自己写一段:构造一个随机点云张量,过一遍models里的网络,看输出形状是否是[batch, points, num_classes]。这一步通常能暴露PyTorch版本不兼容、算子改名之类的暗坑。常见做法是在训练脚本里临时把epoch设为1、数据量截断到几十个样本,跑一遍再停,确认数据管道、损失函数、评估函数全链路通,再放开正式训练。不要一上来就铺满显卡跑几十轮,等烧完一个晚上才发现代码根本跑不通,会很被动。
3. 数据准备:从S3DIS原始点云到npy的完整链路
3.1 S3DIS原始数据获取与目录约定
S3DIS全称Stanford 3D Indoor Spaces Dataset,包含六个室内区域(Area 1到Area 6)的完整三维扫描点云,每栋楼的点云都带有13类语义标签:天花板、地板、墙、梁、柱、窗、门、桌、椅、沙发、书架、白板、杂物。它是室内场景语义分割的事实标准数据集,几乎所有点云分割论文都在这上面报mIoU。
官网下载时按“Stanford 3D Indoor Spaces Dataset”注册申请即可,拿到的是一个zip,解开后是每个Area目录的txt/ply文件。每个文件里每一行是一个点的三维坐标、RGB颜色和归一化坐标信息。你不需要等待官方提供额外的处理接口,直接用包内脚本完成转换。建议建立一个固定的数据目录结构,Windows和Linux通用:
data/ s3dis/ Area_1/ ... Area_2/ ... ... collect_indoor3d_data.py 的输出目录单独放在 processed/确认目录结构一致后,在项目的README里把数据和生成npy的放置路径写好,后续改代码、换机器重跑,都不用重新猜路径。
3.2 collect_indoor3d_data.py:点云去噪与逐文件切块
这个脚本的核心任务是把原始点云按房间切分成固定大小的块,并对每个块做降采样,保证输入到网络的点数是可控的。这块是整个数据链路的“地基”,很多复现失败源于切块时标签与坐标错位。
cd data_utils python collect_indoor3d_data.py脚本的典型逻辑是:遍历S3DIS每个Area目录,按房间或楼层加载原始点云,将整个场景切分为block_size×block_size的小块,再在每块内均匀采样固定点数。常见做法是block_size=1.0米、stride=0.5米(块之间重叠50%)、每块采样4096个点。块切得越大,上下文信息越丰富,但GPU占用越高;块越小,越容易丢失大物体结构。如果你只想快速验证流程,可把point_per_block降到1024,后续再升回4096。
脚本跑完后,控制台会出现每个Area的进度输出。看到生成的文件数量正确再继续,不要跳过这一步直接进训练。注意这里有个很容易被忽略的点:采集时把点云颜色做归一化(通常除以255),并把坐标缩放到以米为单位,如果源数据里坐标和颜色混在一列,读入时要按固定分隔符和列序解析。
3.3 indoor3d_util.py:npy样本生成与标签对齐
collect脚本完成块切分后,indoor3d_util.py负责把切分结果整理成标准npy格式。这个文件决定了DataLoader最终读入的数据长什么样。
典型的npy存储约定是每行一个点,每列分别是[x, y, z, r, g, b, label],有些版本还会附带法向量或强度的扩展列。你可以在运行后直接打印一个样本的shape确认:
import numpy as np sample = np.load('data/s3dis/processed/Area_1_1.npy') print(sample.shape, sample.dtype) # (num_points, 7) or (num_points, 9)生成的npy通常不区分训练集和测试集,而是靠文件里的Area编号来区分。常见划分方案是Area 1到Area 4加Area 6训练,Area 5测试。这种划分也叫Area 5验证,是S3DIS最通用的对比协议。如果你想做消融实验,也可以改成k-fold交叉验证,但工作量会增加不少。对于毕设场景,官方协议完全够用。验证标签是否对齐的方法很直接:用open3d加载该npy,把label列映射到颜色表上可视化,看桌面、椅子、墙面的边界是不是连续的。
3.4 S3DISDataLoader.py与provider.py:加载、采样与增强
数据管道到这里进入PyTorch侧。S3DISDataLoader.py实现Dataset类,核心方法__getitem__负责按索引读取一个npy块,再从块内采样固定点数。常见参数有三个:num_point(每块采样点数)、block_size(切块边长)、sample_stride(滑动步长)。这三个值直接影响训练速度和效果,如果显存不够,优先把num_point从4096降到2048,而不是去改网络结构。
provider.py是增强层,最常见的有随机旋转(绕z轴转一个随机角度)、随机抖动(给xyz加微小高斯噪声)、随机平移。旋转和抖动对语义分割提升显著,因为它们能模拟传感器在不同视角下的采集差异。但要注意增强强度不能过大,否则点云局部形状变形,反而让mIoU下降。实践里我会把rotation_range设为1度到10度之间、jitter标准差设为0.01米量级。跑之前打印一个增强后的点云块用open3d可视化,亲自确认没有发生过度的拉伸或错位。
4. 训练与评估:启动脚本、指标与可视化
4.1 三个训练脚本的启动参数与实验定位
环境装完、数据准备好,接下来就是正式训练。train_SUPnet.py是主入口,建议先跑它。以PyTorch项目最常见的命令行参数为例,启动命令大概长这样:
python train_SUPnet.py --epoch 100 --batch_size 8 --learning_rate 0.001 --gpu 0如果想走快路,把epoch降到50,batch_size降到4,也能看到完整训练流程。训练脚本里一般会包含SGD或Adam优化器选择、学习率调度、BN层设置和模型保存逻辑。PointNet++系模型用SGD配合momentum=0.9、初始学习率0.01的也很多,但实际效果和你选的batch_size强相关。我的血泪经验是:先按README里给的默认参数跑一轮,不要一上来就加花活,尤其是学习率调度器,等基线能复现了再调。
train_FG_F1F2.py和train_PW-ATM.py的启动方式类似,只是损失函数里多了约束项。做对比实验时,保持数据划分完全一致,只切换入口脚本,控制变量才成立。S3DIS每块是带重叠切出来的,所以训练和测试数据存在交叠风险,一定要确保验证用的Area完全不参与训练切块。
4.2 训练中需要盯住的几个关键输出
训练时的终端输出一般包括loss、逐类IoU、均IoU和像素准确率。每轮epoch结束时,我强烈建议同时保存一个checkpoint而不是只保留最优权重,因为后面万一指标震荡需要回滚就有后悔药吃。
python train_SUPnet.py --epoch 100 --batch_size 8 --learning_rate 0.001 --save_dir checkpoints/训练中期如果loss下降但mIoU停在原地,优先怀疑两个方向:学习率太大导致在最优值附近震荡,或验证集切块和训练集切块尺度不一致。一个可行的排查是打印几张验证集样本的预测结果,肉眼对比真实标签,看错误集中出现在哪些类别上。S3DIS里柱子和梁这类细长结构面积占比极小,即使整体acc很高,mIoU也可能很低,这时属于类别不平衡问题而不是程序bug。
4.3 test_SUPnet.py与结果可视化
训练完成后,test_SUPnet.py负责加载checkpoint并对指定Area做推理,输出结果.png。这份png通常会并排画点云原图、真实标签和预测标签三列。点云可视化如果画成二维投影,很容易把三维结构压缩得看不清边界,我一般会用open3d转一圈看分割整体效果,再按区域截局部细节。
import open3d as o3d import numpy as np data = np.load('data/s3dis/processed/Area_5_1.npy') points = data[:, :3] labels = data[:, 6].astype(np.int32) colors = np.zeros((points.shape[0], 3)) for c in range(13): colors[labels == c] = np.random.rand(3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(points) pcd.colors = o3d.utility.Vector3dVector(colors) o3d.visualization.draw_geometries([pcd])注意这段代码里label列索引要与生成npy时的列序一致,如果前面扩展了法向量维度,索引就要往后挪。换个现场数据时,先确认数据列序再动手可视化。评估指标除了mIoU之外,Dice系数和像素准确率在课程作业报告里也很有说服力。mIoU更关注类别间的均衡性,像素准确率则会被大面积背景带偏,同一份结果两个指标一起报告,老师或审阅者会认为你理解差异。
5. 避坑排查:复现时最容易翻车的五个环节
5.1 现象:训练正常但验证集mIoU个位数
原因:模型进入测试阶段时BN层统计量与训练阶段不一致,dropout也未关闭,导致验证推理输出分布漂移。这在使用PyTorch时最常见的是忘了调用model.eval(),或调用顺序不对。
解决:在test脚本里把model.eval()放到所有推理代码之前,并在推理循环外同步关闭dropout。同时检查是否用了torch.no_grad(),它不影响BN统计,不能替代model.eval()。我一般会在验证函数开头打印当前模型的training标志,确保为False。
5.2 现象:collect_indoor3d_data.py跑完,生成的npy数量远低于房间数
原因:原始点云文件中存在大量离群点或无效点(坐标为NaN或全零),切块时这些块被丢弃。也可能是坐标参考系没对齐,导致块切出来全部落在空白区域。
解决:在collect脚本里先按坐标范围过滤一遍离群点,再检查数据文件前100行的列是否完整。S3DIS官方数据有Aligned和unaligned两种版本,训练用Aligned版本。如果下载的是Raw版本,必须先做坐标对齐再切块,否则z轴方向混乱会让模型完全学不到几何结构。
提示:这类问题表现得很隐蔽,loss能降,但所有类别都预测成地板或墙体,多半是数据对齐或标签错位,不是模型问题。
5.3 现象:在Area 5上评估,mIoU比论文低10个点以上
原因:最常见的是Area切块策略与官方协议不同。论文里通常用Area 5作为测试,其余Area训练;如果实际代码把Area 5加了进去,相当于数据泄漏,测试集mIoU虚高。还有一种是切块步长设置过大,导致测试时每块的预测边界不连续,整体指标被拉低。
解决:在数据准备脚本里打印每个npy文件名前缀,确认测试Area没有出现在训练列表里。推荐用文件级划分而不是随机切分,否则同一块点云可能同时出现在训练和测试集,评估结果不可信。切块步长按数据集的通用约定,若原来用stride=1.0,就改成0.5并重新生成npy,重新训练再对比。
5.4 现象:Windows下训练中途报路径或文件读取错误
原因:项目中读取路径硬编码了Linux风格分隔符,有的是相对路径拼接错误,比如把data/s3dis/...拼成了data\s3dis\...之外的组合。还有一种情况是文件列表读取时没有排除隐藏文件或.meta文件缺失。
解决:把所有路径切换成统一的Path.join方式,并在读取文件列表时过滤目录项。数据文件里若引用了.meta或.json,先确认它们没有被杀毒软件抽走。建议在Windows上直接用pathlib替换字符串拼接,不只规避分隔符,还能顺手处理文件名大小写不一致的问题。遇到读取失败时,打印实际拼接出的路径,检查是不是存在空格或中文路径。
5.5 现象:训练时显存溢出或者CPU内存暴涨
原因:切块重叠率太高,导致DataLoader并行加载时(sample_stride=0.25)生成的npy块数量非常多,内存被中间张量占满。另一个原因是batch_size和num_point乘积过大,PointNet++的球查询在高密度点云上十分吃显存。
解决:先把batch_size降到2确认网络前向能跑通,再逐步递增到目标值。num_point是显存的直接乘数因子,优先降到2048。数据加载用num_workers=4分担预处理压力,如果内存还是涨太快,把sample_stride改回0.5重新生成数据,宁可块数少一点,也别把机器拖死。训练中期发现显存告警,把混合精度打开是收益最高的优化方式,完全不影响最终指标。
6. 迁移到自采数据并导出一个推理模型
三套脚本都跑通之后,真正的进阶是把这套流程用在自己的点云数据上。我建议分三步走:第一步,把自定义点云数据整理成和S3DIS相同的npy格式,行列含义保持[x,y,z,r,g,b,label],类别数改小;第二步,修改DataLoader里的num_classes和训练脚本里的类别映射,把原来的13改成自己的类别数量;第三步,可视化中间结果,确认切割块的标签边界没有错位。
python train_SUPnet.py --num_classes 5 --epoch 200 --batch_size 8 --learning_rate 0.001模型训练好之后收尾工作同样重要。训练好的权重是PyTorch的.pt或.pth格式,课程作业能跑通就算完成,但真要部署到演示环境,最好走一遍导出。PyTorch训练的模型可以先转成ONNX,再借助ONNX Runtime在C++端加载,这样漫游演示的实时性会好很多。转换时需要固定输入尺寸,因为ONNX导出不支持动态点云大小的隐式改变,一般把输入固定为(B, 4096, 3)。
pip install onnx onnxruntime python -m torch.onnx.export \ --model checkpoints/best_model.pth \ --input demo_input.npy \ --output supnet.onnx \ --opset 11导出后测试一次输出数值与PyTorch推理结果是否一致,避免后续C++调用时发现结果完全不对。训练脚本里的参数、预处理逻辑、类别色表要一并写进部署文档,C++代码里读到的类别索引才能对得上。
从那以后我每次拿到这类毕设包,都强制自己先走一遍“跑通主入口、生成数据、验证指标、再看论文”的顺序,不急着改网络结构。别一上来就动模型核心模块,基线还在跑就把注意力模块换掉,翻车了都不知道根因在哪。希望帮到你。
本文还有配套的精品资源,点击获取