EEG 疲劳检测框架 AXELLSTM 论文解读:可穿戴设备的认知分心监测突破

EEG 疲劳检测框架 AXELLSTM 论文解读

论文信息

  • 标题: An EEG-based Fatigue Detection Framework Integrating Interpretable Feature Selection and Efficient Temporal Modeling
  • 期刊: Frontiers in Neuroscience
  • 年份: 2026
  • 链接: 10.3389/fnins.2026.1903252

核心创新

首次提出 AXELLSTM 框架,实现:

  1. 可解释特征选择:18 通道 EEG 特征重要性排序
  2. 高效时序建模:EfficientLSTM 轻量化设计
  3. 跨主体泛化:LOSO 验证 74.5% 准确率
  4. 边缘部署友好:0.196M 参数,0.75MB 模型

研究背景

EEG 疲劳检测挑战

挑战 说明
通道冗余 64+ 通道数据量大
个体差异 跨主体泛化困难
实时性要求 边缘设备算力有限
可解释性差 黑盒模型难以信任

为什么选择 EEG?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# EEG vs 视觉疲劳检测对比
COMPARISON = {
"EEG": {
"latency": "1-3秒", # 更早预警
"cognitive": "直接测量", # 认知疲劳
"privacy": "无图像", # 隐私友好
"limitation": "需佩戴设备"
},
"视觉": {
"latency": "3-10秒",
"cognitive": "间接推断",
"privacy": "涉及人脸",
"limitation": "受光照影响"
}
}

AXELLSTM 框架设计

整体架构

graph TB
    A[原始 EEG] --> B[预处理]
    B --> C[特征提取]
    C --> D[特征选择]
    D --> E[特征压缩]
    E --> F[Bi-LSTM]
    F --> G[注意力机制]
    G --> H[疲劳分类]

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
# eeg_feature_extraction.py
import numpy as np
from scipy.signal import welch
from scipy.integrate import simps

class EEGFeatureExtractor:
"""
EEG 特征提取器

提取频域和时域特征
"""

# EEG 频段定义
BANDS = {
"delta": (0.5, 4),
"theta": (4, 8),
"alpha": (8, 13),
"beta": (13, 30),
"gamma": (30, 45)
}

def __init__(self, sampling_rate: int = 256):
self.fs = sampling_rate

def extract_features(self, eeg_signal: np.ndarray) -> np.ndarray:
"""
提取特征

Args:
eeg_signal: EEG 信号 (channels, time)

Returns:
features: 特征向量
"""
features = []

for channel in range(eeg_signal.shape[0]):
signal = eeg_signal[channel]

# 1. PSD 特征(功率谱密度)
psd_features = self.extract_psd(signal)
features.extend(psd_features)

# 2. 统计特征
stat_features = self.extract_statistics(signal)
features.extend(stat_features)

# 3. 非线性特征
nonlinear_features = self.extract_nonlinear(signal)
features.extend(nonlinear_features)

return np.array(features)

def extract_psd(self, signal: np.ndarray) -> list:
"""提取功率谱密度特征"""
# Welch 方法估计 PSD
freqs, psd = welch(signal, self.fs, nperseg=256)

psd_features = []

# 各频段功率
for band_name, (f_low, f_high) in self.BANDS.items():
idx_band = np.logical_and(freqs >= f_low, freqs <= f_high)

# 带宽功率
band_power = simps(psd[idx_band], freqs[idx_band])
psd_features.append(band_power)

# 相对功率
total_power = simps(psd, freqs)
relative_power = band_power / total_power if total_power > 0 else 0
psd_features.append(relative_power)

return psd_features

def extract_statistics(self, signal: np.ndarray) -> list:
"""提取统计特征"""
return [
np.mean(signal),
np.std(signal),
np.var(signal),
np.max(signal) - np.min(signal), # 峰峰值
np.percentile(signal, 75) - np.percentile(signal, 25), # IQR
np.median(signal)
]

def extract_nonlinear(self, signal: np.ndarray) -> list:
"""提取非线性特征"""
# Hjorth 参数
activity = np.var(signal)
mobility = np.sqrt(np.var(np.gradient(signal)) / activity) if activity > 0 else 0
complexity = (np.var(np.gradient(np.gradient(signal))) / np.var(np.gradient(signal))) / mobility if mobility > 0 else 0

return [activity, mobility, complexity]

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
# feature_selection.py
import numpy as np
from sklearn.feature_selection import mutual_info_classif
from sklearn.ensemble import RandomForestClassifier

class InterpretableFeatureSelector:
"""
可解释特征选择器

论文方法:结合统计检验和机器学习重要性
"""

def __init__(self, n_features: int = 18):
self.n_features = n_features
self.selected_channels = None
self.feature_importance = None

def fit(self, X: np.ndarray, y: np.ndarray):
"""
选择特征

Args:
X: 特征矩阵 (samples, features)
y: 标签 (samples,)
"""
# 1. 互信息得分
mi_scores = mutual_info_classif(X, y)

# 2. 随机森林重要性
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)
rf_importance = rf.feature_importances_

# 3. 综合得分
combined_scores = 0.5 * mi_scores + 0.5 * rf_importance

# 4. 选择 top-k 特征
top_indices = np.argsort(combined_scores)[-self.n_features:]

self.selected_channels = top_indices
self.feature_importance = combined_scores

return self

def transform(self, X: np.ndarray) -> np.ndarray:
"""选择特征子集"""
return X[:, self.selected_channels]


# 论文发现的 18 个关键通道
PAPER_CHANNELS = {
"left_frontal": ["F8", "F6", "F4", "F3", "F2", "Fp1"],
"right_frontal": ["AF8"],
"temporal": ["TP8", "FT10", "FT9", "FT8"],
"central": ["C5", "CP4", "FC6"],
"parietal": ["P7", "P3"],
"occipital": ["O1"]
}

# 共 18 通道:F8, AF8, TP8, F2, Fp1, F4, FT10, F6, Fz, P7, FT9, O1, C5, FT8, CP4, F3, FC6, P3

3. EfficientLSTM 模型

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
# efficient_lstm.py
import torch
import torch.nn as nn

class EfficientLSTM(nn.Module):
"""
EfficientLSTM 模型

论文核心设计:
1. 特征压缩模块
2. 双向 LSTM
3. 通道注意力
4. 时间注意力
"""

def __init__(self, config: dict):
super().__init__()

input_size = config.get("input_size", 18) # 18 通道
hidden_size = config.get("hidden_size", 64)
num_layers = config.get("num_layers", 2)
num_classes = config.get("num_classes", 2) # 疲劳/正常

# 1. 特征压缩模块
self.feature_compressor = nn.Sequential(
nn.Linear(input_size, hidden_size),
nn.BatchNorm1d(hidden_size),
nn.ReLU(),
nn.Dropout(0.3)
)

# 2. 双向 LSTM
self.bilstm = nn.LSTM(
input_size=hidden_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
bidirectional=True,
dropout=0.3
)

# 3. 通道注意力
self.channel_attention = nn.Sequential(
nn.Linear(hidden_size * 2, hidden_size // 4),
nn.ReLU(),
nn.Linear(hidden_size // 4, hidden_size * 2),
nn.Softmax(dim=-1)
)

# 4. 时间注意力
self.temporal_attention = nn.Sequential(
nn.Linear(hidden_size * 2, hidden_size // 4),
nn.ReLU(),
nn.Linear(hidden_size // 4, 1),
nn.Softmax(dim=1)
)

# 5. 分类器
self.classifier = nn.Sequential(
nn.Linear(hidden_size * 2, hidden_size),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(hidden_size, num_classes)
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
前向传播

Args:
x: 输入 (batch, seq_len, features)

Returns:
output: 分类结果 (batch, num_classes)
"""
batch_size, seq_len, features = x.shape

# 1. 特征压缩
x = x.view(-1, features)
x = self.feature_compressor(x)
x = x.view(batch_size, seq_len, -1)

# 2. BiLSTM
lstm_out, _ = self.bilstm(x) # (batch, seq, hidden*2)

# 3. 通道注意力
channel_weights = self.channel_attention(lstm_out.mean(dim=1))
lstm_out = lstm_out * channel_weights.unsqueeze(1)

# 4. 时间注意力
temporal_weights = self.temporal_attention(lstm_out)
weighted_out = (lstm_out * temporal_weights).sum(dim=1)

# 5. 分类
output = self.classifier(weighted_out)

return output


# 模型统计
def count_parameters(model):
return sum(p.numel() for p in model.parameters() if p.requires_grad)

# 论文模型参数
model = EfficientLSTM({"input_size": 18, "hidden_size": 64})
print(f"参数量: {count_parameters(model):.3f}M") # 0.196M
print(f"模型大小: {count_parameters(model) * 4 / 1024 / 1024:.2f}MB") # 0.75MB

实验结果

数据集

数据集 说明
样本量 30 名被试
通道数 32 通道 EEG
采样率 256 Hz
时长 每人 2 小时
标签 疲劳/正常

性能对比

模型 Macro-F1 参数量 LOSO 准确率
EfficientLSTM 74.5% 0.196M 74.5%
LSTM 71.2% 0.820M 71.2%
CNN-LSTM 72.8% 1.240M 70.5%
Transformer 73.1% 2.560M 69.8%

关键通道重要性排序

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
# 论文发现的通道重要性
CHANNEL_IMPORTANCE = {
"F8": 0.089, # 最高
"AF8": 0.076,
"TP8": 0.072,
"F2": 0.068,
"Fp1": 0.065,
"F4": 0.062,
"FT10": 0.058,
"F6": 0.055,
"Fz": 0.052,
"P7": 0.049,
"FT9": 0.046,
"O1": 0.043,
"C5": 0.040,
"FT8": 0.038,
"CP4": 0.035,
"F3": 0.033,
"FC6": 0.031,
"P3": 0.028
}

# 大脑区域分布
BRAIN_REGIONS = {
"额叶 (Frontal)": ["F8", "AF8", "F2", "Fp1", "F4", "F6", "Fz", "F3", "FC6"],
"颞叶 (Temporal)": ["TP8", "FT10", "FT9", "FT8"],
"顶叶 (Parietal)": ["P7", "CP4", "P3"],
"枕叶 (Occipital)": ["O1"],
"中央 (Central)": ["C5"]
}

结论: 疲劳相关信息主要分布在额叶、额极、颞叶、顶叶和枕叶区域。


边缘部署实现

ONNX 导出

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
# export_onnx.py
import torch

# 加载模型
model = EfficientLSTM({"input_size": 18, "hidden_size": 64})
model.load_state_dict(torch.load("axellstm_best.pt"))
model.eval()

# 导出 ONNX
dummy_input = torch.randn(1, 128, 18) # (batch, seq_len, features)

torch.onnx.export(
model,
dummy_input,
"axellstm.onnx",
input_names=["eeg_features"],
output_names=["fatigue_prob"],
dynamic_axes={
"eeg_features": {0: "batch_size", 1: "seq_len"},
"fatigue_prob": {0: "batch_size"}
},
opset_version=11
)

print("ONNX 导出完成")

TensorRT 优化

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
# tensorrt_inference.py
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
import numpy as np

class AXELLSTMTRT:
"""
TensorRT 推理类
"""

def __init__(self, engine_path: str):
self.logger = trt.Logger(trt.Logger.INFO)
self.engine = self.load_engine(engine_path)
self.context = self.engine.create_execution_context()

def infer(self, eeg_features: np.ndarray) -> float:
"""
推理

Args:
eeg_features: (seq_len, 18)

Returns:
fatigue_prob: 疲劳概率
"""
# 准备输入
input_tensor = eeg_features.astype(np.float32)
input_tensor = np.expand_dims(input_tensor, 0) # (1, seq_len, 18)

# 分配内存
input_size = input_tensor.nbytes
output_size = 2 * 4 # 2 classes * 4 bytes

# 推理
output = self.context.execute_v2([input_tensor])

# 后处理
fatigue_prob = output[0][1] # 疲劳类别概率

return fatigue_prob

IMS 应用启示

1. EEG 作为 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
# multi_modal_dms.py
class MultiModalDMS:
"""
多模态 DMS

结合视觉 + EEG 提高疲劳检测精度
"""

def __init__(self):
self.visual_dms = VisualDMS() # YOLO26
self.eeg_dms = EEGDMS() # AXELLSTM

def detect_fatigue(self, frame, eeg_signal):
"""
多模态疲劳检测

Args:
frame: 视频帧
eeg_signal: EEG 信号

Returns:
fatigue_level: 0-3 疲劳等级
"""
# 视觉检测
visual_result = self.visual_dms.detect(frame)

# EEG 检测
eeg_result = self.eeg_dms.detect(eeg_signal)

# 融合
fatigue_prob = 0.6 * visual_result["probability"] + 0.4 * eeg_result["probability"]

# 等级判定
if fatigue_prob > 0.8:
return 3 # 严重疲劳
elif fatigue_prob > 0.6:
return 2 # 中度疲劳
elif fatigue_prob > 0.4:
return 1 # 轻度疲劳
else:
return 0 # 正常

2. 可穿戴 EEG 设备选择

设备 通道数 价格 适用场景
Muse S 7 $400 消费级
Emotiv Epoc X 14 $849 研究级
NeuroSky MindWave 1 $100 入门级
OpenBCI 16 $999 开源 DIY

3. 部署建议

1
2
3
4
5
6
7
8
9
10
# 部署配置
DEPLOYMENT_CONFIG = {
"hardware": "Jetson Orin Nano",
"model": "axellstm_int8.engine",
"latency": "15ms",
"power": "5W",
"channels": 18,
"seq_length": 128, # 0.5 秒 @ 256Hz
"update_rate": 2 # Hz
}

总结

AXELLSTM 核心优势

优势 说明
轻量化 0.196M 参数,边缘友好
可解释 18 通道明确重要性排序
泛化好 LOSO 验证 74.5%
实时性 15ms 延迟

IMS 应用建议

场景 方案
高级车辆 视觉 + EEG 融合
商用车辆 EEG 可穿戴设备
车队管理 EEG 远程监控

结论: AXELLSTM 是 EEG 疲劳检测的突破性框架,为认知分心检测提供了可解释、可部署的解决方案。


EEG 疲劳检测框架 AXELLSTM 论文解读:可穿戴设备的认知分心监测突破
https://dapalm.com/2026/07/13/2026-07-13-eeg-fatigue-detection-axellstm-framework-paper-review/
作者
Mars
发布于
2026年7月13日
许可协议