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
| import torch import torch.nn as nn
class OrdinalEmotionModel(nn.Module): """ 序数情绪识别模型 核心思想:情绪有顺序关系 "非常消极" < "消极" < "中性" < "积极" < "非常积极" 传统分类损失(cross-entropy)忽略顺序 序数损失(CORAL/CORN)保留等级信息 """ def __init__(self, input_dim=128, num_classes=5): super().__init__() self.feature_extractor = nn.Sequential( nn.Linear(input_dim, 256), nn.ReLU(), nn.Dropout(0.3), nn.Linear(256, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, 64) ) self.ordinal_outputs = nn.Linear(64, num_classes - 1) def forward(self, x): """ 输入: EDA+EEG+车辆动力学融合特征 输出: 序数概率 第k个输出 = P(emotion_level > k) """ features = self.feature_extractor(x) logits = self.ordinal_outputs(features) probs = torch.sigmoid(logits) return probs def predict_level(self, x): """从序数概率推断情绪等级""" probs = self.forward(x) levels = torch.zeros(x.shape[0], len(probs[0]) + 1) levels[:, 0] = 1 - probs[:, 0] for k in range(1, len(probs[0])): levels[:, k] = probs[:, k-1] - probs[:, k] levels[:, -1] = probs[:, -1] return levels.argmax(dim=1)
class MultiModalFusion(nn.Module): """多模态融合层""" def __init__(self, eda_dim=16, eeg_dim=64, dyn_dim=48): super().__init__() self.eda_encoder = nn.LSTM(eda_dim, 32, batch_first=True, bidirectional=True) self.eeg_encoder = nn.Conv1d(eeg_dim, 64, kernel_size=3, padding=1) self.dyn_encoder = nn.LSTM(dyn_dim, 32, batch_first=True, bidirectional=True) total_dim = 64 + 64 + 64 self.cross_attention = nn.MultiheadAttention(total_dim, 4, batch_first=True) self.fusion_fc = nn.Sequential( nn.Linear(total_dim, 128), nn.ReLU() ) def forward(self, eda, eeg, dynamics): eda_out, _ = self.eda_encoder(eda) eeg_out = self.eeg_encoder(eeg.transpose(1, 2)).transpose(1, 2) dyn_out, _ = self.dyn_encoder(dynamics) combined = torch.cat([eda_out, eeg_out, dyn_out], dim=2) attended, _ = self.cross_attention(combined, combined, combined) pooled = attended.mean(dim=1) return self.fusion_fc(pooled)
if __name__ == "__main__": model = OrdinalEmotionModel(input_dim=128, num_classes=5) x = torch.randn(32, 128) probs = model(x) levels = model.predict_level(x) print(f"序数概率: {probs.shape}") print(f"预测等级: {levels.shape}")
|