本地模型做提取任务,这两年讨论最多的场景之一就是 building footprint extraction。简单说,就是从遥感影像或航拍影像里把建筑轮廓自动提出来,输出成可供 GIS 使用的矢量边界。和直接调云端 API 相比,本地模型的核心优势是数据不出环境、后处理可以反复改、批量任务跑起来成本更可控。但“本地能跑”和“本地能稳定产出可用结果”是两回事,很多人一开始只看到模型精度,实际落地时却被数据切片、环境依赖、输出管理这些事拖住。
这篇文章不打算堆功能列表,而是从一次横向对比的视角拆清楚:如果你要评估本地模型在提取任务上的表现,应该先准备什么、怎么跑通、怎么判断结果、遇到问题按什么顺序排查。无论你是做地理信息、遥感解译,还是单纯想把一套检测模型搬回本地跑批量,下面的思路都可以直接套用。
1. 先弄清楚“本地模型做提取”到底在对比什么
1.1 提取任务的两条路线:端到端分割和本地推理服务
“head to head”按字面理解是模型之间正面对比。放到提取场景里,我们通常比的是两条路线。
一条是端到端的语义分割模型。输入影像瓦片,输出每个像素的类别概率,再通过后处理把建筑区域转成轮廓。这条路线最直接,也是 building footprint extraction 最常见的做法。
另一条是本地部署的推理服务。模型被封装成接口,批量图片送进去,拿回掩膜或边界。这类服务可能是通用分割模型,也可能是针对建筑轮廓微调过的专用模型。它解决的问题是工程化接入,让上游系统和下游系统之间不需要手工拷贝文件。
这两条路线不冲突。很多落地流程是先用分割模型出掩膜,再用后处理算法修正边界,最后统一转矢量。对比时不要把“模型”和“工程流程”混在一起,否则你很难说清楚精度差异到底是模型带来的,还是后处理带来的。
1.2 对比本地模型时,不能只盯着平均精度
很多人在对比本地模型时只看一个数字,比如 IoU 或者 F1。这是最容易踩的坑。
提取任务真正要看的输出质量维度至少有五个:
- 完整度:建筑轮廓是否被完整识别,有没有一半被切掉。
- 边界精度:轮廓线是否贴合真实房顶边缘,有没有锯齿或内缩。
- 拓扑正确性:相邻建筑是否粘连,洞口、天井有没有被错误填充。
- 小目标表现:小房子、密集自建房、临时建筑是否被漏检。
- 泛化能力:换一个城市、换一种拍摄角度或光影条件后,精度下降多少。
同一个模型在不同数据上的表现差异可能非常大。本地的优势恰恰在这里:你可以用自己的数据反复试,把指标和可视化结果都放在一起,再做决定。只看平均精度选出来的模型,很可能在你自己的数据上并不是最优解。
2. 跑本地提取模型之前,先把环境条件列出来
2.1 显存、内存、磁盘和推理时间的基本判断
本地模型能不能跑,第一道门槛不是模型有多先进,而是你的机器能装下什么。
以常见的图像分割模型为例,判断条件大致是这些:
| 检查项 | 建议关注点 |
|---|---|
| 显存 | 单张推理时峰值占用,批量推理时按 batch size 成倍上升 |
| 内存 | 大影像切片、数据加载和缓存都会占用内存 |
| 磁盘 | 模型权重、中间结果、瓦片缓存都需要空间 |
| CPU | 数据预处理、后处理、矢量化通常吃 CPU |
| 推理时间 | 单张 512 或 1024 瓦片耗时多少,批量吞吐多少 |
这些数字没有一个固定的“够用标准”,因为不同模型、不同输入尺寸差异很大。更稳妥的做法是先跑一个最小样例,用监控工具记录峰值显存和峰值内存,再决定要不要加 batch size。
比如 Linux 下可以用 nvidia-smi 周期性记录显存,也可以用系统监控工具看 CPU 和内存。跑完一个小批次后,把峰值占用记下来,再倒推合理的并发数。不要一上来就开满并发,否则报的错很难判断是内存不足还是代码问题。
2.2 数据准备:影像、标签、范围、切片
building footprint extraction 的输入通常是遥感影像或无人机影像,输出是建筑轮廓。数据准备阶段要做四件事:
- 统一定义范围:想清楚提取对象是永久建筑、临时板房还是含棚房,这个定义直接影响标注和验收。
- 统一数据格式:影像的投影坐标系要一致,波段顺序要一致,尤其是多光谱数据。
- 检查标签质量:如果有现成的建筑轮廓标签,先检查错位、漏标、边界粗糙的问题,否则模型学到的就是错误边界。
- 切片:大影像一般切成 512 或 1024 的瓦片再送进模型,切片时要注意重叠率,避免建筑正好被切在边缘。
切片重叠率通常建议 10% 到 25%。重叠太小,边缘建筑容易被截断;重叠太大,推理成本翻倍。这个值没有绝对标准,要看你目标建筑的平均尺寸。如果建筑普遍很大,重叠率要适当提高;如果建筑小而密,可以适当降低。
2.3 依赖工具链的选择
本地跑这类任务,常见依赖包括深度学习框架、图像处理库、矢量处理库。
比较常见的组合是 PyTorch 加 OpenCV 加 shapely 或 geopandas。如果你的流程里还要做瓦片拼接和矢量化,GDAL 和 rasterio 也几乎绕不开。这里给的是通用组合,原始材料没有给出明确版本,落地时一定要先确认依赖版本和你的 CUDA 环境是否匹配。
我踩过不少次因为 PyTorch 和 CUDA 版本不匹配导致推理直接报错的坑。这类问题看起来像模型问题,实际上和环境问题差不多。第一次搭建环境时,建议把框架版本、CUDA 版本、显卡驱动版本都记录下来,放到项目 README 里。换机器、换环境时,这份记录能省很多时间。
3. 单条样本验证:先跑通,再谈对比
3.1 最小验证流程
多模型对比之前,先保证每个模型在同样的单条样本上能稳定跑通。我会这样拆:
- 准备一张裁剪好的影像瓦片,尺寸固定在 512 或 1024。
- 写出一个最简单的推理脚本,输入这张瓦片,输出掩膜。
- 记录日志:模型输入路径、模型权重路径、预处理方式、推理耗时、输出路径。
- 检查输出不是空数组,掩膜尺寸和输入一致,类别数量正确。
示意图如下:
# 单条样本验证脚本(示意) model = load_model("weights.pth") tile = read_image("sample.tif") tile = preprocess(tile) # 归一化、裁剪、通道调整 mask = model.predict(tile) # 输出概率图或掩膜 save_mask(mask, "output/mask.tif")先跑单条任务的意义在于把变量减到最少。如果这一步就挂了,后面所有对比数据都不可信。不要拿一个还没验证过的脚本直接跑几十张图,否则你可能花了很多时间,最后发现是预处理写错了。
3.2 输出结果怎么检查
模型输出通常是概率图或二值掩膜。检查时不要只看有没有形状,要看边界是否合理。
我一般做三件事:
- 把掩膜叠加到原图上,目视检查建筑边缘是否贴合。
- 用连通域分析看是否有大量碎块。
- 统计掩膜面积和标签面积的偏差,如果系统性偏大或偏小,说明模型有系统性偏移。
这一步不需要很复杂的代码,但很能说明问题。输出质量不是靠一个指标决定的,可视化复查在提取任务里几乎是必需的。
3.3 成功标准:不是“跑出来”就结束
单条样本的验收标准至少包括三部分:
- 不报错:推理脚本从头到尾没有异常。
- 输出完整:掩膜尺寸、通道数、数据范围都正确。
- 结果可用:目视检查轮廓基本贴合,没有大面积误检。
如果这三条都满足,再进入多模型对比。这里要额外提醒一句:成功标准里要写清楚“什么是失败”。比如输出为空、输出错位、输出全是背景,都算失败。把失败定义写清楚,批量跑的时候你才知道哪些结果需要重新处理。
4. 多模型横向对比,要控制哪些变量
4.1 统一数据、统一指标、统一后处理
“head to head”最怕的就是变量控制不一致。对比至少要做到三个统一:
- 统一测试数据:同一批影像、同一个切片方式、同一套标签。
- 统一前后处理:归一化方式、颜色通道顺序、是否反转、后处理阈值,都要一致。
- 统一设备环境:同一台机器、同一个推理框架版本,至少要记录清楚。
如果 A 模型用了精细后处理,B 模型直接用原始概率图做阈值,那对比出来的是“后处理后的 A”和“后处理前的 B”,不是模型本身的对比。这个道理很简单,实际操作时却经常被忽略。
具体执行时,我建议先把后处理流程抽成独立函数,所有模型共用。这样既保证公平,也方便后面单独调后处理参数。后处理对提取结果的影响,有时候比模型选择还大。
4.2 指标怎么看:IoU、F1、边界完整度、推理耗时
提取任务常用指标可以分成两类:质量指标和成本指标。
| 指标 | 看什么 | 注意点 |
|---|---|---|
| IoU | 预测掩膜和真实标签的重叠程度 | 对边界偏移敏感,但无法反映拓扑错误 |
| F1 | 精确率和召回率的平衡 | 小目标多时,单独看 F1 不够 |
| 边界完整度 | 轮廓是完整还是断成多段 | 需要后处理统计,光看 IoU 看不出 |
| 推理耗时 | 单张瓦片耗时和批量吞吐 | 包含预处理和后处理才是真实耗时 |
| 显存峰值 | 单卡还是多卡、batch 多大 | 影响你能跑多大的模型和并发 |
建议不要只看一个指标。同样的 IoU,一个模型可能是边界外扩,另一个是漏检部分建筑,这两个问题在业务上的影响完全不同。边界外扩的问题可能通过收缩后处理解决,漏检却很难靠后处理补回来,两者处理的优先级不一样。
4.3 可视化对比和人工复核
自动指标只能告诉你“差多少”,不能告诉你“差在哪里”。我会把多个模型的结果并排输出成对比图,按区域放大看三类问题:
- 密集建筑区是否粘连。
- 阴影、树木遮挡区域是否漏检。
- 大型建筑屋顶边缘是否被切碎。
如果有条件,找一位懂业务的人一起看结果。建筑提取的标准不完全由模型决定,还取决于下游用途,比如做城市管理、做变化检测、做三维重建,对边界精度的要求都不一样。让业务方参与复核,能避免你只盯着指标调模型,最后交付的东西却不符合实际需求。
5. 从单模型到批量提取落地
5.1 切片推理与原图拼接
单张瓦片跑通后,批量提取的第一步是把大影像切成瓦片,推理完成后把掩膜拼回原图坐标系。
拼接时要注意:
- 每个瓦片要记录它在原图中的行列偏移,否则拼回去会错位。
- 重叠区域要决定融合策略,常见做法是取中间区域或加权平均。
- 拼接完成后要裁剪到原图范围,避免边缘多出黑边。
这个阶段最容易出的问题不是模型,而是坐标偏移。我见过很多次结果看起来“好像还行”,一叠加到原影像上就发现整体平移了几十个像素。排查时优先检查瓦片坐标记录和重采样方式,而不是调模型。
5.2 批量任务需要的队列、日志和失败重试
批量推理不能只写一个 for 循环。至少要处理三件事:
- 任务队列:把瓦片列表按顺序排队,能暂停、能续跑。
- 日志记录:每张瓦片的输入、输出、耗时、是否成功都记录到文件。
- 失败重试:单张失败不能导致整个批次中断,失败的要单独重试。
还有输出命名。批量任务里输出文件命名是重灾区,建议用“原图名加行列号”的方式生成唯一文件名,避免覆盖和混淆。比如 tile_scene01_row012_col034_mask.tif,一眼就能看出这张结果来自哪个位置。
如果可能,给每个批次生成一个批次 ID,并把配置参数、模型权重路径、数据版本都写进日志。这样出了结果问题,你能快速定位是哪一批、哪个参数、哪个模型版本。
5.3 从栅格结果到矢量边界
掩膜是栅格结果,但 building footprint extraction 的业务交付通常是矢量边界。从栅格到矢量的常用流程是:
- 对掩膜做后处理,去掉碎块、填补小洞。
- 使用轮廓提取算法生成多边形。
- 对多边形做简化,去掉过多顶点。
- 按最小面积阈值过滤噪声。
这一步里两个参数很关键:最小面积阈值和简化容差。最小面积太小,会留下大量噪声碎片;简化容差太大,直角屋顶会被抹圆。建议先在小范围测试,目视确认后再套用到全图。
6. 常见问题排查和适用边界
6.1 精度低、边界碎、漏检、卡死的排查顺序
本地提取模型最常见的四类问题,建议按固定顺序排查。
精度低:先看测试集和训练集是否同分布,再看标签是否准确,最后再看模型输入尺寸是不是太小。不要一上来就换模型,很多精度问题出在数据而不是模型。
边界碎:先看后处理有没有做连通域合并和轮廓简化,再看掩膜阈值是否合理。边界碎通常是后处理不足,而不是模型能力问题。
漏检:先看切片重叠率,再看小目标是否被下采样过滤掉。如果建筑尺寸远小于输入瓦片的一个像素,漏检几乎是必然的。这时候要考虑提高输入分辨率,或者分层处理不同尺寸的目标。
卡死或无输出:先看显存和内存占用,再看日志有没有异常,最后看输出目录权限和路径。任务卡住时先确认资源占用和输出目录,不要盲目重启。
6.2 参数边界:不是分辨率越高越好,不是并发越大越快
提取任务里有两个很容易被夸大的直觉。
第一个是“分辨率越高越好”。输入分辨率提高,模型确实可能看得更细,但推理时间、显存占用、后处理复杂度都会上升。而且如果训练数据的标签边界本身不精确,高分辨率只会把标签错误放得更大。建议从模型训练时的原始分辨率开始测,不要随意加码。
第二个是“并发越大越快”。批量推理时并发增加会提升吞吐,但到一定程度后,GPU 显存和 CPU 预处理会成为瓶颈,速度不再线性提升,还可能因为显存溢出直接挂掉。建议先跑一个并发梯度测试,比如 1、2、4、8,找到拐点再确定生产并发数。
6.3 什么时候不要迷信本地模型
本地模型很好,但不是所有场景都适合。如果你的数据量很小、只需要一次性提取,或者对时效性要求极高,云端 API 可能更合适,因为本地部署和调试的成本摊薄不下来。反之,如果你要长期批量处理、数据又不能出环境,或者需要反复调后处理,本地模型就是更合理的选择。
还有一类情况要单独说:模型选择不要只看“本地能跑”。能跑只是第一步,批量稳定性、输出格式统一性、后处理可维护性,才是真正决定这个方案能不能长期用的因素。很多项目不是死在推理精度,而是死在输出管理混乱和失败重试缺失。
踩过不少次之后我的判断是:本地模型做提取,真正该盯住的不是模型列表,而是输入数据、资源占用和失败重试这三件事。先把单条样本跑稳,再把对比变量控制住,最后再考虑批量和接口。这个顺序看起来慢,实际是最省时间的。如果你正在做 building footprint extraction 或者类似的本地提取任务,按这个流程走一遍,基本上能把 80% 的坑提前踩掉。