可解释AI情感识别框架:从黑盒到白盒的驾驶员情绪监测

论文信息


核心创新

这项研究提出了一个可解释的、人类验证的情感识别框架(HER),与当前深度学习黑盒方案形成鲜明对比:

关键差异化

维度 传统深度学习 HER框架
可解释性 ❌ 黑盒 ✅ 符号规则
人类验证 ❌ 众包标签 ✅ 专家标注+验证
算法 深层CNN/Transformer SMO+SVM + J48 + MLP
规则挖掘 无 ✅ Apriori关联规则
表情层级 宏表情 宏+微+微妙表情
透明度 百万参数 可读决策树

技术架构

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
"""
HER: 可解释情感识别框架
论文: Journal of Ambient Intelligence and Humanized Computing, 2026

核心: 经典ML集成 + Apriori规则挖掘 + 人类专家验证
依赖: scikit-learn, mlxtend, numpy
"""

import numpy as np
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import cross_val_score
from mlxtend.frequent_patterns import apriori, association_rules
from typing import Tuple, List, Dict

class HERFramework:
"""
HER: Human Emotion Recognition Framework

三层架构:
1. 特征提取层: 面部动作单元(AU) + 头部姿态 + 视线方向
2. 分类集成层: SMO-SVM + J48决策树 + MLP
3. 规则挖掘层: Apriori关联规则 → 可解释决策

关键创新: 规则层使分类结果可被人类专家审计
"""

def __init__(self, num_au: int = 23, num_emotions: int = 7):
self.num_au = num_au # 23个面部动作单元
self.num_emotions = num_emotions # Ekman 7类情感

# 分类器集成
self.svm = SVC(kernel='rbf', C=1.0, gamma='scale', probability=True)
self.j48 = DecisionTreeClassifier(
criterion='entropy', # C4.5用信息增益
max_depth=10,
min_samples_leaf=5
)
self.mlp = MLPClassifier(
hidden_layer_sizes=(128, 64),
activation='relu',
max_iter=500
)

# 规则存储
self.rules: List[Dict] = []
self.rule_confidence: Dict[str, float] = {}

def extract_features(self, face_landmarks: np.ndarray) -> np.ndarray:
"""
从面部关键点提取特征

输入: 68个关键点 (x, y)
输出: 特征向量 [AU_1, AU_2, ..., AU_23, head_pitch, head_yaw, head_roll, gaze_x, gaze_y]

面部动作单元 (FACS系统):
- AU1: 内眉上提 → 悲伤/恐惧
- AU4: 眉毛下压 → 愤怒
- AU6: 面颊上抬 → 微笑(真笑)
- AU7: 下眼睑收紧 → 厌恶
- AU9: 鼻翼皱起 → 厌恶
- AU12: 嘴角上抬 → 喜悦
- AU15: 嘴角下压 → 悲伤
- AU17: 下巴上抬 → 悲伤
- AU20: 嘴唇拉伸 → 恐惧
- AU23: 嘴唇收紧 → 愤怒
- AU24: 嘴唇压紧 → 愤怒
- AU25: 嘴唇分开 → 惊讶
- AU26: 下巴下垂 → 惊讶
"""
features = np.zeros(self.num_au + 5) # 23 AU + 3 head + 2 gaze

# AU强度估计 (简化: 基于关键点距离)
# AU6 (面颊上抬): 眼角距离变化
features[5] = self._compute_au6(face_landmarks)
# AU12 (嘴角上抬): 嘴角到鼻翼距离
features[11] = self._compute_au12(face_landmarks)
# AU15 (嘴角下压): 嘴角到下巴距离
features[14] = self._compute_au15(face_landmarks)
# ... 其他AU

# 头部姿态
features[self.num_au:self.num_au+3] = self._estimate_head_pose(face_landmarks)

# 视线方向
features[self.num_au+3:self.num_au+5] = self._estimate_gaze(face_landmarks)

return features

def _compute_au6(self, lm: np.ndarray) -> float:
"""AU6: 面颊上抬(眼角距离变化)"""
left_corner = lm[36] # 左眼外角
right_corner = lm[45] # 右眼外角
left_cheek = lm[31] # 左鼻翼
right_cheek = lm[35] # 右鼻翼

# 眼角到嘴角距离变化
return np.linalg.norm(left_corner - left_cheek)

def _compute_au12(self, lm: np.ndarray) -> float:
"""AU12: 嘴角上抬"""
mouth_left = lm[48]
mouth_right = lm[54]
nose_tip = lm[30]

return (np.linalg.norm(mouth_left - nose_tip) +
np.linalg.norm(mouth_right - nose_tip)) / 2

def _compute_au15(self, lm: np.ndarray) -> float:
"""AU15: 嘴角下压"""
mouth_left = lm[48]
mouth_right = lm[54]
chin = lm[8]

return (np.linalg.norm(mouth_left - chin) +
np.linalg.norm(mouth_right - chin)) / 2

def _estimate_head_pose(self, lm: np.ndarray) -> np.ndarray:
"""估计头部姿态 [pitch, yaw, roll]"""
# 简化: 基于关键点几何
pitch = (lm[33][1] - lm[27][1]) / (lm[8][1] - lm[27][1] + 1e-6)
yaw = (lm[39][0] - lm[42][0]) / (lm[0][0] - lm[16][0] + 1e-6)
roll = np.arctan2(lm[45][1] - lm[36][1], lm[45][0] - lm[36][0])
return np.array([pitch, yaw, roll])

def _estimate_gaze(self, lm: np.ndarray) -> np.ndarray:
"""估计视线方向 [x, y]"""
left_eye = lm[36:42]
right_eye = lm[42:48]

left_center = np.mean(left_eye, axis=0)
right_center = np.mean(right_eye, axis=0)

gaze_x = (left_center[0] + right_center[0]) / 2
gaze_y = (left_center[1] + right_center[1]) / 2

return np.array([gaze_x, gaze_y])

def fit(self, X: np.ndarray, y: np.ndarray) -> dict:
"""
训练所有分类器

Args:
X: (N, num_features) 特征矩阵
y: (N,) 情感标签 [0-6]

Returns:
训练结果
"""
# 训练三个分类器
self.svm.fit(X, y)
self.j48.fit(X, y)
self.mlp.fit(X, y)

# 交叉验证
cv_svm = cross_val_score(self.svm, X, y, cv=5)
cv_j48 = cross_val_score(self.j48, X, y, cv=5)
cv_mlp = cross_val_score(self.mlp, X, y, cv=5)

# Apriori规则挖掘
self._mine_rules(X, y)

return {
'svm_cv': cv_svm.mean(),
'j48_cv': cv_j48.mean(),
'mlp_cv': cv_mlp.mean(),
'num_rules': len(self.rules)
}

def _mine_rules(self, X: np.ndarray, y: np.ndarray):
"""
Apriori关联规则挖掘

从特征-标签对中挖掘:
"if AU6_high and AU12_high then emotion=joy (conf=0.95)"
"if AU4_high and AU23_high then emotion=anger (conf=0.88)"
"""
# 离散化特征
X_binned = np.zeros_like(X, dtype=bool)
for i in range(X.shape[1]):
threshold = np.percentile(X[:, i], 70)
X_binned[:, i] = X[:, i] > threshold

# 构建交易表
from mlxtend.preprocessing import TransactionEncoder

transactions = []
for i in range(len(y)):
transaction = [f"AU_{j}" for j in range(X.shape[1]) if X_binned[i, j]]
transaction.append(f"emotion_{y[i]}")
transactions.append(transaction)

# Apriori
te = TransactionEncoder()
te_array = te.fit(transactions).transform(transactions)

frequent_itemsets = apriori(te_array, min_support=0.05, use_colnames=True)

# 生成规则
rules = association_rules(frequent_itemsets, metric="confidence",
min_threshold=0.7)

self.rules = rules.to_dict('records')

def predict_interpretable(self, X: np.ndarray) -> dict:
"""
可解释预测

返回: 情感标签 + 决策路径 + 适用规则
"""
# 分类器预测
svm_pred = self.svm.predict(X)
j48_pred = self.j48.predict(X)
mlp_pred = self.mlp.predict(X)

# 多数投票
predictions = np.array([svm_pred, j48_pred, mlp_pred])
final_pred = np.apply_along_axis(
lambda x: np.bincount(x).argmax(), 0, predictions
)

# J48决策路径 (可解释)
decision_path = self.j48.decision_path(X)

# 匹配的Apriori规则
matched_rules = self._match_rules(X)

return {
'prediction': final_pred,
'svm_pred': svm_pred,
'j48_pred': j48_pred,
'mlp_pred': mlp_pred,
'decision_path': decision_path,
'matched_rules': matched_rules,
'confidence': self._compute_confidence(predictions)
}

def _match_rules(self, X: np.ndarray) -> List[str]:
"""匹配Apriori规则"""
matched = []
for rule in self.rules:
# 检查规则前件是否满足
antecedents = rule.get('antecedents', set())
if self._check_rule_conditions(X, antecedents):
consequents = rule.get('consequents', set())
confidence = rule.get('confidence', 0)
matched.append(
f"IF {antecedents} THEN {consequents} (conf={confidence:.2f})"
)
return matched

def _check_rule_conditions(self, X: np.ndarray, conditions: set) -> bool:
"""检查规则条件是否满足"""
# 简化版
return True

def _compute_confidence(self, predictions: np.ndarray) -> float:
"""计算预测置信度"""
agreement = np.mean(predictions == predictions[0])
return float(agreement)


# Ekman 7类情感
EMOTION_LABELS = {
0: "愤怒 (Anger)",
1: "厌恶 (Disgust)",
2: "恐惧 (Fear)",
3: "喜悦 (Joy)",
4: "悲伤 (Sadness)",
5: "惊讶 (Surprise)",
6: "中性 (Neutral)"
}

if __name__ == "__main__":
# 模拟数据
np.random.seed(42)
N = 200
num_features = 28 # 23 AU + 3 head + 2 gaze

X = np.random.rand(N, num_features)
y = np.random.randint(0, 7, N)

# 训练
her = HERFramework()
results = her.fit(X, y)

print("=== HER框架训练结果 ===")
print(f"SVM准确率: {results['svm_cv']:.3f}")
print(f"J48准确率: {results['j48_cv']:.3f}")
print(f"MLP准确率: {results['mlp_cv']:.3f}")
print(f"挖掘规则数: {results['num_rules']}")

# 预测
test_sample = np.random.rand(1, num_features)
result = her.predict_interpretable(test_sample)

print(f"\n=== 预测结果 ===")
print(f"最终预测: {EMOTION_LABELS.get(result['prediction'][0], 'Unknown')}")
print(f"置信度: {result['confidence']:.2f}")
print(f"匹配规则: {len(result['matched_rules'])}条")
for rule in result['matched_rules'][:3]:
print(f" → {rule}")

2. 三层架构图


情感层级体系

层级 持续时间 特征 检测难度 应用场景
宏表情 0.5-4秒 明显面部变化 ⭐ 低 情绪状态
微表情 0.04-0.5秒 快速泄露 ⭐⭐⭐⭐ 高 欺骗检测
微妙表情 不明显 低强度线索 ⭐⭐⭐⭐⭐ 极高 隐蔽情绪

对IMS驾驶员情绪监测的启示

1. 可解释性的价值

深度学习黑盒方案在车规级认证中面临挑战:

认证要求 黑盒方案 可解释方案
功能安全(ISO 26262) ⚠️ 难以验证 ✅ 规则可审计
可追溯性 ⚠️ 无法解释决策 ✅ 决策路径可查
失效分析 ⚠️ 无法定位 ✅ 规则级定位
法规合规 ⚠️ 无先例 ✅ 逻辑可验证

2. 驾驶场景情感分类

情感 驾驶场景 AU组合 风险等级
愤怒 路怒症 AU4+AU23+AU24 🔴 高
恐惧 紧急情况 AU1+AU2+AU20 🟡 中
悲伤 情绪低落 AU1+AU15+AU17 🟡 中
惊讶 突发事件 AU1+AU2+AU25+AU26 🟡 中
厌恶 不满 AU7+AU9 🟡 低
喜悦 愉悦驾驶 AU6+AU12 🟢 无
疲劳 瞌睡 AU43(闭眼)+AU45(眨眼) 🔴 高

3. 与BiFuseNet的互补

维度 BiFuseNet (ECU) HER框架
方法 3D CNN深度学习 经典ML+规则挖掘
可解释 ❌ 黑盒 ✅ 白盒规则
准确率 88-95% 较低(基础ML)
酒精检测 ✅ ❌
微表情 ⚠️ ✅ 三层级
车规认证 ⚠️ ✅

融合方案: BiFuseNet做主检测器,HER框架做审计层和微表情补充


总结

HER框架的核心价值不在于准确率超越深度学习,而在于:

  • 可解释 — 规则可被人类专家审计和验证
  • 可信任 — 决策路径透明,符合功能安全要求
  • 可扩展 — 新情感类别只需添加规则,不需重训模型
  • 微表情 — 三层级体系覆盖更细粒度的情感信号

对IMS的启示:情绪检测不只是准确率,更是可验证性。车规级DMS需要可审计的决策逻辑。