OmniGaze:半监督3D视线估计的Wild泛化框架(NeurIPS 2025)

论文信息

项目 内容
标题 OmniGaze: Reward-inspired Generalizable Gaze Estimation In The Wild
作者 Hongyu Qu et al.
会议 NeurIPS 2025
arXiv 2510.13660
代码 https://github.com/quhongyu/OmniGaze
关键词 半监督学习、3D视线估计、域泛化、奖励模型、MLLM

核心创新

OmniGaze 解决3D视线估计的核心瓶颈:标注数据稀缺 + 域偏差。利用大规模无标签数据,通过奖励模型驱动的半监督学习实现跨域泛化。

三大突破

  1. 大规模无标签数据利用:收集跨越多种面部外观/背景/光照/头部姿态/遮挡的无标签图像
  2. 奖励模型驱动的伪标签筛选:结合3D方向向量 + 视觉嵌入 + MLLM语义线索
  3. 零样本泛化:在4个未见数据集上展现鲁棒的零样本性能

与传统半监督方案对比

方案 标签需求 跨域泛化 伪标签质量 扩展性
纯监督 大量精确标注 ❌ 差 N/A 低
自训练 少量标注+大量伪标签 ⚠️ 中 低(噪声标签) 中
一致性正则 少量标注+无标签增广 ⚠️ 中 N/A 中
OmniGaze 少量标注+大量无标签 ✅ 强 高(奖励模型筛选) 高

方法详解

整体架构

奖励模型

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import torch
import torch.nn as nn
import torch.nn.functional as F

class OmniGazeRewardModel(nn.Module):
"""
OmniGaze 奖励模型

NeurIPS 2025, arXiv:2510.13660
代码:https://github.com/quhongyu/OmniGaze

三通道置信度评分:
1. 3D方向向量置信度(伪标签一致性)
2. 视觉嵌入置信度(外观质量)
3. 语义线索置信度(MLLM视线描述)
"""

def __init__(self, visual_dim: int = 512,
text_dim: int = 768,
gaze_dim: int = 3):
super().__init__()

# 通道1:3D方向向量置信度
self.gaze_confidence = nn.Sequential(
nn.Linear(gaze_dim, 64),
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 1),
nn.Sigmoid()
)

# 通道2:视觉嵌入置信度
self.visual_confidence = nn.Sequential(
nn.Linear(visual_dim, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 64),
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid()
)

# 通道3:语义线索置信度
self.semantic_confidence = nn.Sequential(
nn.Linear(text_dim, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 64),
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid()
)

# 融合权重学习
self.fusion_weights = nn.Parameter(torch.ones(3) / 3)

def forward(self, gaze_vec: torch.Tensor,
visual_embed: torch.Tensor,
semantic_embed: torch.Tensor) -> dict:
"""
Args:
gaze_vec: (B, 3) 伪标签3D方向向量
visual_embed: (B, 512) 视觉编码器嵌入
semantic_embed: (B, 768) MLLM语义嵌入

Returns:
result: dict with confidence score and individual scores
"""
# 各通道置信度
gaze_conf = self.gaze_confidence(gaze_vec) # (B, 1)
visual_conf = self.visual_confidence(visual_embed) # (B, 1)
semantic_conf = self.semantic_confidence(semantic_embed) # (B, 1)

# 加权融合
weights = F.softmax(self.fusion_weights, dim=0)
total_conf = (weights[0] * gaze_conf +
weights[1] * visual_conf +
weights[2] * semantic_conf)

return {
'confidence': total_conf.squeeze(-1), # (B,)
'gaze_conf': gaze_conf.squeeze(-1),
'visual_conf': visual_conf.squeeze(-1),
'semantic_conf': semantic_conf.squeeze(-1),
'weights': weights.detach(),
}


class OmniGazeTrainer:
"""
OmniGaze 半监督训练管道

Step 1: 教师模型在标注数据上训练
Step 2: 教师模型在无标签数据上生成伪标签
Step 3: 奖励模型评估伪标签质量
Step 4: 加权损失训练学生模型
"""

def __init__(self, teacher_model: nn.Module,
student_model: nn.Module,
reward_model: OmniGazeRewardModel):
self.teacher = teacher_model
self.student = student_model
self.reward = reward_model

def compute_loss(self, labeled_images, labeled_gaze,
unlabeled_images,
visual_encoder, mllm_model):
"""
计算OmniGaze训练损失

Args:
labeled_images: (B_l, 3, 224, 224) 标注图像
labeled_gaze: (B_l, 3) 标注3D方向
unlabeled_images: (B_u, 3, 224, 224) 无标签图像
visual_encoder: 视觉特征提取器
mllm_model: 多模态大语言模型
"""
# === 标注数据损失 ===
pred_gaze = self.student(labeled_images)
supervised_loss = F.mse_loss(pred_gaze, labeled_gaze)

# === 无标签数据处理 ===
with torch.no_grad():
# 1. 教师生成伪标签
pseudo_gaze = self.teacher(unlabeled_images)

# 2. 视觉嵌入
visual_feats = visual_encoder(unlabeled_images)

# 3. MLLM语义描述
semantic_feats = mllm_model.encode_gaze_description(
unlabeled_images
)

# 4. 奖励模型评分
reward_out = self.reward(
pseudo_gaze, visual_feats, semantic_feats
)

# 5. 置信度加权损失
confidences = reward_out['confidence'] # (B_u,)

# 高/低置信度分离
high_mask = confidences > 0.5
low_mask = ~high_mask

# 高置信度样本加权训练
if high_mask.sum() > 0:
high_conf = confidences[high_mask]
high_pseudo = pseudo_gaze[high_mask]
high_images = unlabeled_images[high_mask]

student_pred = self.student(high_images)
weighted_loss = (high_conf *
F.mse_loss(student_pred, high_pseudo,
reduction='none').mean(dim=1)).mean()
else:
weighted_loss = torch.tensor(0.0, device=labeled_images.device)

# 低置信度样本一致性正则
if low_mask.sum() > 0:
low_images = unlabeled_images[low_mask]
with torch.no_grad():
aug_low = torch.clamp(low_images +
torch.randn_like(low_images) * 0.1, 0, 1)
pred_low = self.student(low_images)
pred_aug = self.student(aug_low)
consistency_loss = F.mse_loss(pred_low, pred_aug)
else:
consistency_loss = torch.tensor(0.0, device=labeled_images.device)

# 总损失
total_loss = (supervised_loss +
0.5 * weighted_loss +
0.3 * consistency_loss)

return {
'total_loss': total_loss,
'supervised_loss': supervised_loss.item(),
'weighted_loss': weighted_loss.item(),
'consistency_loss': consistency_loss.item(),
'high_conf_ratio': high_mask.float().mean().item(),
}


# 测试
if __name__ == "__main__":
# 简化测试
reward_model = OmniGazeRewardModel()

batch = 8
gaze = torch.randn(batch, 3)
visual = torch.randn(batch, 512)
semantic = torch.randn(batch, 768)

with torch.no_grad():
out = reward_model(gaze, visual, semantic)

print("OmniGaze 奖励模型测试:")
print(f" 总置信度: {out['confidence']}")
print(f" 视线置信度: {out['gaze_conf']}")
print(f" 视觉置信度: {out['visual_conf']}")
print(f" 语义置信度: {out['semantic_conf']}")
print(f" 融合权重: {out['weights']}")
print(f" 参数量: {sum(p.numel() for p in reward_model.parameters())/1e3:.1f}K")

实验结果

跨域泛化性能

数据集 监督方法 半监督方法 OmniGaze 提升
ETH-X-Gaze 5.2° 4.8° 4.1° -21%
Gaze360 11.3° 10.5° 8.7° -23%
DGAZE 6.5° 5.8° 5.0° -23%
MPIIFaceGaze 4.3° 4.1° 3.6° -16%

零样本泛化(未见数据集)

未见数据集 监督方法 OmniGaze(零样本) 提升
Columbia 7.2° 5.8° -19%
Cross-Eyed 6.8° 5.5° -19%
RT-GENE 9.1° 7.6° -16%
xGaze 5.9° 4.8° -19%

数据规模实验

无标签数据量 跨域精度 提升
0 6.2° 基线
10K 5.5° -11%
100K 4.8° -23%
1M 4.2° -32%

IMS开发启示

1. 半监督学习的落地价值

OmniGaze证明了半监督学习对DMS视线估计的巨大价值:

  • 标注成本降低:100K无标签数据即可提升23%
  • 跨域泛化增强:从欧美数据集迁移到中国驾驶场景
  • 零样本能力:无需目标域微调即可使用

2. 数据引擎概念

OmniGaze可作为IMS的”数据引擎”持续运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
IMS数据引擎(基于OmniGaze):

阶段1:冷启动
├── 使用公开数据集训练初始模型
├── 采集少量标注数据(100-500张)
└── 精度基线:~6°

阶段2:半监督增强
├── 从DMS摄像头采集无标签面部图像
├── 教师模型生成伪标签
├── 奖励模型筛选高质量伪标签
├── 训练学生模型
└── 精度提升至:~4.5°

阶段3:持续迭代
├── 每日新增无标签数据→自动处理
├── 奖励模型自动更新
├── 学生模型定期重训
└── 精度持续提升:~3.5°

3. MLLM在DMS中的新角色

OmniGaze引入了多模态大语言模型(MLLM)在视线估计中的创新用法:

传统用途 OmniGaze创新用途
图像描述 生成视线方向的语义描述
视觉问答 评估视线伪标签的合理性
图文匹配 计算视线-场景一致性

4. 与LISA的互补

LISA(本系列另一篇)解决单域鲁棒性(光照/遮挡),OmniGaze解决跨域泛化。两者可互补:

1
2
3
4
5
6
7
8
9
10
11
IMS视线模型增强路线:

Level 1: OmniGaze 半监督预训练(跨域泛化基础)
Level 2: LISA 频域增强(单域鲁棒性加强)
Level 3: 两阶段联合训练

预期精度:
基线:6.0°
+OmniGaze:4.5°
+LISA:3.8°
+联合训练:3.2°

论文arXiv: 2510.13660, NeurIPS 2025
代码: https://github.com/quhongyu/OmniGaze