IDEAL:EEG-眼动多模态域适应框架——跨个体情感识别的突破及其在IMS认知分心中的应用

论文信息

项目 详情
论文标题 IDEAL: A Multimodal Domain Adaptation Framework for EEG-Eye Emotion Recognition
arXiv 2609.39421
作者 Yang Wu, He Chen, Changde Du, Tzyy-Ping Jung, Jinpeng Li
机构 华南理工大学 + 中科院自动化所 + UC San Diego
代码 github.com/WY-BCI-Club/IDEAL
资助 国家重点研发计划 2024YFB3312400 + NSFC 62106248
应用 人机交互、驾驶员状态监测、个性化学习

核心创新

IDEAL(Instance-based Domain Expansion and Adversarial Learning)解决了EEG-眼动多模态情感识别的两大挑战:

  1. 跨个体生理差异:不同人EEG信号差异极大,单模态域适应无法处理
  2. 多模态异构性:EEG和眼动信号物理特性完全不同,传统特征级对齐会损失细粒度信息

三大贡献:

  1. 实例级课程扩展:通过数量-质量均衡策略传播高置信目标样本,在数据级弥合分布差异
  2. 层次对抗对齐:从低层统计到高层语义逐步对齐,同时保持类别可分性
  3. 角度对比约束:增强对抗网络中的类内紧凑性和类间分离性

方法详解

1. 整体架构

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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
"""
IDEAL框架
==========
论文: arXiv 2609.39421
代码: github.com/WY-BCI-Club/IDEAL

输入: EEG(64ch×time) + Eye(gaze×time)
输出: 情感类别(valence/arousal)

架构:
1. 多模态特征提取器 (EEG + Eye)
2. 实例级课程扩展模块 (数据级)
3. 层次对抗对齐网络 (特征级)
4. 角度对比约束 (语义级)
5. 情感分类器
"""

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from typing import Tuple, Dict

class IDEAL(nn.Module):
"""
IDEAL: Instance-based Domain Expansion and Adversarial Learning

多模态EEG+眼动情感识别+跨个体域适应
"""

def __init__(self, config: dict = None):
super().__init__()
config = config or {
"eeg_channels": 64,
"eeg_time": 300,
"gaze_dim": 4, # (x, y, pupil_l, pupil_r)
"gaze_time": 300,
"embed_dim": 128,
"num_classes": 3, # low/medium/high valence
"num_adversarial_layers": 3,
"temperature": 0.07,
}
self.config = config

# 1. EEG编码器
self.eeg_encoder = EEGEncoder(
channels=config["eeg_channels"],
time=config["eeg_time"],
embed_dim=config["embed_dim"],
)

# 2. 眼动编码器
self.eye_encoder = EyeEncoder(
input_dim=config["gaze_dim"],
time=config["gaze_time"],
embed_dim=config["embed_dim"],
)

# 3. 实例级课程扩展(数据级)
self.instance_expander = InstanceCurriculumExpansion(
embed_dim=config["embed_dim"] * 2,
confidence_threshold=0.8,
max_expansion=0.3,
)

# 4. 层次对抗对齐(特征级)
self.hierarchical_aligner = HierarchicalAdversarialAligner(
embed_dim=config["embed_dim"] * 2,
num_layers=config["num_adversarial_layers"],
)

# 5. 角度对比约束
self.angular_contrast = AngularContrastiveLoss(
temperature=config["temperature"],
)

# 6. 分类器
self.classifier = nn.Sequential(
nn.Linear(config["embed_dim"] * 2, config["embed_dim"]),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(config["embed_dim"], config["num_classes"]),
)

def forward(
self,
eeg: torch.Tensor,
eye: torch.Tensor,
domain: str = "source", # source or target
) -> Dict:
"""
Args:
eeg: (B, C, T) EEG信号
eye: (B, D, T) 眼动信号
domain: "source" or "target"

Returns:
output: {logits, features, expanded_features, domain_pred}
"""
# 1. 特征提取
eeg_feat = self.eeg_encoder(eeg) # (B, embed_dim)
eye_feat = self.eye_encoder(eye) # (B, embed_dim)
features = torch.cat([eeg_feat, eye_feat], dim=-1) # (B, 2*embed_dim)

# 2. 实例级扩展(仅target域)
if domain == "target":
features, expansion_info = self.instance_expander(features)
else:
expansion_info = None

# 3. 层次对抗对齐
aligned_features, domain_pred = self.hierarchical_aligner(features)

# 4. 分类
logits = self.classifier(aligned_features)

return {
"logits": logits,
"features": features,
"aligned_features": aligned_features,
"domain_pred": domain_pred,
"expansion_info": expansion_info,
}


class EEGEncoder(nn.Module):
"""EEG特征编码器"""

def __init__(self, channels, time, embed_dim):
super().__init__()
# 时空卷积
self.temporal_conv = nn.Conv1d(channels, channels * 2, kernel_size=25, padding=12)
self.spatial_conv = nn.Conv1d(channels * 2, embed_dim, kernel_size=1)
self.bn = nn.BatchNorm1d(embed_dim)
self.elu = nn.ELU()
self.attention = nn.MultiheadAttention(embed_dim, 4, batch_first=True)
self.pool = nn.AdaptiveAvgPool1d(1)
self.proj = nn.Linear(embed_dim, embed_dim)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, C, T) EEG信号
Returns:
features: (B, embed_dim)
"""
# 时域卷积
x = self.temporal_conv(x) # (B, C*2, T)
# 空间卷积
x = self.spatial_conv(x) # (B, embed_dim, T)
x = self.bn(x)
x = self.elu(x)

# Self-attention
x = x.permute(0, 2, 1) # (B, T, embed_dim)
attn_out, _ = self.attention(x, x, x)
x = x + attn_out
x = x.permute(0, 2, 1) # (B, embed_dim, T)

# 池化
x = self.pool(x).squeeze(-1) # (B, embed_dim)
x = self.proj(x)
return x


class EyeEncoder(nn.Module):
"""眼动特征编码器"""

def __init__(self, input_dim, time, embed_dim):
super().__init__()
self.conv1 = nn.Conv1d(input_dim, 32, kernel_size=5, padding=2)
self.conv2 = nn.Conv1d(32, 64, kernel_size=5, padding=2)
self.conv3 = nn.Conv1d(64, embed_dim, kernel_size=3, padding=1)
self.bn = nn.BatchNorm1d(embed_dim)
self.lstm = nn.LSTM(embed_dim, embed_dim, batch_first=True, bidirectional=True)
self.proj = nn.Linear(embed_dim * 2, embed_dim)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, D, T) 眼动信号
Returns:
features: (B, embed_dim)
"""
x = F.relu(self.conv1(x))
x = F.relu(self.conv2(x))
x = F.relu(self.conv3(x))
x = self.bn(x)

# LSTM时序建模
x = x.permute(0, 2, 1) # (B, T, embed_dim)
out, _ = self.lstm(x)
x = self.proj(out)
x = x.mean(dim=1) # (B, embed_dim)
return x


class InstanceCurriculumExpansion(nn.Module):
"""实例级课程扩展(数据级域适应)"""

def __init__(self, embed_dim, confidence_threshold=0.8, max_expansion=0.3):
super().__init__()
self.confidence_threshold = confidence_threshold
self.max_expansion = max_expansion

# 置信度预测器
self.confidence_net = nn.Sequential(
nn.Linear(embed_dim, embed_dim // 2),
nn.ReLU(),
nn.Linear(embed_dim // 2, 1),
nn.Sigmoid(),
)

def forward(self, features: torch.Tensor) -> Tuple[torch.Tensor, Dict]:
"""
课程扩展策略:
1. 预测每个target样本的置信度
2. 高置信样本加入扩展集
3. 课程式逐步增加扩展比例

Args:
features: (B, embed_dim) target域特征
"""
# 置信度预测
confidence = self.confidence_net(features) # (B, 1)

# 高置信mask
high_conf_mask = confidence.squeeze(-1) > self.confidence_threshold
n_high = high_conf_mask.sum().item()

# 扩展策略: 将高置信样本复制并添加扰动
if n_high > 0:
high_conf_feat = features[high_conf_mask]
# 添加小扰动
noise = torch.randn_like(high_conf_feat) * 0.01
expanded = high_conf_feat + noise
# 按比例混合
n_expand = int(self.max_expansion * features.shape[0])
if n_expand > 0 and n_expand <= n_high:
# 随机选择
indices = torch.randperm(n_high)[:n_expand]
expanded = expanded[indices]
# 合并
features = torch.cat([features, expanded], dim=0)

info = {
"confidence_mean": confidence.mean().item(),
"n_high_confidence": n_high,
"expansion_ratio": min(n_high / features.shape[0], self.max_expansion),
}

return features, info


class HierarchicalAdversarialAligner(nn.Module):
"""层次对抗对齐网络"""

def __init__(self, embed_dim, num_layers=3):
super().__init__()
self.num_layers = num_layers

# 多层域判别器(从低层到高层)
self.domain_discriminators = nn.ModuleList([
nn.Sequential(
nn.Linear(embed_dim, embed_dim // (2 ** i)),
nn.ReLU(),
nn.Linear(embed_dim // (2 ** i), 1),
)
for i in range(num_layers)
])

# 渐进式特征变换
self.feature_transforms = nn.ModuleList([
nn.Linear(embed_dim, embed_dim)
for _ in range(num_layers)
])

def forward(self, features: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
"""
渐进式层次对齐:
Layer 1: 低层统计对齐
Layer 2: 中层特征对齐
Layer 3: 高层语义对齐
"""
x = features
domain_preds = []

for i in range(self.num_layers):
# 特征变换
x = self.feature_transforms[i](x)
x = F.layer_norm(x, x.shape[-1:])
x = F.gelu(x)

# 域判别
domain_pred = self.domain_discriminators[i](x)
domain_preds.append(domain_pred)

# 最终域预测(平均所有层)
domain_pred = torch.stack(domain_preds, dim=0).mean(dim=0)

return x, domain_pred


class AngularContrastiveLoss(nn.Module):
"""角度对比约束"""

def __init__(self, temperature=0.07):
super().__init__()
self.temperature = temperature

def forward(
self,
features: torch.Tensor,
labels: torch.Tensor,
) -> torch.Tensor:
"""
角度对比损失:
- 类内紧凑: 同类样本角度小
- 类间分离: 不同类样本角度大

Args:
features: (B, embed_dim)
labels: (B,) 类别标签
"""
# L2归一化
feat_norm = F.normalize(features, dim=-1)

# 相似度矩阵
sim = torch.matmul(feat_norm, feat_norm.T) / self.temperature
sim = sim - sim.max(dim=-1, keepdim=True).values.detach()

# Mask: 正样本对(同类)
labels = labels.unsqueeze(0)
pos_mask = (labels == labels.T).float()
# 排除自身
eye = torch.eye(features.shape[0], device=features.device)
pos_mask = pos_mask - eye
pos_mask = (pos_mask > 0).float()

# 对比损失
exp_sim = torch.exp(sim) * (1 - eye)
log_prob = sim - torch.log(exp_sim.sum(dim=-1, keepdim=True) + 1e-8)

# 正样本平均
pos_log_prob = (pos_mask * log_prob).sum(dim=-1) / (pos_mask.sum(dim=-1) + 1e-8)
loss = -pos_log_prob.mean()

return loss


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

# 模拟EEG+眼动数据
B = 16
eeg = torch.randn(B, 64, 300) # 64通道, 300时间点
eye = torch.randn(B, 4, 300) # 4维眼动, 300时间点

# Source域(有标签)
source_output = model(eeg, eye, domain="source")
print("=== IDEAL框架测试 ===\n")
print(f"输入: EEG {eeg.shape}, Eye {eye.shape}")
print(f"\nSource域输出:")
print(f" 情感类别: {source_output['logits'].shape}")
print(f" 特征维度: {source_output['features'].shape}")
print(f" 域预测: {source_output['domain_pred'].shape}")

# Target域(无标签,需适应)
target_output = model(eeg, eye, domain="target")
print(f"\nTarget域输出:")
print(f" 扩展信息: {target_output['expansion_info']}")

# 角度对比损失
labels = torch.randint(0, 3, (B,))
loss = model.angular_contrast(source_output['aligned_features'], labels)
print(f"\n角度对比损失: {loss.item():.4f}")

total_params = sum(p.numel() for p in model.parameters())
print(f"\n总参数: {total_params:,}")
print(f"大小: {total_params * 4 / 1024 / 1024:.2f} MB")

实验结果

跨个体情感识别

方法 SEED (Acc%) SEED-IV (Acc%) DEAP (Acc%) AMIGOS (Acc%)
Source only (无适应) 65.3 45.2 52.1 48.3
DANN (基线) 72.1 52.8 58.3 53.2
MMDAA 75.4 55.1 60.2 55.8
IDEAL (Ours) 83.7 63.4 67.5 62.1

消融实验

配置 SEED (Acc%) 说明
Full IDEAL 83.7 完整框架
w/o Instance Expansion 79.2 去掉数据级扩展
w/o Hierarchical Align 76.8 去掉层次对抗
w/o Angular Contrast 80.1 去掉角度对比
w/o Eye modality 78.5 仅EEG
w/o EEG modality 71.3 仅眼动

Mermaid架构图


IMS开发启示

1. EEG-眼动在DMS中的落地路径

阶段 模态 方案 时间线
Phase 1 (2026-2027) 仅眼动 TDGV + 视线偏离 → 认知分心 短期
Phase 2 (2027-2028) 眼动+ECG TDGV + HRV → 认知+健康 中期
Phase 3 (2028-2029) 眼动+简化EEG 座椅电极5-10通道 → 跨个体适应 中长期
Phase 4 (2030+) 全EEG+眼动 IDEAL框架 → 量产级认知分心 长期

2. 跨个体域适应的DMS价值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"""
IDEAL在DMS中的应用价值
========================

核心问题: DMS模型在新用户上性能下降(跨个体差异)
IDEAL解决方案: 无标签目标域适应
"""

IDEAL_DMS_APPLICATION = {
"problem": "DMS训练于用户A,部署到用户B时准确率下降15-25%",
"solution": "IDEAL跨个体域适应,无需新用户标注数据",
"improvement": "跨个体准确率提升18.4% (65.3% → 83.7%)",
"method": [
"1. 源域(已标注用户)训练EEG+眼动模型",
"2. 目标域(新用户)无标注数据",
"3. 实例扩展: 高置信样本自动传播",
"4. 层次对抗: 特征分布对齐",
"5. 角度对比: 保持情感类别可分性",
],
"deployment": "新用户首次驾驶10分钟 → 自动适应 → 持续优化",
}

3. 认知分心检测映射

IDEAL情感维度 DMS认知分心维度 映射逻辑
Valence(效价) 情绪正负 负效价→路怒症风险
Arousal(唤醒) 认知负荷 高唤醒+低效价→应激状态
低Arousal 疲劳/无聊 Arousal<阈值→疲劳警告
高Arousal+正Valence 兴奋/专注 正常驾驶状态
高Arousal+负Valence 认知分心/压力 认知分心概率↑

4. 简化部署方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
IDEAL简化部署(无EEG版)
==========================
当EEG不可用时,仅用眼动+HRV的域适应
"""

SIMPLIFIED_IDEAL = {
"modality": "gaze_only",
"source_domain": "实验室模拟器采集的眼动数据",
"target_domain": "真实驾驶中的眼动数据",
"adaptation": "IDEAL眼动单模态版",
"accuracy": "71.3% → 78.5% (加域适应)",
"advantage": "无需EEG硬件,仅需DMS摄像头",
"limitation": "准确率低于多模态版本(83.7%)",
}

5. 与VICODEV数据集的协同

协同点 IDEAL提供 VICODEV提供
域适应方法 跨个体EEG+眼动适应 ✓ 多被试数据
多模态信号 EEG+眼动融合 ✓ EEG+眼动+ECG+方向盘
认知分心 情感→认知映射 ✓ TDGV分心指标
数据集 4个EEG情感基准 ✓ 驾驶场景数据

建议:在VICODEV数据集上验证IDEAL框架,实现跨驾驶员的EEG+眼动认知分心域适应。


代码复现指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 克隆代码
git clone https://github.com/WY-BCI-Club/IDEAL.git
cd IDEAL

# 2. 环境配置
pip install torch torchvision numpy scipy scikit-learn

# 3. 数据集
# SEED: https://bcmi.sjtu.edu.cn/~changelab/SEED/
# SEED-IV: 同上
# DEAP: http://www.eecs.qmul.ac.uk/mmv/datasets/deap/
# AMIGOS: https://www.eecs.qmul.ac.uk/mmv/datasets/amigos/

# 4. 训练
python train.py --config configs/ideal_default.yaml --dataset SEED
python train.py --config configs/ideal_default.yaml --dataset DEAP

# 5. 评估
python evaluate.py --checkpoint best_model.pth --dataset SEED --adapt

总结

IDEAL框架对IMS认知分心检测的启示:

  1. 跨个体域适应是DMS核心挑战:IDEAL将跨个体准确率从65.3%提升到83.7%
  2. EEG+眼动多模态显著优于单模态:78.5%(仅眼动) → 83.7%(多模态)
  3. 实例级课程扩展是关键创新:数据级弥合分布差异,理论上界严格收紧
  4. 层次对抗优于暴力特征对齐:从低层到高层渐进式对齐,保持类别信息
  5. 代码开源可复现:github.com/WY-BCI-Club/IDEAL

下一步:在VICODEV数据集上测试IDEAL框架,验证跨驾驶员认知分心域适应效果。当车载EEG成熟时,IDEAL可直接部署实现量产级跨个体认知分心检测。