1. DEAP数据集与情感维度解析
DEAP数据集是情感计算领域最常用的基准数据集之一,记录了32名被试观看40段音乐视频时的脑电信号(EEG)和外围生理信号。这个数据集最特别的地方在于,它用四个连续数值(1-9分)量化了每种情感状态:
- 唤醒度(Arousal):从昏昏欲睡到极度兴奋
- 愉悦度(Valence):从消极负面到积极正面
- 支配度(Dominance):从完全失控到高度掌控
- 喜爱度(Like):从强烈反感到非常喜欢
我第一次处理这个数据集时,发现原始MAT文件的结构很有意思。每个被试文件包含两个关键数组:
data是40×40×8064的三维数组(40段视频×40个信号通道×8064个采样点)labels是40×4的评分矩阵(40段视频×4个情感维度)
实际处理时需要特别注意:
- 后8个通道是非EEG信号(如GSR、呼吸等),建议先剔除
- 采样率已降为128Hz,视频时长约63秒(8064/128≈63)
- 数据已进行过眼电伪迹去除、4-45Hz带通滤波等预处理
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据预处理实战技巧
2.1 信号特征工程
脑电信号的特征提取直接影响模型效果。经过多次实验对比,我推荐使用频带功率特征:
python复制def eeg_power_band(epochs):
FREQ_BANDS = {
"delta": [0.5, 4.5],
"theta": [4.5, 8.5],
"alpha": [8.5, 11.5],
"sigma": [11.5, 15.5],
"beta": [15.5, 30]
}
spectrum = epochs.compute_psd(method='welch', fmin=0.5, fmax=30.)
psds = spectrum.get_data()
psds /= np.sum(psds, axis=-1, keepdims=True) # 归一化
features = []
for band in FREQ_BANDS.values():
band_power = psds[:, :, (freqs >= band[0]) & (freqs < band[1])].mean(axis=-1)
features.append(band_power.reshape(len(psds), -1))
return np.concatenate(features, axis=1)
这个函数会为每个epoch生成160维特征(32通道×5频带)。实测发现:
- alpha波功率与愉悦度正相关
- beta波功率与唤醒度正相关
- theta/delta波在消极情绪中更活跃
2.2 标签编码策略
原始1-9的连续评分需要转化为分类标签。我试过两种方法:
二分法(简单但信息损失大)
python复制binary_label = np.where(raw_labels > 5, 1, 0) # 阈值设为中值5
四分位编码(推荐)
python复制def quantile_encode(labels, n_bins=4):
bins = np.linspace(1, 9, n_bins+1)
return np.digitize(labels, bins) - 1
对于多维度联合分类,可以用笛卡尔积组合。例如将每个维度分为高/低2级,4个维度组合成16类(2^4)。
3. LSTM模型构建详解
3.1 网络架构设计
针对EEG时序特性,我设计了一个双向LSTM网络:
python复制class EmotionLSTM(nn.Module):
def __init__(self, input_size=160, hidden_size=64):
super().__init__()
self.lstm = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=2,
bidirectional=True,
dropout=0.3
)
self.classifier = nn.Sequential(
nn.Linear(hidden_size*2, 32),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(32, num_classes)
)
def forward(self, x):
x, _ = self.lstm(x) # [batch, seq_len, features]
x = x[:, -1, :] # 取最后时间步
return self.classifier(x)
几个关键点:
- 使用双向LSTM捕捉前后文信息
- 最后一层用Dropout防止过拟合
- 只取序列末尾输出进行分类
3.2 处理类别不平衡
DEAP数据存在明显的类别不均衡。我的解决方案是:
- 加权交叉熵损失
python复制class_weights = torch.tensor([1.0, 0.8, ..., 1.2]) # 根据样本数调整
criterion = nn.CrossEntropyLoss(weight=class_weights)
- 过采样少数类
python复制from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler()
X_res, y_res = ros.fit_resample(X, y)
- 分层抽样划分数据集
python复制from sklearn.model_selection import StratifiedShuffleSplit
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2)
4. 训练优化与结果分析
4.1 超参数调优经验
经过网格搜索,这些参数组合效果较好:
| 参数 | 推荐值 | 影响 |
|---|---|---|
| 学习率 | 3e-4 | 太大易震荡,太小收敛慢 |
| Batch Size | 32 | 16-64之间差异不大 |
| 隐藏层大小 | 64 | 超过128易过拟合 |
| LSTM层数 | 2 | 3层以上提升有限 |
| Dropout率 | 0.3-0.5 | 防止过拟合关键 |
建议使用学习率预热:
python复制scheduler = torch.optim.lr_scheduler.LambdaLR(
optimizer,
lr_lambda=lambda epoch: min(epoch/10, 1) # 前10epoch线性增长
)
4.2 典型结果与改进方向
在16分类任务中,我得到的最佳准确率约35%。分析混淆矩阵发现:
- 高唤醒度类别容易混淆
- 中性情绪(各维度中等评分)识别率最低
可能的改进措施:
- 加入注意力机制聚焦关键时间点
- 使用多任务学习同时预测四个维度
- 融合其他生理信号(如GSR、EMG)
训练过程中一个实用技巧是使用TensorBoard监控:
python复制writer = SummaryWriter()
writer.add_scalar('Loss/train', loss.item(), epoch)
writer.add_histogram('LSTM/hidden', lstm_layer.weight_hh, epoch)
这个项目最让我意外的是,简单的频带特征+LSTM就能达到不错的效果。后续尝试更复杂的网络结构(如Transformer)反而容易过拟合。有时候,合适的特征工程比堆叠模型层数更有效。
