资讯动态

大语言模型编码增强建筑语义分割的实践与思考

发布时间:2026/10/20 7:18:08 来源:尧图企业网站定制
最近我在做一个建筑实景分割项目时被一个看似很基础的问题卡了两周模型在验证集上mIoU能到0.71但一旦换到新区块预测结果里外墙幕墙遮阳板就开始来回打架错得非常有规律。后来回溯训练管线发现病灶挺讽刺——我们在数据预处理时把这些建筑语义类别都换成了纯数字ID喂给模型的就是0、1、2、3……模型确实能背下来训练集里的像素分布但对墙为什么是墙、梁和柱的区别到底是什么一窍不通。正好那段时间大语言模型编码LLM Encodings在非文本领域很火我就试着把这类语义先验以文本嵌入的方式绕进分割网络训练流程折腾了大概一个月效果确实超出预期。这篇文章就是那段时间的完整复盘。核心围绕一个方向如何用大语言模型编码去增强AI模型训练中的建筑语义保留让模型在类别极细、样本极不均衡、标注口径又很乱的建筑数据上记住语义而不是ID。适合正在做建筑语义分割、点云分类、BIM构件识别或者任何有细粒度类别需求的朋友参考我会把选型思路、实施路径、踩坑记录和消融结果都摊开讲。1. 建筑语义数据集的两个经典痛点One-Hot编码为什么打不穿1.1 类别粒度极细样本分布几乎永远是畸形的建筑数据集的类别表恐怕是所有行业数据集里最劝退的之一。拿一个旧城区改造扫描项目来说仅立面构件就拆出了17个类别包括普通外墙、涂料外墙、陶板幕墙、玻璃幕墙、金属格栅、遮阳百叶、女儿墙、檐口线条等。其中普通外墙占了全部标注面积的42%而檐口线条落水管这类细长构件占比合计不到0.5%。这种分布下标准做法是给每个类别一个One-Hot编码配合交叉熵损失和类别权重。试过的朋友应该都有体会类别权重一调低频类别的预测是变多了但经常是过量把玻璃幕墙大面积误检成玻璃栏板因为这两个类别的像素外观实在太接近。本质原因是One-Hot编码的向量之间距离全等模型眼里类别ID和类别ID之间没有任何先验关系只能靠视觉特征硬拗低频类又没有足够的样本撑起稳定的视觉模板于是相近类别的决策边界就成了摇晃的钢丝。我用一个小的语义相似度工具算过这17个类别的视觉混淆率排在前五的混淆对基本全是结构位置不同、材质外观相近的组合。这种错误模式本身就在提示光靠视觉通路信息不够。1.2 标注口径混乱同一构件在不同项目中叫法完全不一样更头疼的是建筑语料本身就缺乏统一同义词表。同样是填充墙在有些项目里标注为内隔墙在另一些项目里叫非承重墙同样是阳台有的图纸系统叫露台有的叫悬挑板。这种标注口径差异在普通视觉任务里只是噪声但在细粒度语义任务里是灾难。因为模型学习的是类别ID到视觉特征的映射如果同一个物理实体在训练集和测试集里被赋予不同的ID模型等于在背两套词典。而且这类问题几乎不可能在标注阶段靠短期的对齐培训解决毕竟很多数据来自历史项目归档标注的人换了一茬又一茬。当时我产生了一个很直觉的想法模型不需要记住ID7的像素长什么样它需要理解ID7对应的是建筑中的某种墙墙和柱的根本区别在于承重方向与几何比例。这种语义信息在纯图像通路上几乎无法被直接监督但在语言模型生成的文本描述里却是现成的。这就成了我整个方案的地基。2. 把大语言模型编码接进训练流程我对比过的三种接入方法先说整体思路利用预训练大语言模型的文本编码器把每个建筑类别对应的名称、属性、关系描述编码成稠密向量再让分割网络在训练时感知这些向量。大模型编码在这里扮演的是语义翻译官把建筑领域里那些看不见的规则翻译成网络可以用的梯度信号。我实验了三种差异很大的接入方式各有适用边界下面按我实测的顺序展开。2.1 方法一类别文本嵌入直连——把语义向量拼进特征通道最朴素的方案用文本编码器为每个类别生成一个固定向量然后像语义标签一样把类别语义向量作为额外通道拼在解码器输入或者分类头之前。以常见的分割网络为例网络把图像编码成特征图B, C, H, W分类头输入是每个像素的C维特征。我的做法是把类别语义矩阵做成可被像素索引的查找表每个像素不是拿一个纯数字ID去查输出权重而是让ID去查一个V, D的语义矩阵V为类别数D为文本嵌入维度查出来的D维向量和图像特征C维拼接再进分类器。import torch import torch.nn as nn from transformers import AutoModel, AutoTokenizer class SemanticallyAwareHead(nn.Module): def __init__(self, feat_dim, num_classes, text_embed_dim384, hidden_dim256): super().__init__() # 这里选用的是通用文本编码器冻结参数 self.text_encoder AutoModel.from_pretrained(some-open-text-encoder) for p in self.text_encoder.parameters(): p.requires_grad False self.embed_dim text_embed_dim self.classifier nn.Sequential( nn.Conv2d(feat_dim text_embed_dim, hidden_dim, 1), nn.ReLU(inplaceTrue), nn.Conv2d(hidden_dim, num_classes, 1), ) def get_class_embeddings(self, class_texts): # class_texts: list of strings, 如 [外墙, 承重墙, 窗] tokens self.tokenizer(class_texts, paddingTrue, return_tensorspt).to(next(self.parameters()).device) with torch.no_grad(): embeds self.text_encoder(**tokens).last_hidden_state[:, 0, :] return embeds.detach() # V, D def forward(self, feat, class_embed_lookup, class_ids): # 像素级查找用分割标签的one-hot乘查找表得到像素级语义向量 # 这里简化为只取当前batch用到的类别 B, C, H, W feat.shape sem_feat class_embed_lookup[class_ids].permute(0, 3, 1, 2) # B,D,H,W fused torch.cat([feat, sem_feat], dim1) return self.classifier(fused)这个方案的优点是完全不改变原有网络骨架推理时可以提前算好类别嵌入矩阵额外开销只有一个拼接和一层1x1卷积。缺点是语义信号只是作为额外先验输入网络可以选择忽略它——如果视觉特征已经足够拟合训练集模型不会主动去利用语义向量。我实测下来在小数据集上提升明显但数据集一扩大就不够看了。2.2 方法二文本-视觉对比对齐——用互信息逼两者靠近第二个方案借鉴了跨模态对比学习的思路不直接改变分类头而是在训练时增加一个辅助目标同一类别的图像特征应该与其文本编码靠近不同类别则推开。具体来说分割网络的主干特征图经过全局平均池化后得到每张图的全局特征同一batch内所有类别对应的文本编码经过线性投影后构造对比损失。这里关键的是该把什么和什么对齐。直接对整图全局池化特征做对齐太粗因为一张街景图里包含十几个类别。我后来改成用掩码池化——把分割标签当作mask对每个类别区域内的特征做平均池化把这块区域的特征向量与对应类别的文本向量拉近。这个方案本质上是给网络加了一个跨模态正则化梯度不仅来自像素分类还来自视觉特征和语言特征得保持一致。实测下来它比方法一稳得多尤其是缓解相近类别混淆上效果很明显但训练时间增加了约15%而且对掩码池化操作要额外小心处理小目标区域否则池化出来的特征噪声极大。2.3 方法三知识蒸馏——让大模型当老师但不是对logits蒸馏第三种是我觉得最有意思、也是最终方案里采用的一种。一般的知识蒸馏是大网络教小网络但这里我蒸馏的不是预测结果而是语义命名能力。具体做法分两步。先把建筑类别名以及由大语言模型生成的属性描述句比如承重墙主要承受上部结构传递的竖向荷载的墙体通常厚度较大与梁柱刚性连接同时喂给文本编码器得到语义候选向量。然后在网络的每个解码器阶段额外训练一个小型投影头去预测当前像素最可能对应哪一条语义描述向量。相当于网络不只是学一个离散分类还在学一个连续语义空间中的定位。这个方案的收益是最全面的因为它在网络多个尺度上都施加了语义监督浅层特征被逼着区分墙体和非墙体这种上位语义深层特征再细化到具体是哪一种墙。缺点是训练复杂度高需要维护语义候选向量集并且要对每个batch在线计算相似度。三种方式的对比我整理成了表方便直接选型接入方式额外训练开销分类头改动语义利用深度适用场景我的实测结论类别文本嵌入直连低小拼特征浅小数据快速试点提升有限模型容易忽略语义信号文本-视觉对比对齐中无中有一定数据量的常规训练类别混淆明显缓解训练时间15%语义描述蒸馏较高需加投影头深细粒度、长尾场景为主效果最好收敛也更快复杂度可接受最终我选的是方案三为主、方案二做辅助损失。原因很简单建筑语义分割最难的从来不是分类器而是特征的语义组织只动分类头不如直接在特征层面灌语义。3. 实验室设计提示词模板、数据增强与训练参数的坑方案一旦确定80%的精力反而耗在了怎么写提示词怎么配训练参数上。这部分没什么学术文章会写得特别细但实操里每一步都可能让效果翻倍或归零。3.1 提示词模板远比你想象的敏感用大语言模型编码建筑类别第一步是定义每个类别喂给文本编码器的字符串。你可能会觉得直接把类别名丢进去就行——实测效果很差。因为建筑类别名常常是多义词幕墙单独输入时文本编码器注意力被幕这个字分散生成的向量和窗帘幕布靠得更近而不是建筑幕墙。经过多轮调整我沉淀出一套对建筑领域比较可靠的提示词模板{类别名}{核心定义或功能描述}通常出现在{典型位置}{与其他构件的典型关系}以女儿墙为例完整的输入是女儿墙建筑物屋顶周围的矮墙通常沿屋面边缘连续设置主要起防护和建筑立面收口作用下部与屋顶结构层连接注意这里我没有直接让大语言模型生成文本而是自己写了结构化模板。原因是想尽量控制文本编码器所在的语义空间稳定避免大模型自由发挥出风格漂移的描述。每个句子的长度也做了归一化太长的描述会导致注意力分散太短则信息量不足。实测下来最佳长度是5到8个语义单元。3.2 借用大模型做在线同义词增强这是另一个让我意外的增益点。建筑领域的标注往往不统一比如同一个防火墙不同项目里还可能写成防火隔墙防火分隔墙。我在训练时用大语言模型批量生成每个类别的别名和近义描述再和主描述交替输入文本编码器相当于在语义空间里做了数据增强。具体逻辑很朴素网络在不同角度描述下都看到墙的语义向量就能更不容易被标注词汇的差异带偏。我这里提到的大语言模型生成别名并不是在训练时反复调用而是离线一次性生成存入一个JSON文件训练时随机挑选。class_synonyms { 防火墙: [防火墙用于阻止火焰蔓延的分隔墙体, 防火隔墙防火分区边界处设置的墙体], 玻璃幕墙: [玻璃幕墙由玻璃面板与支承结构组成的建筑外墙, 幕墙系统悬挂于主体结构外侧的非承重外墙] }训练迭代时每个batch随机选一个同义项编码并把它作为该类别本次迭代的语义锚点。这个方法对换数据集测试时的泛化效果贡献很大后来消融时去掉它跨区域测试的mIoU掉了将近2个点。3.3 关键训练参数的选取逻辑这些参数组合不是拍脑袋来的每一条背后都有对应的一次失败实验参数项我的最终取值踩过的坑文本编码器冻结是全冻结最初微调了编码器发现训练早期语义向量漂移严重分割头跟着震荡语义辅助损失权重0.3总损失1.0分类0.3语义权重调到0.8时模型开始偏向语义分类像素边界变模糊warmup 步数2000步不加warmup对比损失前500步震荡幅度很大一度以为要发散语义投影头维度256维度太低语义信息被压缩太高则在小数据集上过拟合训练分辨率768×768分辨率太低时女儿墙这类细长构件的掩码池化特征基本是噪声训练时用到的损失函数组合如下供直接参考total_loss ce_loss(pred, label) 0.3 * semantic_contrast_loss(feat, text_embeds, label)语义对比损失的具体实现并不复杂就是常规的InfoNCE变体以类别为粒度把同一batch内同一类别的掩码池化特征互为正样本与所有其他类别文本向量互为负样本。4. 训练过程中我踩过的三个翻车现场和完整排查链路4.1 文本嵌入维度的隐形天花板第一次跑通方案二时我心里预期至少涨两三个点结果mIoU不升反降。当时非常困惑理论推导和实现都没有明显错误网络也正常收敛。后来把分类头断点输出拉出来看发现一个现象拼接后的特征向量中文本嵌入维度占的比例太小信号完全被图像特征淹没。我用的是OpenAI那类通用文本编码器输出维度是1536维而图像特征维度是256维两者拼接后文本占了86%按理说不该被淹没——但问题是文本嵌入本身在BatchNorm层被重新归一化后方差被压到和图像特征同量级语义信息大量丢失。正确的处理方式不是直接拼接而是先对文本嵌入做独立的LayerNorm和线性压缩映射到128维的语义空间再和图像特征拼接。压缩后的语义向量反而保留了更集中的判别信息。这个改动单独带来了约1.8个点的mIoU提升。4.2 辅助损失权重过高模型开始背文本这个问题发生在调参阶段我把语义辅助损失权重从0.3加到了0.8想着语义约束越强越好。结果训练曲线显示分类损失下降正常但验证集mIoU却在30个epoch后掉头向下。把预测结果可视化出来发现一个诡异的模式模型把几乎所有细长的构件都预测为柱因为柱的语义描述文本在语义空间里和竖长的物体距离最近而视觉上很多建筑设备管道也是竖长的。排查到最后问题出在辅助损失和分类损失的优化方向冲突语义对比损失鼓励视觉特征靠近文本向量但当文本向量之间的距离本身小于部分类别之间的视觉距离时强行拉近反而牺牲了像素级的判别边界。这就像让一个学生学习时总是先背标准答案但考试偏偏考变式题背得越熟错得越狠。最终解决方案不复杂把语义辅助损失从固定权重改成阶梯式衰减前10个epoch用0.5让模型快速建立语义锚点之后逐步降到0.1让位于像素分类。这一条单独带来约1.2个点的提升更重要的是彻底解决了背文本问题。4.3 标注语言不一致导致的语义向量离群点这是最有建筑行业特色、也是我最想分享的一个坑。项目数据来源既有中文标注的项目也有英文标注的项目外墙是一类exterior wall是另一类甚至同一个中文项目里早期标注用外墙面后期统一成外墙。如果不处理语义候选矩阵里会出现几乎重复但又不完全重合的向量让对比学习的目标变得自相矛盾。排查链路是这样的先对语义向量做可视化降维投影到二维看到有几个类别的向量和它们最相近的类别向量距离超过正常水平两倍以上再逐一查看对应的原始描述文本发现是窗窗户window三个条目同时存在。处理方式是把跨语言的同义条目统一到单一规范名再在描述文本里同时保留两种语言的别名。这样既避免了向量冗余又保留了跨语言的泛化迁移能力。5. 消融实验与评测语义保留到底值几个点5.1 评测指标mIoU之外加一个混淆敏感度很多建筑语义项目只看mIoU但这个指标对少量类别错得离谱和大量类别轻微错误给出的分数可能一样这会掩盖语义保留的价值。我在mIoU之外额外统计了结构化混淆指数把所有真实类别两两组合统计互相误判的像素占比再按照建筑结构分组墙体系、门窗体系、屋面体系、构件体系看混淆集中在组内还是跨组。如果模型语义结构学得好混淆应该集中在组内比如玻璃幕墙误判为陶板幕墙而墙体不会误判成窗户。5.2 消融结果对比在同一个旧城区立面数据集上我逐步加回各个模块结果如下配置mIoU混淆指数越低越好墙体组内精度构件组内精度基线One-Hot CE0.7130.2680.7810.642 类别文本嵌入直连0.7210.2410.7920.671 文本-视觉对比对齐0.7440.1960.8170.703 语义描述蒸馏0.7620.1630.8340.746完整方案蒸馏对比同义增强0.7830.1210.8650.793从表中可以看到完整方案相比基线mIoU涨了7个点结构化混淆指数从0.268降到0.121幅度非常可观。尤其值得注意的是一开始的猜想被验证了增益最大的场景恰恰是样本占比低于2%的构件类别檐口线条落水管这类之前基本靠猜的类别像素精度涨了近14个点。这说明语义先验对长尾分布的补偿作用比单纯调类别权重要健康得多因为模型不再需要海量样本来脑补这是什么。5.3 从预测结果里看到的实际变化把两个模型在同一组测试图上的结果摆在一起看差别很有意思。基线模型对建筑外立面的整体把握其实已经不差大面积墙体基本正确但女儿墙、勒脚、窗台板这些边界构件经常会融合在墙体里。加了语义编码后的模型在这些细长构件的边缘会给出更明确的分离预测。我推测原因是文本描述里包含了女儿墙位于屋顶边缘顶部收口这类空间关系信息模型在训练时被引导去关注屋顶边缘附近区域的特征而不是把所有平坦立面都当墙。另一个直观变化是跨区域泛化。用旧城区项目训练的模型直接测评新城区一个待标注项目的数据完整方案的mIoU比基线高了9.2个点。新城区项目的墙体构造和标注风格与旧城区有明显差异能有这个提升已经从侧面说明模型学到的不是某一块区域的像素模板而是更接近建筑语义本身的东西。6. 这套方案的边界条件与我在实践中形成的扩展思路6.1 什么情况下不建议硬上这套方案不是所有建筑AI项目都适合引入LLM编码。首先是数据规模如果你的训练集只有几万张图像且类别只有三五个大项比如只有地面、墙、天花板One-Hot编码加一个良好的预训练分割网络完全够用额外语义模块带来的提升可以被忽略还会徒增训练复杂度。其次是类别关系问题这套方案适合的是类别之间有内容关联的细粒度场景比如墙体、柱、梁这类结构件相互独立但视觉相似的类别。如果类别本身就是完全互斥且视觉差异极大的如草地和天空文本编码提供不了额外信息因为视觉已经足够区分。最后是预算约束方案三需要增加投影头、语义候选矩阵和额外的对比损失计算显存占用比基线高出约1.5GB训练时间增加约20%老显卡用户需要提前评估。6.2 与大语言模型交互的工程化建议在跑了几轮实验之后我对怎么和文本编码器打交道有了一些工程上的体会。最重要的一条是构建语义描述的时候一定要做统一格式的模板并且要控制句子长度最长不要超过模型训练时的序列长度上限。更长的文本输入会触发截断导致尾部信息直接丢失而建筑构件描述里最关键的往往就是与其他构件的关系这部分恰好常常位于句子尾部。我的解决方案是把最核心的定义放在描述的第一句属性放在第二句关系与位置放在第三句这样即使截断也只损失次要信息。这条经验在后续做BIM构件识别时同样适用。另外保持文本编码器冻结是一个安全性选择。微调文本编码器理论上可以更好地适配建筑领域但实际训练中梯度会同时更新语言模型和视觉模型两个模型的学习率如果不严格对齐很容易出现语义空间漂移表现为早期验证指标快速上升后骤降。如果你的任务确实需要微调文本编码器建议给它设置一个比主干网络小20倍的学习率并且密切监控语义向量的分布变化。6.3 往BIM知识图谱方向扩展的可能性这个方向目前我已经在尝试进一步延伸。建筑领域的语义不像自然图像那样只是一个名词标签它背后还连着构件关系、材料属性、施工逻辑等结构化信息。大语言模型编码捕捉到的语义还只是语言知识如果能进一步和BIM模型里的属性拓扑结构对接比如让类别语义向量同时包含该构件连接了哪些构件是否承重是否保温层等结构化特征训练出来的模型在语义保留能力上可能会再上一个台阶。走在路上的同行应该都感受到了建筑AI落地难难题很多时候不在模型结构而在模型是否能理解建筑行业的思维方式。大语言模型编码这条路本质上是用一种低成本的方式把行业知识翻译成网络能用的梯度信号。我后续会继续在这个方向做更系统的实验也希望这篇文章能给大家一个可以直接起跑的参考。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑