做图像标注这行的都懂一个别扭的地方同一张图语义分割刷一遍像素标签实例分割拉一遍框全景分割再把两者拼起来交互式抠图工具又要重新点一遍。一个项目下来四套工具、四份标注、四个模型最后还得写胶水代码把结果对齐。前段时间一位做工业质检的开发者给我看他们的标注后台一张电路板照片五个同事用五种工具各标了一遍人工校验耗掉两天最后发现实例掩码和语义标签的边界还打架。这篇要聊的Segment-Everything-Everywhere-All-At-Once为了叙述方便我把它缩写成 SEE-AO它想干的事其实很朴素一次前向、任意提示、任意粒度。Everything 指覆盖画面里所有目标而非只认训练好的那几类Everywhere 指跨场景跨模态都能接All-At-Once 指不用先分类再分割、不用先检测再抠图一个请求出去掩码直接回来。这是一套多模态图像分割系统输入可以是一个点、一个框、一张粗糙掩码也可以是一句自然语言描述输出是像素级掩码加置信度。适合谁看如果你在做数据标注平台、工业质检、遥感解译、医学影像预处理、内容审核或者单纯想把分割一切这件事塞进自己的产品链路这篇的经验都能直接拿去用。全文按我自己的踩坑顺序组织先讲这套统一方案到底解决了什么结构性问题再钻进模型内部看三个舱室怎么分工然后聊数据引擎这个容易被低估的一半最后是推理部署和落地时那些文档里不会写的坑。基础一般的读者可以只看第 1 节和第 4、5 节想自己训一版的从第 2、3 节入手。1. 四套工具、四份标注分割任务为什么非拆不可又为什么必须合1.1 语义分割、实例分割、全景分割与交互式抠图各自的算盘先把这个领域的分家史说清楚不然理解不了统一模型的价值。语义分割只管像素属于哪一类同一类的两头牛在输出图里是同一种颜色它解决的是这片区域是什么实例分割反着来先找目标框再把框里的像素抠出来同一类要区分个体它回答有几个、分别在哪全景分割是前两者的缝合把不可数的背景归为语义、可数的前景归为实例好处是一次输出完整场景坏处是标注成本翻倍交互式分割又是另一条路用户点一下、画个框模型给出精细边缘它不关心类别只关心你指的那个东西的轮廓。这四件事在工业界被拆成四个模型、四条数据管线背后有很实在的历史原因。语义分割的经典结构是编码器-解码器全卷积网络损失用逐像素交叉熵训练目标是把每个像素分对实例分割主流是检测框 框内掩码的两阶段路线或者中心点 嵌入向量的单阶段路线训练目标是让同一实例的像素在嵌入空间靠近全景分割则要在后处理阶段做启发式合并把语义结果和实例结果在重叠区域仲裁交互式分割的输入里有人工提示网络结构必须支持提示编码训练数据是图 提示 掩码的三元组。拆开的好处是每个任务都能把结构调到最贴合自己的形态坏处列举起来一长串标注成本重复同一张图的像素标签被标了三四遍误差累积检测框偏一点框内掩码就跟着偏维护成本四个模型的输入格式、预处理、后处理、部署方式都不一样粒度断裂语义分割给不出个体实例分割又常常忽略背景这类无个体概念的区域。我在一个遥感项目里见过最夸张的情况地块语义分割用一套管线建筑物实例分割用另一套最后要做某地块内建筑物占地面积占比这个指标得写两百多行代码去对齐两套坐标系和两张掩码。所以统一方案的价值不在于少训一个模型这么简单它真正改掉的是任务定义方式不再用任务来切分模型而是用提示来切分请求。你想要语义结果就给类别文本提示想要实例就给点或框想要全景就把网格点铺满整图让模型自己吐所有目标。粒度变成调用侧的参数而不是模型的结构。1.2 把粒度、提示、模态塞进一次前向真正的难点在哪统一两个字说起来轻松实际要跨过三道坎每一道都能把方案卡死。第一道是提示空间的统一。点、框、掩码、文本这四种输入的形态差异极大点是两个数字框是四个数字掩码是一张二维图文本是一串离散 token。要让一个解码器同时吃下它们必须把它们投影到同一个维度的向量空间里且语义上要能相加。这里的关键是加法可交换——一个框的提示和一个点的提示叠加后解码器应该理解成在框的约束下重点看这个点而不是两个互不相干的信号。做不好这一步多提示组合就会互相干扰我早期实验里最典型的现象是框 负点组合后掩码直接变成整张图。第二道是粒度歧义。用户点在一头牛的背上他想要的是整头牛、牛的躯干还是牛背上那块斑纹这个歧义在单任务模型里被数据集定义掩盖了实例分割数据集只标整头牛但在统一模型里会直接暴露。解法通常是让模型一次输出多个候选掩码并给每个打分把选择权交回调用侧。这个设计看着像偷懒实际上是这套方案最实用的地方之一后面 2.3 会展开。第三道是模态对齐。文本分支的语义空间和视觉分支的语义空间天然错位同一个词在图像里对应的区域大小可能差几十倍。这里最容易出的问题是类别词能对齐、修饰词对不齐——车能分对红色的车就经常把旁边红色的广告牌也框进来裂缝能分对细长的裂缝反而因为形状先验被切碎。这个裂缝不是靠加大模型能补的得靠数据侧的负样本设计和推理侧的提示改写4.3 会讲具体手段。提示如果你评估一个统一分割方案时对方只演示单点分割的效果不给多提示组合、不给粒度歧义场景、不给同一张图的重复请求延迟那基本可以判断这套方案还没过工程关。1.3 Everything和All-At-Once的边界这个方案不承诺什么标题里的词很唬人实际用起来必须先划清边界否则期望管理会崩。它不承诺零样本覆盖一切。所谓 Everything指的是在同一次前向里尽可能多地吐出候选目标而不是对世界上任何物体都有正确语义。遇到训练分布外的材质比如高反光金属、透明玻璃、极细的纤维它照样会给出边界模糊的结果。真正的覆盖度取决于数据引擎喂进去的分布模型结构只是把能接住多少的天花板抬高了。它不承诺实时全图分割。All-At-Once 说的是一次请求内完成不是一帧内完成。全图密集提示比如每隔 16 像素撒一个点在 1024 分辨率下是几千个提示解码器再轻量也扛不住几毫秒实际工程里必须做提示采样和去重。它不承诺输出就是最终标注。全自动生成的掩码只适合做预标注必须有人工审核环节。我在一个内容审核场景里试过纯自动跑5% 左右的掩码存在包含多余背景或缺一块的问题直接入库会导致下游统计口径漂移。它也不替代检测模型。分类置信度和框回归这件事专用检测器依然更准更快。统一分割系统的正确位置是接在检测后面做精细化或者接在人工点击后面做边缘补全而不是把检测器整个替掉。把这三条边界想清楚后面所有的结构设计和工程取舍才有落脚点。这也是我看任何新方案的第一反应先问它不做什么再问它怎么做。2. 拆开多模态分割模型的三个舱室2.1 图像编码器贵在哪里为什么只能跑一次整个系统里最重的部分就是图像编码器通常是一个视觉 Transformer 主干把 H×W×3 的图变成 h×w×C 的特征图。以常见配置为例输入 1024×1024patch 尺寸 16那么特征图是 64×64如果主干是 24 层、宽度 1024 的规模参数量在三亿量级用半精度存权重就要 600MB 出头推理时的激活峰值能到 4~6GB。要是换成更宽更深的版本参数量翻倍显存也跟着翻倍。为什么它只能跑一次因为它和提示无关。图像编码器看到的是图本身不管用户问什么这张图的特征表示是一样的。这套架构把看图和答题彻底分开看图是一次性的重活答题是轻量的活。这个拆分是整套方案能在交互式场景落地的根本原因。算一笔账就明白了。假设图像编码在中等加速卡上耗时 120~180ms解码器单次耗时 5~10ms。用户第一次点下去总延迟是 150ms 左右第二次、第三次点击如果缓存了图像特征延迟就只有 10ms 以内。从每次点都等半秒变成只等第一次交互手感完全是两个产品。我做过一个对比测试同一张图连续点 8 个目标不缓存的总耗时约 1.3 秒缓存后约 0.35 秒。成本控制上有三个经验点值得说。其一长宽比处理不要用 resize。直接把非正方形图拉伸到 1024×1024 会让物体变形边界精度显著下降。正确做法是保持长边缩放到 1024短边补零到 1024同时在元数据里记录原始尺寸和有效区域后处理时把掩码裁回有效区域再缩放到原图。这个补零 记录有效区的细节看着琐碎但它是边界精度不掉的关键。补零的代价是短边方向有大量无效计算一张 1920×1080 的图缩到 1024×576补零后仍有 44% 的面积是空的这部分算力纯属浪费。其二位置编码要支持插值。主干在固定分辨率上预训练换分辨率时位置编码得做双线性插值否则特征会错位。这个坑很隐蔽表现是换分辨率后掩码整体偏移几十像素很多人第一反应是后处理坐标系错了其实是位置编码没处理。其三主干可以选小一号。如果业务对边界精度要求没那么苛刻宽度减半的版本能把显存压到 2GB 出头速度快一倍多掩码质量在常规物体上掉 2~3 个 IoU 点。我在移动端边缘设备上就用过小主干 后处理细化的组合总体效果比大主干单跑更划算。2.2 提示编码器点、框、掩码、文本怎么挤进同一个256维空间这是整套设计里最巧的一块也是我最开始没看懂的地方。四种模态的输入最后都要变成一组 256 维的向量和解码器的 token 序列拼在一起。点的处理每个点有坐标和标签正点表示要这个负点表示不要这个。坐标先做归一化再用一组不同频率的正弦函数编码成高维向量这样相邻位置在向量空间里也相邻标签用一个可学习的嵌入向量表示两者相加。这样在 (320, 480) 的一个正点就变成了一个 256 维向量位置信息和意图信息都在里面。框的处理不把框当成四个数字去回归而是用两个角点各自的编码加上一个表示左上/右下的嵌入。框还额外提供一个稠密提示——在框内填充、框外留白的低分辨率图经过几层卷积压到 64×64×256直接加在图像特征上。这个设计的意思是框既作为稀疏 token 告诉解码器大致范围又作为稠密先验去调制特征图。实测下来这个稀疏 稠密双路设计对小目标特别重要只给稀疏 token 时小目标经常被漏掉。掩码的处理用户给的粗糙掩码比如用笔刷涂的一片先下采样到 256×256再过几层卷积到 64×64和图像特征的尺度对齐后相加。这里要注意掩码输入的意义是约束不是替代所以它的权重不能太大否则模型会完全沿用粗糙掩码的烂边缘。文本的处理分词后过文本编码器得到每个 token 的向量再投影到 256 维。这里有个工程细节文本 token 的数量不固定而解码器的 token 序列要定长通常做法是保留一个固定的最大长度不足补零并加一个有效位标记。文本 token 和点框 token 在序列里的位置不同注意力机制会自己学会区分。提示类型编码方式输出维度常见误用点位置正弦编码 标签嵌入1×256坐标忘记归一化导致尺度偏差框双角点编码 框内稠密图1×256 64×64×256只给稀疏 token小目标漏检掩码下采样 卷积投影64×64×256权重给太大模型沿用烂边缘文本分词 文本编码器 投影N×256长度未定长批处理报错多模态同时输入时坑最多的是冲突仲裁。比如用户给了一个红色的文本提示又给了一个落在蓝色区域的正点模型该听谁的实测下来空间提示点、框的权重通常高于文本提示因为空间提示更明确。如果业务上希望文本优先得在推理时做提示加权或者干脆拆成两次请求再合并。2.3 掩码解码器轻量双向注意力与一次输出三个答案的用意解码器是整个系统里最轻的部分通常只有两层 Transformer每层四个注意力头中间维度 2048。它的工作流程是把提示 token、若干可学习的输出 token、图像特征拼成一个序列做token 到图像和图像到 token的双向注意力几轮之后输出 token 上就带有了这个提示对应哪个区域的信息。为什么要双向单向注意力token 只看图像能解决提示在哪但解决不了提示边界在哪因为边界信息分散在图像各处。加了图像到 token的反向注意力后图像特征会被提示调制聚焦到相关区域边界细节才出得来。这个设计在论文里往往一笔带过但它是边界精度不掉的核心。输出 token 经过几层感知机后一路生成掩码一路生成该掩码的质量分。掩码的生成方式是先得到 256×256 的低分辨率掩码再用两次转置卷积上采样到 1024×1024中途和图像编码器的中间层特征做跳跃连接。这里为什么用转置卷积而不是直接双线性插值因为边界细节需要在低分辨率阶段就学出来双线性插值只能平滑补不出细节。一次输出三个掩码这个设计值得单独说。给定一个点模型同时给出三个候选整体、部分、子部分每个配一个置信度分。举例来说点在一辆车上三个候选可能是整辆车、车门、车窗。这个设计解决的是粒度歧义把用户到底想要哪一层的判断交给调用侧。实际用的时候多数场景直接取置信度最高的那个如果做标注辅助三个候选都摆出来让人选效率比重新点一遍高得多。但这里有个容易被忽略的问题置信度分是模型自己估的不是真值校准过的。我做过统计置信度 0.9 以上的掩码实际 IoU 在 0.82~0.95 之间波动在细长物体和透明物体上偏低。所以拿它做自动过滤时阈值不能设太松我一般设 0.88 起步配合后文的稳定性检验。解码器的另一个轻量化技巧是输出 token 数量固定且很少通常四五个就够。这带来一个好处批处理时不同样本的 token 数一致不会出现变长序列的补齐浪费。2.4 文本分支接入后的对齐裂缝纯视觉提示点、框、掩码的系统相对好做因为提示和输出在同一个视觉空间里。一旦接入文本问题就变成语言空间和像素空间怎么对齐。常规做法是先用大规模图文对做对比预训练让文本编码器和视觉编码器在同一个语义空间里。这套预训练能解决名词对齐但解决不了三件事。第一件是修饰词。红色的车里红色这个词在预训练时更多和红色物体关联而不是和车的颜色关联。结果就是模型会把画面里所有红色区域都拉进来。缓解办法是在训练数据里构造同物体不同属性的对比样本让模型学会属性是绑定在物体上的而不是全局的。第二件是数量词和空间关系。左边的螺丝、三颗芯片这类描述需要模型理解空间布局和计数。这类能力靠分割数据本身很难训出来通常得引入带空间关系标注的数据或者在推理时把文本拆成目标词 空间约束空间约束转成框提示再和文本提示组合。第三件是领域词。工业场景里的焊点虚焊、丝印偏移医学场景里的磨玻璃影这些词在通用图文对里几乎不存在。指望预训练模型认识它们不现实必须在领域数据上做微调而且要保证文本编码器也参与微调不能只调解码器。我见过一个团队只调解码器结果模型对领域词的反应和随机词差不多白训了两周。一个实用的折中方案是建同义词表。把领域黑话映射到模型认识的通用词上比如把虚焊映射到小的圆形凸起把丝印偏移映射到文字位置偏移。这个土办法效果出乎意料地好成本几乎为零适合快速验证阶段。3. 数据引擎比网络结构更决定上限的那一半3.1 辅助标注、半自动、全自动的三段式闭环统一分割模型的效果上限七成在数据三成在结构。这句话我在不同项目里验证过好几次。数据引擎的核心思路是模型帮人标人帮模型改分三段走。第一段是辅助标注。人工在图上点几下模型给出候选掩码人工修边。这一步的模型可以很弱甚至用传统算法都行目的是把从零画轮廓变成改轮廓。实测下来这一步能把单张图的标注时间压到原来的三分之一左右。关键指标不是模型的绝对精度而是人工修改量——如果每次都要大改省的时间就被抵消了。经验阈值是模型给出的掩码和人工最终结果的 IoU 在 0.75 以上时改起来才划算。第二段是半自动。模型批量出候选人工只做接受/拒绝/粗修三选一。这一步需要一个筛选机制把明显烂的掩码提前扔掉减少人工看的时间。筛选靠两个信号模型自估的置信度分以及掩码的稳定性——对同一提示做多次轻微扰动比如把点挪动两像素、把框缩放 5%看输出掩码的 IoU 波动。波动小于 0.05 的判为稳定。第三段是全自动。在图上铺网格点或者用检测器出框让模型自己生成掩码再用稳定性 置信度 规则面积上下限、长宽比、是否压边过滤。这一步产出的数据质量参差只能作为训练数据的补充不能作为评测集。我们当时的比例是全自动数据占训练集的 60%半自动占 30%纯人工的精标占 10%精标那部分专门用来做验证和难样本挖掘。这套闭环有个容易被忽略的点每一段都要留人工抽检。全自动那段的抽检比例我一般设 2%抽到的错误样本反向补充到难样本池里下一轮训练重点关照。不设抽检的话错误会静默累积等你发现时模型已经在错误分布上训了很久。提示数据引擎里最贵的不是标注人力是返工。把抽检机制和难样本回流的路径设计好比多买几张卡有用得多。3.2 损失函数组合与难样本重采样分割任务的损失不是单一指标能覆盖的常规组合是三项相加。掩码损失用焦点损失加 Dice 损失的组合。焦点损失负责逐像素分类处理正负样本极度不平衡一张图里目标像素可能只占 2%其中聚焦参数取 2、平衡参数取 0.25 是常用配置Dice 损失负责整体重叠度对边界不敏感但对漏掉一整块很敏感。两者权重一般是 20:1焦点损失占大头。为什么差这么多因为逐像素分类是基础Dice 是修正项权重给大了会让模型过度追求整体覆盖而忽略细节边界。质量分损失用均方误差把预测分和真实 IoU 拉近权重通常设 0.05。这项权重小是有原因的它只影响候选排序不影响掩码本身权重大了反而会干扰主任务。难样本处理靠提示采样策略。训练时每张图不只用一个提示而是采多个一个来自真值掩码模拟用户点对了其余来自随机采样模拟用户点偏了或点在背景上。这个比例大概是 1:10也就是一个正样本配十个随机样本。这样训出来的模型对点偏了有鲁棒性不会因为点落在物体边缘就崩掉。我踩过的一个坑是难样本挖得太狠。有一版训练里我把所有低 IoU 的样本加权三倍重复采样结果模型在难样本上确实提升了但在常规样本上退化了整体指标反而降了两个点。原因是难样本里有一批是标注本身就有争议的比如物体边界模糊、遮挡严重模型在这些样本上学到的是噪声。后来的做法是难样本加权 1.5 倍封顶并且人工过一遍剔除标注有争议的。另一个经验是空掩码样本必须有。也就是这个提示在图上没有任何对应目标的情况模型要能输出空结果。这类样本在训练集里占比建议 5%~10%。没有这类样本模型遇到点在纯背景上时会强行编一个掩码出来这在自动标注场景里是灾难——它会凭空造出目标。3.3 小规模复现训练流水线与关键超参想自己跑一版不用从零开始。下面是我用过的一条可复现的流水线骨架规模不大单机八卡能跑起来。# 伪代码单轮训练主循环 for images, gt_masks, texts in loader: # 1. 图像编码可梯度也可冻结前几层 feats image_encoder(images) # B×256×64×64 # 2. 提示采样1 个来自真值10 个随机 prompts sample_prompts(gt_masks, k_pos1, k_neg10) # 3. 解码每个提示输出 3 个候选掩码 3 个质量分 pred_masks, pred_iou mask_decoder(feats, prompts) # 4. 多项匹配候选和真值做匈牙利匹配选损失最小的那个 matched hungarian_match(pred_masks, gt_masks) # 5. 三项损失 loss 20 * focal_loss(matched, gt_masks) \ 1 * dice_loss(matched, gt_masks) \ 0.05 * mse_loss(pred_iou, true_iou(matched, gt_masks)) loss.backward() optimizer.step()关键超参我列一下都是试出来的参数取值说明优化器AdamW权重衰减 0.1主干学习率1e-5比解码器低一个量级解码器学习率1e-4前期可以再高一档批大小每卡 4梯度累积 4等效批 128输入分辨率长边 1024短边补零不要拉伸提示采样正 1 负 10负样本含背景点和随机框训练轮数30~50 轮超过 60 轮开始过拟合预热前 2 轮线性预热防早期梯度爆炸关于冻结策略我的建议是前 5 轮冻结主干只训解码器。理由是预训练主干的特征已经很好了一开始就让大学习率去动它容易把好特征破坏掉。5 轮之后再解冻用很小的学习率微调效果比全程联合训练稳。还有一个容易忽略的细节真值掩码的边界要处理。不同标注源的边界习惯不一样有的贴紧物体有的习惯往里收两像素。混在一起训模型会学出一个平均边界结果两边都不像。我的做法是在数据加载时对边界做一致性处理把外扩两像素以内的像素权重降到 0.5让模型不必纠结这几像素的差异。4. 推理侧问题排查显存、分辨率与退化场景4.1 分辨率和显存的死结以及padding带来的隐性浪费分辨率往上走边界精度明显变好但显存和耗时也线性甚至平方级上涨。这个矛盾没法完全消除只能找平衡点。我实测过几档分辨率的组合用的是中等规模主干输入长边显存峰值单次编码耗时边缘精度相对值512约 2.2 GB约 45 ms0.82768约 3.6 GB约 80 ms0.911024约 6.0 GB约 150 ms1.001280约 8.8 GB约 230 ms1.03可以看到从 1024 到 1280显存涨了 47%耗时涨了 53%精度只涨 3%。所以1024 是性价比拐点除非业务是精细边缘比如缺陷检测里的发丝级裂纹否则没必要往上堆。padding 的隐性浪费前面提过一半这里补充一个优化思路按批次内的最大长宽比补齐而不是统一补到正方形。如果一批图都是宽幅比如 1920×1080统一补成 1024×1024 会让短边方向空白 44%改成补到 1024×640 就能省掉这部分算力。实现上要用掩码注意力把空白区域屏蔽掉否则空白区的特征会污染结果。另一个必须做的事是图像特征缓存。缓存键用图片内容的哈希不用文件路径同名不同内容的图很常见。缓存值存 64×64×256 的特征图单张占用约 4MB半精度缓存 500 张就是 2GB用内存或者本地 SSD 都行。命中率在标注场景里非常高因为标注员会在一张图上反复点。我做过统计开了缓存之后标注平台的 GPU 平均利用率从 70% 降到 35%同样的卡能多扛一倍的人。4.2 小目标、细长结构、透明件的典型失败模式这三类是我遇到问题最多的场景每一类都有对应的缓解手段。小目标面积小于 32×32 像素的目标掩码经常整个丢失或者只剩半个。根本原因是特征图是 64×64一个小目标在特征图上不到一个格子信息在编码阶段就被压没了。缓解手段有三个提高输入分辨率最直接但最贵、在特征图上做多尺度融合把浅层高分辨率特征接进来、用框提示代替点提示框的稠密先验能显著提升小目标召回。第三个最省钱实测点提示换成紧贴目标的框提示小目标召回率能从 55% 提到 78%。细长结构电缆、裂纹、血管、细线条掩码容易被切碎成好几段。原因是转置卷积的感受野偏方正对 1~2 像素宽的细长结构不友好。缓解办法是后处理接一个形态学闭运算核大小 3×3 或 5×5把断开的段连起来或者在训练数据里对上采样阶段做细化标注让模型学到细长不断的先验。我试过直接改网络结构加方向卷积收益不明显性价比不如后处理。透明件玻璃、塑料膜、水面边界几乎没有颜色差模型给出的掩码往往偏大或者偏小。这类场景纯靠外观分割是做不到的必须引入额外线索——比如偏振图、深度图或者在提示里加入边界在哪的框约束。工程上更现实的做法是把它标成不确定交给人工而不是硬让模型猜。还有一个隐蔽的失败模式是大面积同色区域比如白墙、天空、纯色布景。模型在这种情况下会把整个区域当成一个目标吐出来甚至把不同物体连成一片。缓解办法是在提示里加负点或者设面积上限比如超过图像 40% 的掩码直接判为可疑降级处理。4.3 文本提示歧义的消解手段文本提示的好处是零门槛坏处是歧义多。我在实际项目里总结了四条处理原则。原则一把模糊词换成可视觉化的词。损坏→缺口或裂纹脏污→深色小斑块缺陷→形状不规则的小区域。这一步本质上是把抽象判断转成外观描述模型才能接住。原则二加空间锚点。与其说螺丝不如说左上角那颗螺丝具体做法是把空间词转成框提示和文本提示一起送进去。这个组合的准确率比纯文本高出一截。原则三用负向提示排除干扰。想分红色指示灯但画面里红色太多加几个负点落在其他红色区域上效果立竿见影。这个技巧成本极低但很多人不知道。原则四接受多候选。文本提示天然有多解让模型出三个候选再筛比反复改写提示更省事。我在一个仓储盘点场景里就这么干纸箱这个提示会同时出整箱、箱盖、箱上标签三个候选取第一个就够用了。还有一个工程上的建议把常用提示词做成模板库而不是让业务方自由输入。自由输入听着灵活实际上业务方写不出模型能懂的描述反复试错的时间成本远高于维护一个几十条的模板库。5. 工程落地提示设计、缓存策略与三个真踩过的坑5.1 同一张图多次提问的embedding缓存前面提过缓存这里讲清楚实现层面的三个细节。缓存的粒度是图 预处理参数。同一张图如果这次用 1024 补零、下次用 768 补零特征是不一样的缓存键必须带上分辨率和补齐策略。我最初的版本只用了图片哈希结果换分辨率后拿到旧特征掩码整体偏移排查了半天才发现是缓存串了。缓存的淘汰策略按标注会话来不按 LRU。标注员的工作模式是在一张图上点十几次然后换下一张典型的 LRU 会在换图时把刚用过的图淘汰掉下次回来又得重算。改成会话级缓存一次标注会话内不淘汰会话结束统一释放之后命中率从 60% 提到了 90% 以上。缓存要能失效。图片被替换、模型更新、预处理逻辑改动这三种情况必须让缓存失效。做法是在缓存键里加一个版本号模型或预处理一改就升版本旧缓存自然失效。这个机制看着简单但如果一开始没设计后面清理脏缓存会非常痛苦。5.2 与既有检测链路的分工与结果融合我不建议用统一分割模型替掉检测器正确姿势是分工。检测器负责有没有、在哪、是什么类它的优势是速度快、类别置信度准、对小目标召回高。分割模型负责精确边界接收检测框作为提示输出掩码。这个组合的好处是检测器的框天然解决了分割模型不知道要看哪的问题而且框提示对小目标的分割质量提升明显。融合时有两个技术点要注意。第一框要略微外扩。检测框通常贴得比较紧直接拿来当提示会切掉物体的边缘部分。我的经验是外扩 5%~10%具体比例和物体尺寸有关小物体外扩比例要大一些。第二掩码要裁回框内再做后处理否则掩码可能溢出框外和相邻物体的掩码重叠。还有一个容易被忽略的问题检测器和分割模型的类别体系可能不一致。检测器有 20 类分割模型靠文本提示两者的类别名不完全对应。我的做法是维护一张映射表把检测类别映射到分割模型认识的文本提示映射不上的走物体这种泛化提示宁可粗一点也不要报错。5.3 三个踩坑记录第一个坑以为掩码质量分可以直接当阈值用。早期版本我把置信度 0.8 当过滤线结果自动标注的数据里混进了大量整个画面的掩码。后来才明白模型对大面积简单区域特别自信因为这类样本在训练时损失很小。修正办法是加面积约束和压边检测同时把置信度阈值提到 0.88并且必须配合稳定性检验。这个坑的教训是模型自估的分数反映的是它有多确定不是它有多对两者在分布外样本上会严重背离。第二个坑批量推理时提示数量不一致导致结果错位。一批图里有的图 5 个提示有的 20 个我图省事把提示拼成一个大 batch 送进去再用索引切回来。结果因为补零和排序的关系切回来的掩码和提示对不上标注平台上出现了点左边出右边的诡异现象。排查了两天才定位到是批处理拼接的问题。修正办法是每个样本独立维护提示数量输出时按样本 ID 回填不做跨样本拼接。这个坑的教训是批处理能省时间但省出来的时间很容易在调试上还回去。第三个坑以为换了更强的文本编码器就能解决领域词问题。有个项目里模型对焊点这个词反应很差我第一反应是换更大的文本编码器折腾了一周没效果。后来发现根因是训练数据里焊点这个概念从来没有以文本形式出现过——所有标注都是点提示生成的文本分支根本没被训到。补了一批图 文本 掩码的三元组数据之后同样的编码器效果直接上来了。这个坑的教训是先确认数据里有没有这个信号再考虑换模型顺序反了就是白烧算力。还有个小技巧顺便说同一张图做多次不同提示的请求时把提示合并成一次前向。解码器很轻合并后耗时几乎不增加但省掉了多次调用的框架开销。我在一个批量标注任务里把 8 个提示合并总耗时从 8×10ms 降到 15ms提升非常明显。我在实际项目里最大的体会是这套多模态分割系统的价值不在于一个模型干所有事这种叙事而在于它把分割从训练一个专用模型变成了设计一组提示。专用模型的门槛在数据和训练提示工程的门槛在理解业务——后者的迭代速度快一个量级。真正难的部分从来不是那两层解码器怎么写而是你怎么把业务里的模糊需求翻译成模型能接住的提示以及你怎么设计一条能持续产出干净数据、持续发现模型盲区的回流链路。这两件事做扎实了哪怕换个结构、换套权重整套系统照样能跑做不扎实模型再新也只是个好看的 demo。
阅读完成 · 觉得有帮助?