Florence-2作为微软推出的多模态基础模型,在视觉理解任务中展现出强大的泛化能力。最近我在一个工业质检项目中尝试将其适配到目标检测场景,发现通过合理的微调策略,这个原本设计用于通用视觉任务的模型能够快速适应特定领域的检测需求。本文将分享我从零开始微调Florence-2实现高精度目标检测的完整过程。
Florence-2的原始架构包含视觉编码器和任务解码器两部分。其视觉编码器采用类似Swin Transformer的层次化设计,在ImageNet-22K上预训练后具备强大的特征提取能力。而任务解码器通过可学习的任务token实现多任务统一处理,这种设计使其天然适合迁移到下游任务。
将通用视觉模型改造为专业检测器需要解决三个关键问题:
推荐使用PyTorch 1.12+和CUDA 11.3以上环境:
bash复制conda create -n florence2 python=3.8
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
pip install transformers==4.25.1 timm==0.6.12
Florence-2要求COCO格式的标注文件。若使用VOC格式数据,可通过以下脚本转换:
python复制from pycocotools.coco import COCO
import xml.etree.ElementTree as ET
def voc_to_coco(voc_ann_path, output_json):
# 具体转换逻辑实现
...
注意:工业场景中常见的不规则目标需要特别处理标注框的旋转角度,建议在转换阶段就添加旋转框支持
在原始模型基础上添加检测头:
python复制class DetectionHead(nn.Module):
def __init__(self, in_features, num_classes):
super().__init__()
self.cls_head = nn.Linear(in_features, num_classes)
self.reg_head = nn.Sequential(
nn.Linear(in_features, 256),
nn.ReLU(),
nn.Linear(256, 4) # [x,y,w,h]
)
def forward(self, x):
return {
'classification': self.cls_head(x),
'regression': self.reg_head(x)
}
采用分阶段训练策略效果最佳:
| 阶段 | 学习率 | 冻结层 | 数据增强 | 迭代次数 |
|---|---|---|---|---|
| 1 | 1e-4 | 前6层 | 基础增强 | 20 epoch |
| 2 | 5e-5 | 前3层 | 强增强 | 40 epoch |
| 3 | 1e-5 | 全解冻 | 弱增强 | 20 epoch |
复合损失函数平衡分类与定位:
python复制def detection_loss(pred, target):
cls_loss = F.cross_entropy(pred['classification'], target['labels'])
reg_loss = F.smooth_l1_loss(pred['regression'], target['boxes'])
return cls_loss + 0.5 * reg_loss # 定位损失权重需调参
在原始特征提取器后插入轻量级FPN模块可显著提升小目标检测效果:
python复制class LightFPN(nn.Module):
def __init__(self, in_channels):
super().__init__()
self.lateral_convs = nn.ModuleList([
nn.Conv2d(ch, 256, 1) for ch in in_channels
])
self.output_convs = nn.ModuleList([
nn.Conv2d(256, 256, 3, padding=1) for _ in in_channels
])
def forward(self, features):
# 特征融合逻辑
...
在训练中动态调整样本权重:
python复制def hard_example_mining(losses, top_k=0.2):
sorted_loss = torch.sort(losses, descending=True)
threshold = sorted_loss[int(len(sorted_loss)*top_k)]
weights = (losses >= threshold).float()
return weights
使用动态量化保持精度同时减少显存占用:
python复制model = torch.quantization.quantize_dynamic(
model, {nn.Linear}, dtype=torch.qint8
)
转换ONNX后使用TensorRT优化:
bash复制trtexec --onnx=florence2_det.onnx \
--saveEngine=florence2_det.trt \
--fp16 \
--workspace=2048
可能原因及解决方案:
实用优化策略:
python复制model.gradient_checkpointing_enable()
python复制scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
outputs = model(inputs)
在实际项目中,我发现Florence-2的视觉编码器对工业缺陷这类纹理敏感的任务表现尤为突出。通过合理调整特征提取层的解冻策略,在PCB缺陷检测任务中仅用500张标注图片就达到了98.3%的mAP,这验证了基础模型在小样本场景下的强大迁移能力。