1. 小目标检测优化概述
小目标检测是计算机视觉领域的一个重要研究方向,主要解决图像中尺寸小于32×32像素的目标识别问题。这类目标由于像素信息少、特征不明显,在常规检测算法中往往表现不佳。在实际应用中,小目标检测技术广泛应用于卫星遥感、医学影像分析、自动驾驶、工业质检等领域。
与常规目标检测相比,小目标检测面临三大核心挑战:
- 特征提取困难:小目标在卷积神经网络中经过多次下采样后,有效特征几乎消失
- 正负样本失衡:图像中小目标区域占比极小,导致模型训练时正负样本比例严重失调
- 定位精度不足:传统检测算法对小目标的边界框回归误差较大
2. 小目标检测核心技术解析
2.1 特征金字塔网络优化
特征金字塔网络(FPN)是小目标检测的基础架构,但标准FPN存在高层特征丢失问题。我们采用以下优化方案:
python复制# 改进的多级特征融合示例
class EnhancedFPN(nn.Module):
def __init__(self, in_channels_list, out_channels):
super().__init__()
self.lateral_convs = nn.ModuleList()
self.fpn_convs = nn.ModuleList()
for in_channels in in_channels_list:
self.lateral_convs.append(
nn.Conv2d(in_channels, out_channels, 1))
self.fpn_convs.append(
nn.Sequential(
nn.Conv2d(out_channels, out_channels, 3, padding=1),
nn.GroupNorm(32, out_channels),
nn.ReLU(inplace=True)
))
# 添加跨层连接
self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
self.merge_conv = nn.Conv2d(out_channels*2, out_channels, 1)
def forward(self, inputs):
# 标准FPN流程
laterals = [conv(x) for conv, x in zip(self.lateral_convs, inputs)]
used_backbone_levels = len(laterals)
# 自顶向下路径
for i in range(used_backbone_levels-1, 0, -1):
laterals[i-1] += F.interpolate(
laterals[i], scale_factor=2, mode='nearest')
# 增强特征融合
outs = []
for i in range(used_backbone_levels):
if i < used_backbone_levels-1:
# 融合相邻层特征
next_level = self.upsample(laterals[i+1])
merged = torch.cat([laterals[i], next_level], dim=1)
outs.append(self.merge_conv(merged))
else:
outs.append(self.fpn_convs[i](laterals[i]))
return outs
关键改进点:
- 引入跨层特征拼接(cat操作)而非简单相加
- 使用组归一化(GN)替代批归一化(BN),解决小batch size问题
- 添加1×1卷积进行特征通道压缩
注意:特征融合时建议保持空间分辨率一致,上采样推荐使用最近邻插值而非双线性插值,避免引入虚假高频信息。
2.2 注意力机制增强
针对小目标特征容易被背景淹没的问题,我们设计了一种混合注意力模块:
python复制class HybridAttention(nn.Module):
def __init__(self, in_channels, reduction=16):
super().__init__()
self.channel_attention = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_channels, in_channels//reduction, 1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels//reduction, in_channels, 1),
nn.Sigmoid()
)
self.spatial_attention = nn.Sequential(
nn.Conv2d(in_channels, 1, 1),
nn.Sigmoid()
)
def forward(self, x):
ca = self.channel_attention(x)
sa = self.spatial_attention(x)
return x * ca * (1 + sa) # 增强重要区域
该模块同时考虑通道和空间维度的重要性:
- 通道注意力筛选关键特征通道
- 空间注意力聚焦目标可能出现区域
- 最终采用乘积加权而非简单相加,增强重要区域响应
3. 数据层面优化策略
3.1 多尺度训练策略
我们采用渐进式多尺度训练方案:
| 训练阶段 | 输入尺寸 | 批次大小 | 学习率 | 数据增强 |
|---|---|---|---|---|
| 阶段1 | 512×512 | 32 | 0.01 | 基础增强 |
| 阶段2 | 768×768 | 16 | 0.005 | 增加mosaic |
| 阶段3 | 1024×1024 | 8 | 0.002 | 完整增强 |
实施要点:
- 每阶段训练epoch数=总epoch×30%
- 使用warmup策略避免初期震荡
- 最后阶段冻结骨干网络只训练检测头
3.2 小目标专用数据增强
除常规翻转、旋转外,特别设计以下增强方法:
-
小目标复制粘贴:
- 从其他图像随机选取小目标
- 按以下规则粘贴到当前图像:
python复制def paste_small_objects(img, targets, max_paste=10): h, w = img.shape[:2] for _ in range(random.randint(1, max_paste)): src_img, src_target = random.choice(dataset) obj_idx = random.choice(range(len(src_target))) x1,y1,x2,y2 = src_target[obj_idx]['bbox'] obj = src_img[y1:y2, x1:x2] # 随机位置粘贴(确保不超出边界) new_x = random.randint(0, w - (x2-x1)) new_y = random.randint(0, h - (y2-y1)) img[new_y:new_y+(y2-y1), new_x:new_x+(x2-x1)] = obj # 更新标注 targets.append({ 'bbox': [new_x, new_y, new_x+(x2-x1), new_y+(y2-y1)], 'cls': src_target[obj_idx]['cls'] }) return img, targets
-
背景纹理混合:
python复制def blend_background(img, alpha=0.1): bg = random.choice(backgrounds) bg = cv2.resize(bg, (img.shape[1], img.shape[0])) return cv2.addWeighted(img, 1-alpha, bg, alpha, 0)
4. 损失函数优化
4.1 改进的Focal Loss
针对小目标正样本稀少问题,我们改进原始Focal Loss:
python复制class DynamicFocalLoss(nn.Module):
def __init__(self, alpha=0.25, gamma=2, beta=0.6):
super().__init__()
self.alpha = alpha
self.gamma = gamma
self.beta = beta # 控制困难样本挖掘强度
def forward(self, pred, target):
BCE_loss = F.binary_cross_entropy_with_logits(pred, target, reduction='none')
# 动态调整alpha
pt = torch.exp(-BCE_loss)
alpha_factor = self.alpha * (1 - pt)**self.beta
# 困难样本挖掘
focal_weight = alpha_factor * (1 - pt)**self.gamma
loss = focal_weight * BCE_loss
return loss.mean()
改进点:
- 引入动态alpha因子,对难样本给予更高权重
- 通过beta参数控制困难样本挖掘强度
- 保持对易分类样本的降权效果
4.2 定位损失优化
采用CIoU Loss替代常规SmoothL1 Loss:
python复制def bbox_ciou(box1, box2):
"""
box1: predict (x1,y1,x2,y2)
box2: target (x1,y1,x2,y2)
"""
# 计算IoU
inter = (torch.min(box1[:,2:], box2[:,2:]) - torch.max(box1[:,:2], box2[:,:2])).clamp(0)
area1 = (box1[:,2]-box1[:,0]) * (box1[:,3]-box1[:,1])
area2 = (box2[:,2]-box2[:,0]) * (box2[:,3]-box2[:,1])
union = area1 + area2 - inter
iou = inter / union
# 计算中心点距离
c_x1 = (box1[:,0] + box1[:,2])/2
c_y1 = (box1[:,1] + box1[:,3])/2
c_x2 = (box2[:,0] + box2[:,2])/2
c_y2 = (box2[:,1] + box2[:,3])/2
c_dist = (c_x1-c_x2)**2 + (c_y1-c_y2)**2
# 计算最小包围框对角线距离
enclose_x1 = torch.min(box1[:,0], box2[:,0])
enclose_y1 = torch.min(box1[:,1], box2[:,1])
enclose_x2 = torch.max(box1[:,2], box2[:,2])
enclose_y2 = torch.max(box1[:,3], box2[:,3])
c_diag = (enclose_x2 - enclose_x1)**2 + (enclose_y2 - enclose_y1)**2 + 1e-7
# 计算长宽比一致性
v = (4/(math.pi**2)) * torch.pow(torch.atan((box2[:,2]-box2[:,0])/(box2[:,3]-box2[:,1]+1e-7)) -
torch.atan((box1[:,2]-box1[:,0])/(box1[:,3]-box1[:,1]+1e-7)), 2)
alpha = v / (1 - iou + v + 1e-7)
return iou - (c_dist/c_diag + alpha*v)
CIoU相比IoU的优点:
- 考虑中心点距离
- 考虑长宽比一致性
- 对微小目标定位更敏感
5. 后处理优化
5.1 自适应NMS
传统NMS对小目标检测效果不佳,我们改进如下:
python复制def adaptive_nms(boxes, scores, iou_thresh=0.5, score_thresh=0.1, top_k=200):
"""
boxes: [N,4] (x1,y1,x2,y2)
scores: [N]
"""
# 按得分排序
scores, idx = scores.sort(descending=True)
boxes = boxes[idx]
# 动态调整IoU阈值
areas = (boxes[:,2] - boxes[:,0]) * (boxes[:,3] - boxes[:,1])
scale = torch.sqrt(areas / (256*256)) # 基准尺寸
iou_thresh = iou_thresh * (1 + 0.5*scale) # 小目标使用更宽松阈值
keep = []
while boxes.size(0) > 0 and len(keep) < top_k:
# 保留当前最高分框
keep.append(idx[0].item())
if boxes.size(0) == 1:
break
# 计算IoU
ious = bbox_iou(boxes[0:1], boxes[1:])
# 动态过滤
mask = ious < iou_thresh[1:]
boxes = boxes[1:][mask]
scores = scores[1:][mask]
idx = idx[1:][mask]
iou_thresh = iou_thresh[1:][mask]
return keep
关键改进:
- 根据目标尺寸动态调整IoU阈值
- 保留更多小目标候选框
- 引入得分阈值二次过滤
5.2 多模型融合策略
我们采用加权框融合(WBF)方法:
python复制def weighted_box_fusion(boxes_list, scores_list, labels_list, weights=None, iou_thr=0.55):
"""
boxes_list: list of [N,4] tensors
scores_list: list of [N] tensors
labels_list: list of [N] tensors
weights: list of model weights
"""
if weights is None:
weights = [1.0] * len(boxes_list)
# 按得分排序并归一化权重
weights = np.array(weights) / sum(weights)
# 聚类相似框
clusters = []
for boxes, scores, labels in zip(boxes_list, scores_list, labels_list):
for box, score, label in zip(boxes, scores, labels):
matched = False
for cluster in clusters:
if label != cluster['label']:
continue
iou = bbox_iou(box, cluster['boxes'])
if iou.max() > iou_thr:
idx = iou.argmax()
cluster['boxes'] = np.vstack([cluster['boxes'], box])
cluster['scores'].append(score)
cluster['weights'].append(weights[i])
matched = True
break
if not matched:
clusters.append({
'boxes': np.array([box]),
'scores': [score],
'weights': [weights[i]],
'label': label
})
# 加权融合
fused_boxes = []
fused_scores = []
fused_labels = []
for cluster in clusters:
weights = np.array(cluster['weights'])
scores = np.array(cluster['scores'])
# 计算加权得分
total_weight = weights.sum()
conf = (scores * weights).sum() / total_weight
# 计算加权框坐标
boxes = np.array(cluster['boxes'])
x1 = (boxes[:,0] * weights * scores).sum() / (weights * scores).sum()
y1 = (boxes[:,1] * weights * scores).sum() / (weights * scores).sum()
x2 = (boxes[:,2] * weights * scores).sum() / (weights * scores).sum()
y2 = (boxes[:,3] * weights * scores).sum() / (weights * scores).sum()
fused_boxes.append([x1,y1,x2,y2])
fused_scores.append(conf)
fused_labels.append(cluster['label'])
return np.array(fused_boxes), np.array(fused_scores), np.array(fused_labels)
优势:
- 保留多个模型的预测信息
- 通过加权平均减少单一模型偏差
- 对小目标检测结果更稳定
6. 实际应用案例
6.1 卫星图像小目标检测
在遥感图像车辆检测任务中,我们对比了优化前后的性能:
| 指标 | 原始模型 | 优化模型 | 提升幅度 |
|---|---|---|---|
| mAP@0.5 | 0.412 | 0.587 | +42.5% |
| 小目标召回率 | 0.326 | 0.521 | +59.8% |
| 推理速度(FPS) | 23.4 | 18.7 | -20.1% |
关键改进点:
- 使用1024×1024输入分辨率
- 添加小目标专用数据增强
- 采用改进的FPN结构
6.2 工业缺陷检测
在PCB板缺陷检测中的应用效果:
| 缺陷类型 | 原始检出率 | 优化后检出率 | 误检率变化 |
|---|---|---|---|
| 焊点缺失 | 68.2% | 92.1% | +1.2pp |
| 线路断裂 | 54.7% | 83.6% | +0.8pp |
| 异物残留 | 72.3% | 95.4% | +0.5pp |
提示:工业场景应用时,建议针对特定缺陷类型设计专用的注意力模块。例如焊点检测可加入圆形模板注意力。
7. 部署优化技巧
7.1 模型量化方案
针对边缘设备部署的量化策略:
python复制# 训练后量化示例
model = load_model('small_obj_det.pth')
model.eval()
# 准备校准数据
calibrator = torch.quantization.QuantStub()
dequantizer = torch.quantization.DeQuantStub()
model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm')
# 融合模块
model_fused = torch.quantization.fuse_modules(model, [
['conv1', 'bn1', 'relu1'],
['conv2', 'bn2'],
# 添加更多可融合模块...
])
# 准备量化模型
prepared_model = torch.quantization.prepare_qat(model_fused)
# 校准(约500张图像)
with torch.no_grad():
for data in calib_loader:
prepared_model(data)
# 转换量化模型
quantized_model = torch.quantization.convert(prepared_model)
torch.save(quantized_model.state_dict(), 'quantized_model.pth')
量化后性能变化:
- 模型大小减小4倍(从189MB→47MB)
- 推理速度提升2.3倍(从45ms→19ms)
- mAP下降约3-5%(可通过QAT缓解)
7.2 TensorRT加速
针对NVIDIA GPU的优化部署:
python复制# 转换ONNX模型
torch.onnx.export(
model,
dummy_input,
"model.onnx",
opset_version=11,
input_names=['input'],
output_names=['output'],
dynamic_axes={
'input': {0: 'batch', 2: 'height', 3: 'width'},
'output': {0: 'batch'}
}
)
# TensorRT优化
trt_cmd = f"""
trtexec --onnx=model.onnx \
--saveEngine=model.engine \
--fp16 \
--workspace=2048 \
--minShapes=input:1x3x512x512 \
--optShapes=input:8x3x1024x1024 \
--maxShapes=input:16x3x1536x1536 \
--builderOptimizationLevel=3
"""
os.system(trt_cmd)
优化效果:
- Tesla T4 GPU上延迟从28ms降至9ms
- 批量处理吞吐量提升4倍
- 显存占用减少30%
8. 常见问题与解决方案
8.1 小目标漏检问题
可能原因及对策:
-
下采样过度:
- 减少骨干网络stage5的下采样率
- 使用空洞卷积保持感受野
- 示例修改:
python复制# ResNet修改示例 layer4 = nn.Sequential( nn.Conv2d(1024, 2048, kernel_size=3, stride=1, padding=2, dilation=2), nn.BatchNorm2d(2048), nn.ReLU(inplace=True), nn.Conv2d(2048, 2048, kernel_size=3, stride=1, padding=2, dilation=2), nn.BatchNorm2d(2048), nn.ReLU(inplace=True) )
-
锚框尺寸不匹配:
- 使用K-means重新聚类数据集锚框
- 添加更小尺度的检测层(如P2)
- 锚框生成示例:
python复制# 基于数据集的锚框计算 def kmeans_anchors(dataset, k=9): all_boxes = [] for data in dataset: all_boxes.extend(data['bboxes']) # 转换为wh格式 wh = np.array([[b[2]-b[0], b[3]-b[1]] for b in all_boxes]) # K-means聚类 kmeans = KMeans(n_clusters=k) kmeans.fit(wh) # 排序聚类中心 centers = kmeans.cluster_centers_ return centers[np.argsort(centers.prod(axis=1))]
8.2 误检问题优化
常见误检类型及处理:
| 误检类型 | 特征 | 解决方案 |
|---|---|---|
| 背景噪声 | 无规律分布 | 提高RPN得分阈值 |
| 部分目标 | 不完整特征 | 增加上下文注意力 |
| 相似物体 | 类间混淆 | 改进分类头结构 |
分类头改进示例:
python复制class EnhancedClassifier(nn.Module):
def __init__(self, in_channels, num_classes):
super().__init__()
self.gap = nn.AdaptiveAvgPool2d(1)
self.fc1 = nn.Linear(in_channels, in_channels//4)
self.fc2 = nn.Linear(in_channels//4, num_classes)
# 添加对比学习分支
self.projection = nn.Sequential(
nn.Linear(in_channels, in_channels//2),
nn.ReLU(),
nn.Linear(in_channels//2, 128)
)
def forward(self, x):
x = self.gap(x).flatten(1)
feat = self.fc1(x)
cls_out = self.fc2(feat)
proj_out = self.projection(x) if self.training else None
return cls_out, proj_out
8.3 训练技巧总结
-
学习率策略:
- 使用warmup+cosine衰减
- 小目标相关层使用更高学习率
- 示例配置:
yaml复制lr_scheduler: name: cosine base_lr: 0.01 warmup_epochs: 5 final_lr: 0.0001 # 参数组设置 param_groups: - params: backbone lr_mult: 0.1 - params: fpn lr_mult: 1.0 - params: rpn_head lr_mult: 1.5 # RPN需要更大学习率
-
正样本定义:
- 放宽IoU阈值(从0.5→0.3)
- 考虑中心点匹配而非框匹配
- 代码实现:
python复制def assign_targets(anchors, gt_boxes): # 计算中心点距离 anchor_ctr = (anchors[:,:2] + anchors[:,2:])/2 gt_ctr = (gt_boxes[:,:2] + gt_boxes[:,2:])/2 dist = torch.cdist(anchor_ctr, gt_ctr) # 结合IoU和中心距离 iou = bbox_iou(anchors, gt_boxes) scores = 0.7*iou + 0.3*(1-dist/dist.max()) # 分配规则 matches = scores.argmax(dim=1) max_scores = scores.max(dim=1)[0] pos_indices = max_scores > 0.3 return matches, pos_indices
9. 未来优化方向
-
Transformer架构适配:
- 试验Swin Transformer等视觉Transformer
- 设计小目标专用的窗口注意力机制
- 示例修改:
python复制class SmallObjectAttention(nn.Module): def __init__(self, dim, window_size=7): super().__init__() self.window_size = window_size self.relative_position_bias = nn.Parameter( torch.zeros((2*window_size-1)**2, 1)) # 初始化相对位置编码 coords = torch.stack(torch.meshgrid( torch.arange(window_size), torch.arange(window_size))).flatten(1) relative_coords = coords[:,:,None] - coords[:,None,:] relative_coords = relative_coords.permute(1,2,0).contiguous() relative_coords[:,:,0] += window_size - 1 relative_coords[:,:,1] += window_size - 1 relative_coords[:,:,0] *= 2 * window_size - 1 relative_position_index = relative_coords.sum(-1) self.register_buffer("relative_position_index", relative_position_index) self.qkv = nn.Linear(dim, dim*3) self.proj = nn.Linear(dim, dim) def forward(self, x): B, C, H, W = x.shape x = x.view(B, C, H//self.window_size, self.window_size, W//self.window_size, self.window_size) x = x.permute(0,2,4,3,5,1).reshape(-1, self.window_size*self.window_size, C) qkv = self.qkv(x).reshape(x.shape[0], x.shape[1], 3, C).permute(2,0,1,3) q, k, v = qkv[0], qkv[1], qkv[2] attn = (q @ k.transpose(-2,-1)) * (C**-0.5) relative_position_bias = self.relative_position_bias[ self.relative_position_index.view(-1)].view( self.window_size*self.window_size, self.window_size*self.window_size) attn = attn + relative_position_bias.unsqueeze(0) attn = attn.softmax(dim=-1) x = (attn @ v).transpose(1,2).reshape(-1, self.window_size, self.window_size, C) x = x.permute(0,3,1,2).contiguous() x = x.view(B, H//self.window_size, W//self.window_size, C, self.window_size, self.window_size) x = x.permute(0,3,1,4,2,5).reshape(B, C, H, W) x = self.proj(x) return x
-
神经架构搜索(NAS):
- 自动搜索小目标最优网络结构
- 设计多目标损失函数:
python复制class NASLoss(nn.Module): def __init__(self, alpha=0.7, beta=0.3): super().__init__() self.alpha = alpha # 精度权重 self.beta = beta # 速度权重 def forward(self, pred, target, latency): # 检测损失 cls_loss = F.cross_entropy(pred['cls'], target['cls']) reg_loss = F.smooth_l1_loss(pred['reg'], target['reg']) # 多目标权衡 return self.alpha*(cls_loss + reg_loss) + self.beta*latency
-
知识蒸馏应用:
- 使用大模型指导小模型训练
- 特别设计针对小目标的蒸馏损失:
python复制class SmallObjectDistillLoss(nn.Module): def __init__(self, temp=1.0, alpha=0.5): super().__init__() self.temp = temp self.alpha = alpha def forward(self, student_feats, teacher_feats, gt_boxes): # 提取小目标区域特征 small_masks = [] for boxes in gt_boxes: areas = (boxes[:,2]-boxes[:,0])*(boxes[:,3]-boxes[:,1]) small_masks.append(areas < 32*32) # 计算小目标特征相似度 loss = 0 for s_feat, t_feat, mask in zip(student_feats, teacher_feats, small_masks): if mask.sum() == 0: continue s = s_feat[mask].flatten(1) t = t_feat[mask].flatten(1).detach() s = F.normalize(s, dim=1) t = F.normalize(t, dim=1) loss += (s * t).sum(dim=1).mean() return self.alpha * (1 - loss/len(student_feats))
10. 完整训练示例
以下是一个典型的小目标检测训练流程:
python复制def train_small_object_detector():
# 1. 数据准备
train_transform = Compose([
RandomSmallObjectPaste(max_paste=5), # 小目标粘贴
RandomPhotometricDistort(),
RandomFlip(0.5),
Resize((1024,1024)),
Normalize()
])
dataset = SmallObjectDataset(
img_dir='data/images',
ann_file='data/annotations.json',
transform=train_transform
)
# 2. 模型构建
model = EnhancedSmallObjectDetector(
backbone='resnet50',
fpn_channels=256,
num_classes=20
)
# 3. 损失函数
cls_loss = DynamicFocalLoss()
reg_loss = CIoULoss()
# 4. 优化器
optimizer = torch.optim.AdamW([
{'params': model.backbone.parameters(), 'lr': 0.001},
{'params': model.fpn.parameters(), 'lr': 0.01},
{'params': model.head.parameters(), 'lr': 0.01}
], weight_decay=0.05)
# 5. 训练循环
for epoch in range(100):
model.train()
for images, targets in train_loader:
# 多尺度训练
if epoch % 30 == 0: # 每30epoch调整一次尺度
size = random.choice([512, 768, 1024])
images = F.interpolate(images, size=(size,size))
# 前向传播
preds = model(images)
# 损失计算
loss_cls = cls_loss(preds['cls'], targets['cls'])
loss_reg = reg_loss(preds['reg'], targets['reg'])
loss = loss_cls + loss_reg
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 验证
if epoch % 5 == 0:
evaluate(model, val_loader)
# 保存最佳模型
if is_best:
torch.save(model.state_dict(), f'best_{epoch}.pth')
关键训练参数建议:
- 批量大小:至少8(小目标需要足够多的样本)
- 初始学习率:0.01(检测头),0.001(骨干网络)
- 训练周期:100-300(视数据集规模而定)
- 数据增强:必须包含小目标复制粘贴
11. 评估指标解析
小目标检测需要特别关注的指标:
-
mAP@0.5:0.95:
- 计算IoU阈值从0.5到0.95(步长0.05)的平均精度
- 更能反映小目标定位精度
-
小目标召回率:
python复制def small_object_recall(detections, ground_truth, size_thresh=32): # 统计小目标 small_gt = [gt for gt in ground_truth if (gt[2]-gt[0])*(gt[3]-gt[1]) < size_thresh**2] # 计算召回 matched = 0 for gt in small_gt: for det in detections: if bbox_iou(gt, det[:4]) > 0.5: matched += 1 break return matched / len(small_gt) -
误检密度:
python复制def false_alarm_density(detections, image_size): # 计算每平方像素的误检数 area = image_size[0] * image_size[1] return len(detections) / area * 1e6 # 每百万像素误检数
12. 实际部署建议
-
分辨率选择:
- 服务器端:建议1024×1024以上分辨率
- 边缘设备:折中考虑768×768
- 移动端:至少512×512
-
模型裁剪技巧:
python复制def prune_model(model, prune_rate=0.3): # 1. 计算通道重要性 importance = [] for m in model.modules(): if isinstance(m, nn.Conv2d): # 使用L1范数作为重要性指标 imp = m.weight.abs().mean(dim=(1,2,3)) importance.append(imp.cpu().numpy()) # 2. 确定裁剪阈值 all_imp = np.concatenate(importance) threshold = np.percentile(all_imp, prune_rate*100) # 3. 执行裁剪 pruned_channels = 0 for m in model.modules(): if isinstance(m, nn.Conv2d): mask = m.weight.abs().mean(dim=(1,2,3)) > threshold pruned_channels += (~mask).sum() m.weight = nn.Parameter(m.weight[mask]) if m.bias is not None: m.bias = nn.Parameter(m.bias[mask]) print(f'Pruned {pruned_channels} channels') -
推理优化技巧:
- 使用ROI Align替代ROI Pooling(对小目标更友好)
- 对高分辨率输入采用滑动窗口检测
- 示例滑动窗口实现:
python复制def sliding_window_inference(image, model, window_size=512, stride=256): h, w = image.shape[-2:] outputs = [] for y in range(0, h, stride): for x in range(0, w, stride): # 提取窗口 x1, y1 = x, y x2 = min(x+window_size, w) y2 = min(y+window_size, h) window = image[..., y1:y2, x1:x2] # 推理 with torch.no_grad(): out = model(window.unsqueeze(0)) # 转换坐标 out['boxes'][..., [0,2]] += x1 out['boxes'][..., [1,3]] += y1 outputs.append(out) # 合并结果 final_out = { 'boxes': torch.cat([o['boxes'] for o in outputs]), 'scores': torch.cat([o['scores'] for o in outputs]), 'labels': torch.cat([o['labels'] for o
