驾驶员多模态情绪识别:MHLT模型级融合视频与音频

论文信息

  • 标题: Intelligent emotion recognition for drivers using model-level multimodal fusion
  • 期刊: Frontiers in Physics, 2025
  • 链接: https://doi.org/10.3389/fphy.2025.1599428
  • 发表日期: 2025年11月2日
  • 核心方法: MHLT模型——视频+音频模型级融合 + 注意力机制 + 情绪强度回归

核心创新

首次在驾驶员情绪识别中引入情绪强度连续维度(-1到+1),而非传统的离散分类。MHLT模型通过多头注意力机制在模型级融合视频和音频,不仅识别情绪类型(正/中/负),还量化情绪强度(如-0.7表示强烈负面情绪)。

关键差异:

  • 传统方法:分类为”愤怒”/“悲伤”/“高兴”等6类
  • MHLT方法:连续维度[-1, +1],-0.7=强烈负面,+0.3=轻度正面
  • 轻度负面情绪(-0.2)可能让驾驶更谨慎,极端负面(-0.8)才危险

方法详解

1. 情绪模型

2. MHLT架构

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
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Tuple

class MHLTDriverEmotionModel(nn.Module):
"""
MHLT: Multi-Head attention Level fusion for Driver emotion recognition

论文: Frontiers in Physics, 2025
核心: 视频(面部表情) + 音频(语音情绪) → 模型级融合 → 情绪强度回归

创新点:
1. 情绪连续维度 [-1, +1] 而非离散分类
2. 多头注意力模型级融合
3. 同时预测情绪类型和强度
"""

def __init__(self,
video_feature_dim=512,
audio_feature_dim=256,
hidden_dim=256,
num_heads=8):
super().__init__()

# 视频编码器 (基于VGG/ResNet的面部表情特征)
self.video_encoder = nn.Sequential(
nn.Linear(video_feature_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU(),
nn.Dropout(0.1),
nn.Linear(hidden_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU()
)

# 音频编码器 (基于Transformer的语音情绪特征)
self.audio_encoder = nn.Sequential(
nn.Linear(audio_feature_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU(),
nn.Dropout(0.1),
nn.Linear(hidden_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.GELU()
)

# 多头注意力融合层
self.fusion_attention = nn.MultiheadAttention(
embed_dim=hidden_dim * 2,
num_heads=num_heads,
dropout=0.1,
batch_first=True
)

# 情绪分类头 (正/中/负)
self.classification_head = nn.Sequential(
nn.Linear(hidden_dim * 2, hidden_dim),
nn.GELU(),
nn.Dropout(0.2),
nn.Linear(hidden_dim, 3) # 3类: 正/中/负
)

# 情绪强度回归头 [-1, +1]
self.intensity_head = nn.Sequential(
nn.Linear(hidden_dim * 2, hidden_dim),
nn.GELU(),
nn.Dropout(0.2),
nn.Linear(hidden_dim, 1),
nn.Tanh() # 输出 [-1, 1]
)

def forward(self, video_features: torch.Tensor,
audio_features: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
"""
前向传播

Args:
video_features: 面部表情特征 [B, T, 512]
audio_features: 语音情绪特征 [B, T, 256]

Returns:
emotion_class: 情绪分类logits [B, 3]
emotion_intensity: 情绪强度 [-1, 1] [B, 1]
"""
# 编码
v_encoded = self.video_encoder(video_features) # [B, T, 256]
a_encoded = self.audio_encoder(audio_features) # [B, T, 256]

# 拼接
fused = torch.cat([v_encoded, a_encoded], dim=-1) # [B, T, 512]

# 多头注意力融合
attended, _ = self.fusion_attention(
fused, fused, fused
)

# 池化
pooled = attended.mean(dim=1) # [B, 512]

# 双头输出
emotion_class = self.classification_head(pooled)
emotion_intensity = self.intensity_head(pooled)

return emotion_class, emotion_intensity


# 训练和测试代码
class MHLTTrainer:
"""MHLT模型训练器"""

def __init__(self, model, lr=1e-4):
self.model = model
self.optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=0.01)

# 分类损失
self.cls_criterion = nn.CrossEntropyLoss()
# 强度回归损失 (MSE)
self.reg_criterion = nn.MSELoss()

def train_step(self, video_feat, audio_feat, emotion_label, intensity_label):
"""
单步训练

Args:
video_feat: [B, T, 512]
audio_feat: [B, T, 256]
emotion_label: [B] (0=正, 1=中, 2=负)
intensity_label: [B] (-1.0 to 1.0)
"""
self.optimizer.zero_grad()

cls_pred, int_pred = self.model(video_feat, audio_feat)

# 总损失 = 分类损失 + 强度损失
cls_loss = self.cls_criterion(cls_pred, emotion_label)
reg_loss = self.reg_criterion(int_pred.squeeze(), intensity_label)

# 论文使用加权组合
total_loss = cls_loss + 0.5 * reg_loss

total_loss.backward()
self.optimizer.step()

return {
'total_loss': total_loss.item(),
'cls_loss': cls_loss.item(),
'reg_loss': reg_loss.item()
}


if __name__ == "__main__":
# 模型初始化
model = MHLTDriverEmotionModel(
video_feature_dim=512,
audio_feature_dim=256,
hidden_dim=256,
num_heads=8
)

# 模拟输入
batch_size = 4
seq_len = 30 # 30帧

video_feat = torch.randn(batch_size, seq_len, 512)
audio_feat = torch.randn(batch_size, seq_len, 256)

# 前向传播
cls_pred, int_pred = model(video_feat, audio_feat)

print("=== MHLT模型测试 ===")
print(f"输入: 视频{video_feat.shape} + 音频{audio_feat.shape}")
print(f"分类输出: {cls_pred.shape} (3类: 正/中/负)")
print(f"强度输出: {int_pred.shape} (范围: [-1, +1])")
print(f"强度值: {int_pred.detach().numpy().flatten()}")

# 训练模拟
trainer = MHLTTrainer(model)
labels = torch.tensor([2, 1, 0, 2]) # 负, 中, 正, 负
intensities = torch.tensor([-0.7, 0.0, 0.3, -0.8])

for epoch in range(5):
result = trainer.train_step(video_feat, audio_feat, labels, intensities)
print(f"Epoch {epoch+1}: loss={result['total_loss']:.4f} "
f"(cls={result['cls_loss']:.4f}, reg={result['reg_loss']:.4f})")

# 情绪强度解释
print("\n=== 情绪强度解读 ===")
print("-0.8: 极端负面 → 可能危险驾驶(愤怒/恐慌)")
print("-0.2: 轻度负面 → 可能更谨慎驾驶")
print(" 0.0: 中性 → 正常驾驶状态")
print("+0.3: 轻度正面 → 放松但可能分心")
print("+0.8: 极端正面 → 兴奋可能导致冒险")

3. 预处理流程

步骤 视频模态 音频模态
1 人脸检测(face_recognition库) 降噪+归一化
2 人脸对齐(一致性区域) 分帧(25ms窗口)
3 特征提取(VGG/ResNet) 特征提取(Mel频谱+Transformer)
4 序列化(滑动窗口) 序列化(对齐视频帧)

4. 融合策略对比

融合层级 方法 优点 缺点 典型准确率
特征级 直接拼接 简单 冗余+跨模态交互弱 82%
决策级 各模态独立预测后投票 模块独立 时序依赖丢失 80%
模型级(MHLT) 注意力机制中间表示交互 动态权重+跨模态 计算复杂 88%

实验结果

性能对比

方法 模态 准确率 强度MAE 说明
VGG-only 视频 78.3% - 单模态基线
Transformer-only 音频 73.5% - 单模态基线
特征级融合 视频+音频 82.1% 0.21 简单拼接
决策级融合 视频+音频 80.5% 0.23 投票
MHLT(本文) 视频+音频 88.4% 0.15 模型级融合

情绪强度预测

情绪状态 真实强度 MHLT预测 误差
极端愤怒 -0.8 -0.74 0.06
轻度焦虑 -0.3 -0.27 0.03
中性 0.0 0.02 0.02
轻度愉快 +0.3 +0.28 0.02
极度兴奋 +0.8 +0.71 0.09

IMS开发启示

1. 情绪强度对驾驶安全的影响

情绪强度范围 驾驶影响 IMS策略
[-1.0, -0.6] 极端负面:路怒/恐慌 立即警告+建议停车
[-0.6, -0.2] 中度负面:焦虑/沮丧 提醒+播放舒缓音乐
[-0.2, +0.2] 中性:最佳驾驶状态 无干预
[+0.2, +0.6] 中度正面:愉快/兴奋 监控分心风险
[+0.6, +1.0] 极端正面:过度兴奋 警告+建议冷静

2. DMS情绪监测系统集成

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
class DMSEmotionIntegration:
"""
DMS + 情绪识别集成方案

当情绪强度超出安全范围时触发干预
"""

SAFE_RANGE = (-0.2, 0.2)
WARNING_RANGE = (-0.6, -0.2, 0.2, 0.6)
DANGER_RANGE = (-1.0, -0.6, 0.6, 1.0)

def __init__(self):
self.emotion_model = MHLTDriverEmotionModel()
self.current_emotion = 0.0
self.emotion_history = []

def monitor(self, video_feat, audio_feat) -> dict:
"""实时情绪监控"""
with torch.no_grad():
cls_pred, int_pred = self.emotion_model(video_feat, audio_feat)

intensity = int_pred.item()
emotion_class = ['positive', 'neutral', 'negative'][cls_pred.argmax().item()]

self.emotion_history.append(intensity)

# 滑动窗口平均(10秒)
if len(self.emotion_history) > 300:
recent = self.emotion_history[-300:]
avg_intensity = sum(recent) / len(recent)
else:
avg_intensity = intensity

return self._generate_response(avg_intensity, emotion_class)

def _generate_response(self, intensity: float, emotion: str) -> dict:
"""生成情绪干预响应"""
if intensity < -0.6:
return {
'level': 'danger',
'action': '强烈建议靠边停车',
'audio': '舒缓音乐',
'hud': '请冷静,建议休息'
}
elif intensity < -0.2:
return {
'level': 'warning',
'action': '提醒注意情绪',
'audio': '轻音乐',
'hud': '保持冷静驾驶'
}
elif intensity > 0.6:
return {
'level': 'warning',
'action': '提醒注意分心',
'audio': None,
'hud': '请专注驾驶'
}
else:
return {'level': 'safe', 'action': None, 'audio': None, 'hud': None}

3. 语音情绪识别的工程挑战

挑战 严重程度 解决方案
车内噪声干扰 🔴 高 降噪麦克风+信噪比阈值
驾驶员不说话 🟡 中 回退到视觉模态
方言/口音差异 🟡 中 多语言预训练模型
隐私顾虑 🔴 高 边缘处理+不上传
实时性要求 🟡 中 模型量化+知识蒸馏

4. 部署优先级

优先级 功能 模态 时间
P0 面部表情情绪识别 视频 3个月
P1 情绪强度回归 视频 6个月
P2 语音情绪融合 视频+音频 12个月
P3 情绪干预策略 全模态 18个月

总结

对IMS的5条可执行建议:

  1. 情绪强度连续维度比离散分类更有价值——-0.2和-0.8的驾驶风险完全不同
  2. 视频模态是Phase1首选——音频受车内噪声影响大
  3. 模型级融合优于特征级——多头注意力捕捉跨模态交互
  4. 情绪监测可复用DMS现有摄像头——无需额外硬件
  5. 极端负面情绪是最危险状态——路怒症导致事故率增加数倍

论文链接: https://doi.org/10.3389/fphy.2025.1599428