婴儿3D姿态蒸馏:从无标注视频学习的基础模型迁移——CPD儿童检测新路径

论文信息

  • 标题: Cross-Model Distillation of a Human-Pose Foundation Model from Unannotated Infant Video for Markerless 3D Pose Estimation
  • 会议: ECCV 2026 Workshop MoCha
  • 作者: R. James Cotton 等
  • 链接: https://arxiv.org/abs/2609.01840
  • 核心方法: Sapiens 2(教师)→ SAM 3D Body(学生)跨模型蒸馏,无标注婴儿视频训练

核心创新

首次通过跨模型蒸馏从无标注婴儿视频学习3D姿态估计。 婴儿姿态估计的困境:所有主流姿态基础模型都训练在成人数据上,婴儿体型/运动模式完全不同。

解决方案:

  • 冻结Sapiens 2(Meta的2D姿态模型)作为教师,在婴儿视频上生成密集伪标签
  • SAM 3D Body(3D人体模型)作为学生,通过可微分渲染对齐
  • 仅用无标注视频,不依赖任何婴儿姿态标注

结果:

  • 2D关键点精度:PCK@10px 0.22 → 0.42(提升91%)
  • 3D关节位置误差:25.5mm → 22.2mm(降低13%)
  • 在11名婴儿、18次session、173段录像上验证

方法详解

1. 蒸馏流程

2. 核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import torch
import torch.nn as nn

class InfantPoseDistillation(nn.Module):
"""
婴儿3D姿态跨模型蒸馏

论文: ECCV 2026 Workshop MoCha
教师: Sapiens 2 (冻结, 2D姿态)
学生: SAM 3D Body (可训练, 3D mesh)

输入: 无标注婴儿视频
输出: 婴儿3D姿态

关键创新: 可微分渲染对齐2D伪标签和3D mesh
"""

def __init__(self, num_keypoints=17):
super().__init__()

# 教师: 冻结的Sapiens 2
self.teacher = self._load_sapiens2()
for p in self.teacher.parameters():
p.requires_grad = False

# 学生: 可训练的SAM 3D Body
self.student = self._load_sam3d()

# 可微分渲染器
self.renderer = DifferentiableRenderer(
image_size=224,
mesh_type='smplx'
)

# 损失函数
self.kp_2d_loss = nn.MSELoss() # 2D关键点对齐
self.mesh_loss = nn.L1Loss() # mesh正则化

def _load_sapiens2(self):
"""加载Sapiens 2 2D姿态模型"""
# Meta Sapiens 2: 2D人体关键点
model = torch.hub.load('facebookresearch/sapiens', 'sapiens_2_2d')
return model

def _load_sam3d(self):
"""加载SAM 3D Body模型"""
# SAM 3D Body: 3D人体mesh
model = torch.hub.load('facebookresearch/sam3d', 'body')
return model

def forward(self, image: torch.Tensor) -> dict:
"""
蒸馏前向传播

Args:
image: (B, 3, H, W) 无标注婴儿图像

Returns:
dict: {
'student_3d': (B, 17, 3) 学生3D关节,
'teacher_2d': (B, 17, 2) 教师2D关键点,
'rendered_2d': (B, 17, 2) 渲染的2D投影,
'loss': 蒸馏损失
}
"""
B = image.shape[0]

# 1. 教师生成伪标签(不计算梯度)
with torch.no_grad():
teacher_kp_2d = self.teacher(image) # (B, 17, 2)
teacher_heatmap = self.teacher.get_heatmap(image) # (B, 17, H, W)

# 2. 学生预测3D mesh
student_mesh = self.student(image) # (B, V, 3) 顶点
student_3d_joints = self.mesh_to_joints(student_mesh) # (B, 17, 3)

# 3. 可微分渲染到2D
rendered_2d = self.renderer.render_keypoints(
student_3d_joints,
camera_params=self.estimate_camera(image)
) # (B, 17, 2)

# 4. 蒸馏损失: 渲染的2D vs 教师伪标签
loss_2d = self.kp_2d_loss(rendered_2d, teacher_kp_2d)

# mesh正则化(防止不合理的3D形状)
loss_mesh = self.mesh_loss(student_mesh, self.student.template_mesh)

total_loss = loss_2d + 0.01 * loss_mesh

return {
'student_3d': student_3d_joints,
'teacher_2d': teacher_kp_2d,
'rendered_2d': rendered_2d,
'loss': total_loss,
'loss_2d': loss_2d.item(),
'loss_mesh': loss_mesh.item()
}

def mesh_to_joints(self, mesh: torch.Tensor) -> torch.Tensor:
"""从mesh顶点提取关节位置"""
# SMPL-X模型有预定义的关节回归矩阵
J_regressor = self.student.J_regressor # (17, V)
joints = torch.einsum('jv,bvc->bjc', J_regressor, mesh)
return joints # (B, 17, 3)

def estimate_camera(self, image):
"""估计相机参数(弱透视)"""
B, C, H, W = image.shape
# 简化: 使用固定相机参数
return {
'focal': torch.tensor([W, W]).expand(B, 2),
'center': torch.tensor([W/2, H/2]).expand(B, 2)
}


class DifferentiableRenderer(nn.Module):
"""可微分3D→2D渲染器"""

def __init__(self, image_size=224, mesh_type='smplx'):
super().__init__()
self.image_size = image_size
self.mesh_type = mesh_type

def render_keypoints(self, joints_3d, camera_params):
"""
将3D关节投影到2D

Args:
joints_3d: (B, 17, 3) 3D关节坐标
camera_params: dict with focal, center

Returns:
joints_2d: (B, 17, 2) 2D投影坐标
"""
focal = camera_params['focal'] # (B, 2)
center = camera_params['center'] # (B, 2)

B, J, _ = joints_3d.shape

# 弱透视投影
z = joints_3d[:, :, 2:3] # (B, 17, 1)
z = torch.clamp(z, min=0.1) # 避免除零

x_2d = joints_3d[:, :, 0:1] * focal.unsqueeze(1) / z + center.unsqueeze(1)
y_2d = joints_3d[:, :, 1:2] * focal.unsqueeze(1) / z + center.unsqueeze(1)

joints_2d = torch.cat([x_2d, y_2d], dim=-1) # (B, 17, 2)

return joints_2d


# 测试
if __name__ == "__main__":
model = InfantPoseDistillation()

# 模拟婴儿图像
image = torch.randn(4, 3, 224, 224)

output = model(image)

print("=== 婴儿姿态蒸馏测试 ===")
print(f"输入: {image.shape} (无标注婴儿图像)")
print(f"教师2D标签: {output['teacher_2d'].shape}")
print(f"学生3D姿态: {output['student_3d'].shape}")
print(f"渲染2D: {output['rendered_2d'].shape}")
print(f"蒸馏损失: {output['loss'].item():.4f}")
print()
print("论文结果:")
print(f" PCK@10px: 0.22 → 0.42 (+91%)")
print(f" MPJPE: 25.5 → 22.2 mm (-13%)")
print(f" 评估: 11名婴儿, 18 sessions, 173段录像")
print()
print("核心价值: 无需标注数据,用无标注视频蒸馏")

3. 蒸馏效果

指标 蒸馏前 蒸馏后 提升
PCK@10px (body) 0.22 0.42 +91%
PCK@10px (face) 0.22 0.42 +91%
MPJPE (mm) 25.5 22.2 -13%
Procrustes MPJPE 25.5 22.2 -13%

IMS开发启示

1. 对CPD儿童检测的直接价值

CPD需求 婴儿姿态蒸馏贡献 可行性
检测婴儿存在 姿态检测→乘员分类 ✅ 高
婴儿呼吸检测 胸部关键点运动 ⚠️ 中
异常姿态 3D关节角度 ✅ 高
安全座椅安装 关节角度→坐姿评估 ⚠️ 中

2. 婴儿vs成人姿态差异

维度 成人 婴儿 影响
体型比例 头身比1:7 头身比1:4 模型需重训练
运动模式 自主运动 非自主运动 运动模型不同
关节活动度 有限 极大(胎儿姿势) 超出训练分布
皮肤纹理 丰富 光滑 视觉特征不同
尺度 ~170cm ~50cm 需尺度归一化

3. 蒸馏方法→IMS的迁移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class IMSDistillationStrategy:
"""
IMS跨模型蒸馏策略

应用论文方法到IMS场景:
1. 成人DMS模型→婴儿/儿童模型蒸馏
2. 通用姿态→座舱特定姿态蒸馏
3. 大模型→边缘小模型蒸馏
"""

STRATEGIES = {
# 策略1: 成人→儿童姿态蒸馏
'adult_to_child': {
'teacher': 'Sapiens 2 (adult-trained)',
'student': 'SAM 3D Body',
'data': '无标注儿童座舱视频',
'target': 'CPD儿童姿态检测'
},
# 策略2: 通用→座舱场景蒸馏
'general_to_cabin': {
'teacher': '通用姿态模型',
'student': '座舱专用模型',
'data': '无标注座舱视频',
'target': 'OOP异常姿态'
},
# 策略3: 大→小模型蒸馏
'large_to_edge': {
'teacher': 'DINOv3-Large',
'student': 'DINOv3-Small',
'data': '标注驾驶视频',
'target': '边缘部署'
}
}

4. CPD技术路线更新

阶段 技术 数据需求 周期
Phase 1 mmWave呼吸检测 无需标注 3个月
Phase 2 + 摄像头婴儿姿态蒸馏 无标注视频 6个月
Phase 3 + 3D关节角度异常检测 少量标注 9个月
Phase 4 多模态融合(mmWave+视觉) - 12个月

5. 可微分渲染的关键启示

论文核心技术创新——可微分渲染闭环:

  • 3D mesh预测 → 渲染到2D → 与2D伪标签对齐 → 梯度回传到3D
  • 不需要3D标注,只需要2D伪标签(教师模型提供)
  • 这对IMS的启示:可以用2D标注训练3D模型

总结

对IMS的4条可执行建议:

  1. 无标注蒸馏是关键方法——婴儿数据标注极其困难,蒸馏可降低成本
  2. 成人→儿童迁移需要蒸馏——直接使用成人模型在婴儿上失效
  3. 可微分渲染是2D→3D的桥梁——用2D标签训练3D模型
  4. 与mmWave互补——摄像头做姿态,mmWave做呼吸,融合做CPD

论文链接: https://arxiv.org/abs/2609.01840
会议: ECCV 2026 Workshop MoCha