YOLO11-C3k2-CTA:细长台风螺旋带旋转框检测实战
把YOLO11用在台风螺旋带识别上最初是我在一次气象影像项目中被逼出来的决定。红外云图里的螺旋带不是人眼找不到而是它太“长条”——一条雨带可以从台风中心外围甩出去几百公里宽度却只有十几个像素。常规目标检测框住飞机、车辆这类物体时很自然框住这种细长云带时要么框太小漏掉中段要么框太大把外围晴空区包进来。我们后来基于YOLO11改出了一套配置在工作日志里称它为YOLO11-C3k2-CTA重点就是解决细长螺旋带的检测问题。在内部测试集上这套模型的漏检率从20%上下压到了9%左右平均角度误差也降了不少。这篇文章想把当时的拆解和踩坑过程完整讲一遍适合正在做遥感目标检测、气象视觉分析、或者被细长目标搞得头疼的同行。1. 螺旋带识别为什么不能用常规的框来思考1.1 一个检测任务两种截然不同的目标形态台风螺旋带是云图里最显眼也最别扭的结构。说显眼是因为它呈现出清晰的围绕台风中心旋转的弧状云带肉眼可以一眼认出来。说别扭是因为它本质上是一条曲线条带长度可能覆盖几百公里宽度在卫星云图上看常常只有几十个像素。常规目标检测的预设是“用水平边界框围住一个物体”这种表述对螺旋带并不友好。如果我们坚持用水平框去标注一条完整的螺旋带会出现两个问题。第一框的面积被拉得很大但真实目标只占框内的一小部分导致正负样本比例失衡训练出的模型容易被晴空区、卷云干扰。第二螺旋带存在分支、断裂、重叠一条带往往不是连续均匀的弧单框无法表达“从哪里开始、到哪里结束、走向角度是多少”这些对气象分析真正有价值的信息。1.2 把识别拆成“片段检测 角度预测 曲线聚合”我们后来把问题重新定义了一遍。不直接去“框住整条螺旋带”而是把螺旋带切成若干片段每个片段用一个带角度参数的旋转矩形框表示模型输出的不是普通目标框的4个参数而是中心坐标(x, y)、宽度w、长度l、朝向角θ。这样原本细长的曲线目标被分解成一系列短而规则的小目标检测难度从“大而空”变成了“小而准”。在这个思路下模型的输出头需要在YOLO11原有检测头外面增加一个角度分支。角度预测的好处不只是让框贴合螺旋带走向更重要的是后续可以做聚合把多个检测片段按角度连续性串成整条带甚至用对数螺线方程拟合出螺旋带的空间轨迹。这套“片段—角度—聚合”的流程比直接回归整体掩膜容易训练得多也更容易在工程上落地。1.3 从输入到输出的完整数据流我们的YOLO11-C3k2-CTA模型结构上可以拆成四段。输入层接收多通道卫星产品切片通常是红外亮温、水汽、可见光反射率组合成的三通道伪彩图主干网络采用YOLO11的backbone其中在部分Stage位置使用C3k2模块做特征提取Neck部分在特征融合后接CTA模块也就是本文标题里最核心的部分检测头则在YOLO11解耦头的基础上加入角度输出用于旋转框回归。整个流程走下来输入一张1024×1024的云图切片输出是若干个带角度的螺旋带片段。用这个思路跑通之后我才真正意识到C3k2这种基础模块和CTA注意力机制的组合对细长目标的收益并不体现在“定位更准”这一个点上而是让特征图更干净让模型不会花力气去响应那些非螺旋结构的云系。2. C3k2基座YOLO11里最容易吃到红利的地方2.1 从C3到C3k2参数变少但梯度流更顺YOLO11里的C3k2不是一个新概念它是从CSPNet那套思路延续下来的基础模块。名字里的C3指的是三段式结构k2在我们实际使用中理解为内部两次卷积修正的配置。它在设计上的核心动作是把输入特征在通道维上split成两个分支一个分支走直连残差路径另一个分支经过两层卷积和一个C3k小模块的计算最后把两个分支拼接起来再通过一个卷积做通道融合。这个结构和早期C3相比最大的变化是“算得更少、连接更多”。C3k2每个分支的内部结构更轻量而split机制相当于给梯度开了一条高速公路。在训练螺旋带模型时我们对中间梯度做过一次诊断发现如果不使用C3k2深层特征里细小条带的信息在反向传播时衰减得很快换成C3k2之后P3层对云带边缘纹理的响应明显更活跃。对细长目标来说边缘纹理梯度是否保得住直接决定了后续能不能把边界分开。2.2 主干阶段的选择P3/P4对小目标的权重分配YOLO11的主干里分多个Stage我们重点关注P3和P4两个尺度。P3特征图分辨率高、感受野小适合捕捉螺旋带的局部纹理和边缘细节P4特征图分辨率中等能够表达云带的走向和连续性。在实际配置中我们没有对所有Stage都使用C3k2而是把C3k2集中在Stage3和Stage4。理由也很简单浅层Stage主要保留高频细节过多模块会干扰原始云图信息深层Stage如果模块太重又容易丢失小目标的局部响应。C3k2放在中层等于在细节和语义之间做一个均衡让模型既看得到“条带边缘在哪”也判断得出“这段云带属于螺旋结构还是普通云系”。2.3 我们在C3k2上做的两个小改动第一个改动是控制C3k2分支内的中间通道宽度。YOLO11原始配置在某些阶段会把分支通道扩得比较宽但台风螺旋带数据量有限通道过宽容易过拟合。我们把分支宽度缩到原配置的0.75倍在内部测试集上mAP反而涨了约0.8个点。第二个改动是在C3k2的shortcut连接处加了一个轻量的通道缩放层。这个思路类似SE模块的简化版只做全局平均池化和一个1×1卷积计算量可以忽略但能让模型在多个C3k2串联时自动调节不同通道的增益。改完之后模型对低对比度云带的响应更稳不会因为某些通道的响应太弱导致整段云带被忽略。3. CTA模块的机制拆解通道、目标、注意力如何协同3.1 C分支通道上下文统计与云顶亮温的强相关CTA中的C在我们项目里指Channel-context。卫星云图的通道不是普通照片的RGB那么简单。红外亮温通道中云顶越低亮温越高亮温值反映的是云顶高度和厚度水汽通道则反映高空水汽分布。这些通道之间高度耦合不能只看单独一个通道。CTA模块的C分支做的事情是计算每个通道的全局上下文生成通道权重。具体实现并不复杂先对特征图做全局平均池化得到C维向量再用两层1×1卷积做压缩和激发最后用sigmoid输出0到1的权重。它的效果等于告诉模型“在当前的切片里红外亮温通道的响应比水汽通道更有区分力”。在实践中这个分支确实会一边倒地放大亮温通道的贡献因为螺旋带在对流强的位置上亮温梯度最明显。3.2 T分支如何让模型知道“螺旋带应该长什么样”T分支全称是Target prior branch在CTA里是最值得讲清楚的一部分。日常用的注意力机制里SE关注通道CBAM关注空间位置但它们都不知道“目标长什么样”。对于螺旋带目标最大的特征是“细长、弧状、存在连续走向”。如果只靠数据去学这个特征需要大量标注台风样本本身有限标注成本又高不划算。所以我们在训练阶段增加了一个辅助的弱监督分支。它的做法是把标注框转换成一个粗糙的二维目标先验掩膜掩膜的中心点处响应最强并向四周衰减同时在角度方向上做拉长。这个先验掩膜被用来监督T分支的输出。T分支在推理时不需要额外计算只输出一个空间权重图它的作用等效于在特征被送入检测头之前告诉后续层“云带中心方向要多看一点”。这个设计的本质是用先验约束替代部分数据驱动。我们做的实验显示去掉T分支之后模型对螺旋带断裂处的漏检率明显上升因为模型倾向于把断裂处当成两个独立目标而不是一条连续带的中断。3.3 A分支空间注意力与多尺度融合的摆放位置A分支是CTA里的Attention融合部分。我们把它放在Neck的跨尺度连接之后也就是PAN结构在自上而下和自下而上两条路径汇合的位置。多尺度融合的常见问题是高层特征语义强但分辨率低低层特征细节多但噪声也多。螺旋带在P5层可能已经糊成一片在P3层又会因为云图噪声出现大量碎片。A分支做的事情是同时对空间维度和通道维度做一次调制然后对融合后的特征再做一次残差加权。简单说它决定“这次融合应该更相信高层的方向性还是低层的边缘细节”。值得强调的是我们没有把CTA塞进每一个融合位置那样计算量会翻倍。只用了两个CTA模块一个在P4融合输出后一个在最终检测特征之前。靠这两个模块已经能覆盖螺旋带在不同尺度下的特征表达。3.4 CTA模块的伪代码与参数量分析用Pytorch风格的伪代码描述我们最终使用的CTA模块大致是这样class CTA(nn.Module): def __init__(self, in_channels, out_channels, ratio8): super(CTA, self).__init__() # C分支通道上下文 self.channel_pool nn.AdaptiveAvgPool2d(1) self.channel_fc nn.Sequential( nn.Conv2d(in_channels, in_channels // ratio, 1), nn.ReLU(inplaceTrue), nn.Conv2d(in_channels // ratio, in_channels, 1), nn.Sigmoid() ) # T分支目标先验空间权重 self.target_conv nn.Sequential( nn.Conv2d(in_channels, in_channels, kernel_size3, padding1, groupsin_channels), nn.Conv2d(in_channels, in_channels, 1), nn.Sigmoid() ) # A分支融合压缩 self.fuse nn.Sequential( nn.Conv2d(in_channels, out_channels // 2, 1), nn.ReLU(inplaceTrue), nn.Conv2d(out_channels // 2, out_channels, 1), nn.Sigmoid() ) self.shortcut nn.Conv2d(in_channels, out_channels, 1) def forward(self, x): b, c, h, w x.shape ch_weight self.channel_fc(self.channel_pool(x)) target_weight self.target_conv(x) weighted ch_weight * target_weight * x attn self.fuse(weighted) return self.shortcut(x) * attn self.shortcut(x)这段代码并没有追求结构上的花哨核心就是让不同来源的权重互相调制后再叠加残差。参数量方面以512通道输入、512输出为例CTA模块的额外参数大约在几十万量级相比整个模型动辄上千万的参数量占比很小。我们用一份消融实验验证过加入CTA之后模型推理耗时只增加了6%左右但mAP提升了2到3个点这笔账很划算。4. 数据、标注与预处理螺旋带检测的坑大多在这里4.1 卫星载荷通道组合不是所有云图都适合直接送进模型台风螺旋带识别绕不开卫星云图但不同载荷通道对模型的影响差别很大。我们一开始试过直接把单通道红外亮温图复制成三通道送进模型效果很差因为伪彩色没有任何信息增益模型只能靠边缘纹理去猜。后来把输入改成三通道组合红外亮温通道、水汽通道、以及红外与窗区通道计算的温差产品。这种组合在视觉上类似伪彩图模型可以同时看到云顶高度、高空湿度梯度和云层厚度差异对螺旋带边界的判别明显变好。实际效果上仅这一步调整就让各项指标提升了约1个百分点。如果手头没有多通道数据至少也应该用线性拉伸后的红外单通道加上梯度图作为双通道输入。梯度图可以看作对“边缘纹理”的显式提示对细长结构尤其有用。我们在台风环流较弱、亮温对比度低的条件下测试梯度通道能让断裂处的漏检率下降不少。4.2 标注协议片段长度、重叠区与类别定义螺旋带的标注是整个项目里最需要较劲的环节。一开始我们让标注人员直接画整条螺旋带的外接矩形结果发现不同标注人员对“这条带算不算一条连续带”的判断完全不同模型训练出来之后一会儿激进一会儿保守。最终确定的标注协议是把螺旋带切成片段每个片段的长度控制在120到200像素相邻片段之间保留约20像素的重叠。片段框用旋转框表示标注参数包括中心坐标、宽度、长度、角度和类别。类别分为两类内雨带靠近台风眼壁、对流强、亮温低外雨带距离中心远、结构松散、容易断裂。这个协议同时解决了三个问题。频繁断裂导致的不连续被片段化建模吸收角度标注为后续聚合提供了回归目标重叠区保证了拼接时不出现大段空洞。训练结束后我们还专门做了一个标注一致性抽检把部分切片丢给两个不同标注人员重新标注计算框的位置差异结果显示一致性能达到可接受范围。4.3 遥感切片的拼接策略与困难样本挖掘卫星云图是整张全球或者大区域图不能直接送进模型。我们的做法是采用等经纬度网格先切块切片大小定为1024×1024相邻切片之间保留12.5%的重叠。这样做的好处是处于切片边缘的螺旋带片段不会被一刀切掉在推理阶段可以通过重叠区域去重。困难样本挖掘也是训练效果提升的关键一环。最容易让模型误检的是高空卷云它同样呈细长纤维状视觉上跟螺旋带很像还有台风外围的松散积云线虽然弯曲但并不是围绕台风中心的螺旋结构。我们把这两类样本作为hard negative显式加入训练集不开采样比例的难度提升。实验数据显示只做这一步误检率就下降了三成左右。数据方面还有一个容易被忽视的点纯晴空样本不能太少。我们按照台风环境背景、干净晴空、普通中纬度云系三类比例搭配训练集让模型见过不同场景的底色避免它把所有弯曲结构都当成螺旋带。5. 训练配置与损失函数旋转框输出头要额外管什么5.1 超参数与多尺度训练策略模型训练的配置我们做了很多轮最终稳定下来的参数是输入尺寸1024×1024多尺度范围为768到1280每10个epoch随机切换一次训练尺寸batch size根据显存调整单卡16优化器使用SGDmomentum0.937weight_decay5e-4初始学习率0.01余弦退火降到1e-4前3轮采用warmup。这里有一个容易踩的坑台风螺旋带的标注框长宽比跨度很大最窄的片段宽度只有十几个像素最长的能到250像素。如果多尺度范围设置太小模型在不同尺度下的长宽比分布差异会被抹平我们试过只做640和1024两档结果小尺寸下训练出的模型对长链线段不敏感漏检率反复横跳。建议多尺度档位至少3档并且每档都要保持切片内容完整。EMA指数移动平均我们也建议一定要开。滑动平均衰减系数设成0.9997虽然让训练过程看起来收敛得慢一点但最终模型的泛化能力比直接保存最好checkpoint要好。我们在最后一个阶段对EMA模型和非EMA模型做了对比mAP相差接近1个点。5.2 损失函数分类、框回归之外的“角度回归”YOLO11的检测头本身带分类和回归两个分支我们的模型在回归分支上扩展出了角度输出。分类损失用标准的BCE框的中心点和宽高回归仍然用CIoU但角度部分的损失函数需要单独设计。角度预测不能直接用L1损失或者MSE损失。原因在于角度是循环量0度和360度其实一样177度和-177度虽然数值上差354实际只差3度。直接算L1的话模型会在角度接近0度和360度边界处反复震荡。我们采用的方案是周期角度损失Loss_angle 1 - cos(θ_pred - θ_gt)。这个损失函数既平滑又保持周期性在角度靠近边界时不会出现跳变。如果使用旋转框还要注意角度定义的一致性问题。同一个旋转矩形框可以表示为90度和-90度如果不强制统一角度的值域模型输出会不稳定。我们的做法是把角度输出范围限制在0到180度之间同时把宽高顺序归一为“长边在前”。这样角度的歧义被消掉了模型不需要花额外能力去处理“同一个框的两种表示”。5.3 正负样本匹配与辅助分割损失螺旋带的视觉特征和普通目标很不一样云带中心区域往往是亮温梯度最大的位置而不是云带中心的亮温最低点。所以我们在正负样本匹配时没有完全依赖传统anchor匹配而是额外利用了T分支的目标先验掩膜在特征图对应位置上只有目标先验掩膜响应大于阈值的区域才被评为正样本候选再结合IoU做筛选。还有一个细节CTA模块的T分支有一个辅助损失。我们在训练阶段加了一个轻量的分割头监督目标先验掩膜的预测分割损失用Dice损失。这个辅助头在训练结束后直接丢弃不参与推理因此不会增加部署负担。它存在的意义是让T分支学到“螺旋带应该在哪里”而不是单纯靠梯度回传形成模糊的空间权重。整体损失函数可以概括为L_total L_class L_ciou L_angle λ * L_dice。λ取0.5权重不算高但要保证T分支能学到有效先验。我们试过把λ提到1.0发现检测精度变化不大但训练波动明显加大所以最终保持在0.5。6. 消融实验与结果对比mAP提高多少才算真正有效6.1 指标口径为什么不能只看mAP模型效果评估是最容易自欺欺人的环节。台风螺旋带检测的典型场景要求是宁可多报一次也不能漏掉一段。因为漏检的螺旋带段在气象分析里意味着可能漏看了强对流区域而过检的片段至少能由人工二次筛查。所以除了mAP我们还统计两个指标漏检率即GT框没有被任何预测框匹配上的比例平均角度误差只统计成功匹配的预测框与GT之间的角度差绝对值。这三个指标放在一起比单独看mAP更能说明模型是否适合落地。清晰地区分评估口径之后模型改进的方向也会更明确不会为了涨零点几个mAP去做对实际任务无益的调整。6.2 与YOLO11基线的对比内部验证集上我们维护了一套固定的评估切片不参与训练且覆盖不同强度台风过程。这里给出三种配置的对比结果模型mAP0.50mAP0.50:0.95漏检率平均角度误差YOLO11n基线水平框0.8230.5119.8%——YOLO11n 旋转框0.8480.5414.2%3.9°YOLO11-C3k2-CTA完整版0.8720.588.7%2.5°需要说明这个表格只是我们内部测试集上的相对口径不同机构的数据分布差别很大绝对值不具备横向可比性。但从趋势上能看出旋转框本身就能带来收益因为框贴合目标后正样本特征更集中了而CTA模块叠加C3k2之后漏检率下降最明显说明注意力机制确实在处理断裂、模糊云带时更有效。6.3 可视化分析与误检来源把预测结果叠加回原图看最顽固的误检有两类。一类是高空卷云在红外通道上呈纤维状结构被模型误认为螺旋带另一类是台风外围的干侵入区域云系破碎但呈现出弧状排列模型容易把多个云团连接成一条虚假的带。针对第一类误检我们在训练集里增加了卷云样本效果明显针对第二类单靠模型很难根除需要在后处理阶段增加角度连续性校验。我们写了一个后处理逻辑如果一串预测片段的角度跳跃超过30度且片段间距大于阈值就判定不是一条连续的螺旋带以低置信度候选保留。这套规则做进去之后误检率又降了几个百分点。7. 部署阶段的取舍与后续可以从哪里接着优化7.1 推理链路设计从整景云图到结构化输出模型训完不算完真正上线还要处理整景云图的拼接和输出。我们的推理链路分成五步读取卫星通道产品按等经纬度网格切块并做重叠每块送入YOLO11-C3k2-CTA推理对同一位置的重叠预测做加权NMS最后把保留的片段按角度和中心点做对数螺线聚合。对数螺线聚合这一步是我们后来补上的。螺旋带在物理上接近对数螺线形状我们可以用片段中心点和角度作为观测值拟合出一条二维螺线方程输出参数包括螺线中心位置、增长系数和覆盖角范围。这样气象分析人员拿到的不是几百个零散片段框而是一条带编号的螺旋带结构可直接用来做台风中心定位辅助或强度估计。7.2 推理加速和量化经验部署时我们用了一块常规服务器显卡做性能测试。一开始直接在原始精度下推理切片数量大时无法达到实时性要求。后来采用了半精度推理速度提升了接近1.8倍精度基本无损。再进一步做8bit量化时mAP下降约0.4个点但速度更快如果业务场景是对历史台风数据做批量重分析这个速度很有价值。值得提醒的是量化时最容易出问题的是角度分支。角度损失我们用余弦形式表达但量化后的模型输出角度会在0度和180度边界出现微小抖动导致聚合时出现角度不连续。解决办法是在聚合算法里加一个边界处理逻辑角度超过170度就映射到负角域再进行平滑。这个坑排查了很久写出来供大家参考。7.3 下一步可做但还没做的事CTA模块目前使用的是人工设计的先验掩膜下一步可以考虑把先验掩膜换成可学习的形态参数让模型自己决定螺旋带片段的长度和宽度分布。数据层面台风样本难获得我们正在尝试半监督方案用已经训好的模型去伪标注未编号的台风历史云图再经过人工抽检后加入训练集。虽然伪标注会带来噪声但数据量的增长可能会抵消这部分负面影响。最后说点实在的如果让我给后来者一句建议那就是先别急着把模型做复杂先把你标注的“螺旋带”定义清楚。我们踩过最大的坑不是模型不够强而是标注人员对同一段雨带到底算不算“螺旋带”的判定都不一样。后来我们定了三类标准把片段长度、连续性和走向规则写进标注手册模型性能才真正稳定下来。模型结构上的东西YOLO11、C3k2、CTA很多团队可以复现但标注口径和对任务的拆解方式才是决定这个模型能不能在业务里跑出效果的分水岭。