模型进阶-自注意力机制概述+双代码实现方案讲解

一句话总结为,自注意力机制可以让模型在处理每个词的时候,动态地关注序列中其他所有词的信息,从而捕捉长距离依赖。

假设要处理一句话:小明打了篮球,因为很喜欢运动。”

在这句话中,“他”指的是“小明”。如果模型要理解“他”的意思,就需要知道“他”和“小明”之间是有关系的,虽然它们在句子中相隔了几个词。即需要引出自注意力机制会在处理“他”这个词时,自动计算出它与句子中其他词(比如“小明”)的关系权重,决定该关注哪些词。

“自注意力机制” (Self-Attention Mechanism)是一种用于神经网络中的机制。核心思想是:在处理一个序列时,模型可以自动学习序列中不同位置之间的关联关系,并且根据这些关系动态调整对不同部分的关注程度。

文末代码为双套代码(python或matlab均可实现),使用LSTM进行时序预测,但是LSTM默认“平均关注所有时间步”是不合理的在很多情况下。引入Self-Attention 层自动学习“关注哪些时间步”。

注释:使用随机数模拟了1000个数据点,18步时间步长,7个维度的数据数组。因此,结果展示中不太理想并不是模型问题,而是选择数据问题。

工作流程(大白话版本

1、输入嵌入(Embedding)

每个词会被转成一个向量。

2、计算注意力权重

对每对词之间,模型计算它们的“相似度”或“相关性”。

公式上,通常通过“查询(Query)”、“键(Key)”、“值(Value)”向量来计算注意力分数。

3、加权求和

每个词的新表示是它对所有其他词的加权平均(根据注意力权重)。

4、输出

得到一个融合了全局信息的新序列表示。

自 Transformer (Vaswani et al., 2017)开始,各种自注意力机制层出不穷,具体的体现为复杂度越来越低、长依赖捕捉越来越好、逐渐 适用于各种领域。下表为自行收集的近年来不同的“变种”或“优化版本”的自注意力机制

名称

概述

适用范围

代表(发布年份)

标准自注意力 (Vanilla Self-Attention / Full Attention)

每个 token 对所有 token  attention,使用 Scaled Dot-Product 公式,复杂度 O(N²)

NLPCV

Transformer (Vaswani et al., 2017)

多头自注意力 (Multi-Head Self-Attention)

多头并行学习不同注意力模式,增强表达能力

NLPCV、语音

Transformer, BERT (Devlin et al., 2018), GPT (2018-2020)

稀疏注意力 (Sparse Attention)

只计算一部分注意力,减少计算复杂度

长序列 NLPDNA分析

Sparse Transformer (2019), Longformer (2020), Big Bird (2020)

线性注意力 (Linear Attention)

把复杂度降到 O(N),适合超长序列

超长序列 NLP、日志分析

Performer (2020), Linformer (2020)

卷积式注意力 (Convolutional Attention)

部分 attention 用卷积代替,提升速度

语音、实时系统

Synthesizer (2020), Conformer (2020)

记忆增强注意力 (Memory-Augmented Attention)

引入外部记忆,增强长期依赖建模

超长文本、视频理解

Transformer-XL (2019), Compressive Transformer (2020)

图注意力 (Graph Attention, GAT)

在图结构上使用注意力机制

图神经网络 (GNN)、社交网络

GAT (Velickovic et al., 2018)

视觉自注意力 (Vision Self-Attention)

把图像划分成 patch,做自注意力建模

图像识别、检测

Vision Transformer (ViT, 2020), Swin Transformer (2021)

交叉注意力 (Cross Attention)

一个序列对另一个序列做 attention,跨模态

Encoder-Decoder、跨模态

Transformer Encoder-Decoder (2017), Diffusion Models (2021-2022)

实际操作

LSTM → Self-Attention → Dense

 

 

%% 1️⃣ 生成随机时间序列输入特征
clc; clear;

numSamples = 1000; % 样本数量
timeSteps = 18; % 时间步 n
numFeatures = 7; % 特征数

% 模拟输入特征 [numSamples x timeSteps x numFeatures]
X = rand(numSamples, timeSteps, numFeatures);

% 模拟目标输出(比如SWH)
Y = rand(numSamples,1); % SWH,标量

%% 2️⃣ 构建 LSTM + Self-Attention + Dense 网络
layers = [ ...
sequenceInputLayer(numFeatures)
% LSTM层
lstmLayer(64,'OutputMode','last')

% Self-Attention 层 (用 multiHeadAttentionLayer 或自己实现,简化这里写 fullyConnected)
% 如果有较新版本Matlab可以用 multiHeadAttentionLayer
fullyConnectedLayer(64) % 代替 attention 层,核心思想是聚合
% Dense层
fullyConnectedLayer(32)
reluLayer
fullyConnectedLayer(1) % 输出 SWH (标量)
regressionLayer
];

%% 3️⃣ 配置训练选项
options = trainingOptions('adam', ...
'MaxEpochs',30, ...
'MiniBatchSize', 32, ...
'InitialLearnRate',1e-3, ...
'GradientThreshold',1, ...
'Shuffle','every-epoch', ...
'Plots','training-progress', ...
'Verbose',false);

%% 4️⃣ 转换数据格式 → cell array(sequenceInput需要 cell 格式)
XCell = cell(numSamples,1);
for i = 1:numSamples
XCell{i} = squeeze(X(i,:,:))'; % 转置成 [numFeatures x timeSteps]
end

%% 5️⃣ 训练网络
net = trainNetwork(XCell,Y,layers,options);

%% 6️⃣ 提取 LSTM 中间特征用于 Random Forest 特征重要性评估
% 这里用 activations 函数提取 LSTM 层的输出
featureLayer = 'lstm'; % LSTM 层名字 (你可以改名或用 layerGraph)

% 提取 LSTM 层的输出(取最后一个时间步的状态作为整体特征)
features = zeros(numSamples,64);
for i = 1:numSamples
lstmOut = activations(net,XCell{i},'lstm','OutputAs','channels');
% 取最后时间步
features(i,:) = lstmOut(:,end);
end

%% 7️⃣ 用 Random Forest 评估特征重要性
% 用 LSTM 输出特征预测 SWH,评估特征重要性
numTrees = 100;
RF = TreeBagger(numTrees,features,Y,'Method','regression','OOBPrediction','on','OOBPredictorImportance','on');

% 画特征重要性
figure;
bar(RF.OOBPermutedPredictorDeltaError);
xlabel('LSTM 特征维度');
ylabel('特征重要性');
title('Random Forest 评估特征重要性');
grid on;

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
import warnings

warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 1️⃣ 数据准备
num_samples = 1000
time_steps = 18
num_features = 7

# 生成随机输入 [num_samples, time_steps, num_features]
X = np.random.rand(num_samples, time_steps, num_features).astype(np.float32)

# 生成随机目标 SWH
Y = np.random.rand(num_samples, 1).astype(np.float32)

# 转成 PyTorch Tensor
X_tensor = torch.tensor(X)
Y_tensor = torch.tensor(Y)


# 2️⃣ 定义 LSTM + Self-Attention + Dense 网络
class LSTM_Attention_Net(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(LSTM_Attention_Net, self).__init__()
        self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)

        # Self-Attention 参数
        self.attention = nn.Linear(hidden_dim, 1)

        # Dense 层
        self.fc1 = nn.Linear(hidden_dim, 32)
        self.fc2 = nn.Linear(32, output_dim)

    def forward(self, x):
        # LSTM
        lstm_out, _ = self.lstm(x)  # [batch, time_steps, hidden_dim]

        # Attention 权重
        attn_weights = torch.softmax(self.attention(lstm_out), dim=1)  # [batch, time_steps, 1]

        # 加权求和
        attn_output = torch.sum(attn_weights * lstm_out, dim=1)  # [batch, hidden_dim]

        # Dense
        out = torch.relu(self.fc1(attn_output))
        out = self.fc2(out)

        return out, attn_weights


# 超参数
input_dim = num_features
hidden_dim = 64
output_dim = 1

# 实例化模型
model = LSTM_Attention_Net(input_dim, hidden_dim, output_dim)

# 损失函数 & 优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)

# 3️⃣ 训练模型
num_epochs = 50
batch_size = 32

loss_list = []

for epoch in range(num_epochs):
    permutation = torch.randperm(num_samples)

    for i in range(0, num_samples, batch_size):
        indices = permutation[i:i + batch_size]
        batch_X = X_tensor[indices]
        batch_Y = Y_tensor[indices]

        optimizer.zero_grad()
        outputs, _ = model(batch_X)
        loss = criterion(outputs, batch_Y)
        loss.backward()
        optimizer.step()

    loss_list.append(loss.item())
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}")

# 4️⃣ 可视化训练过程
plt.figure(figsize=(8, 5))
sns.lineplot(x=range(num_epochs), y=loss_list)
plt.title("Training Loss")
plt.xlabel("Epoch")
plt.ylabel("MSE Loss")
plt.grid(True)
plt.show()

# 5️⃣ 用 LSTM 特征喂给 RF 评估特征重要性
# 提取 LSTM 最后时间步的输出
with torch.no_grad():
    lstm_out, _ = model.lstm(X_tensor)
    # 取最后时间步
    lstm_features = lstm_out[:, -1, :].numpy()

# 用 RF 评估
rf = RandomForestRegressor(n_estimators=100)
rf.fit(lstm_features, Y)

# 画特征重要性
plt.figure(figsize=(10, 6))
sns.barplot(x=np.arange(hidden_dim), y=rf.feature_importances_)
plt.title("Random Forest Feature Importance (LSTM features)")
plt.xlabel("LSTM hidden unit")
plt.ylabel("Importance")
plt.grid(True)
plt.show()

# 6️⃣ 可视化 Attention 权重 (对一个 batch 画 heatmap)
with torch.no_grad():
    _, attn_weights = model(X_tensor)
    attn_weights_np = attn_weights.squeeze(-1).numpy()  # [batch, time_steps]

# 取前 10 个样本画 attention heatmap
plt.figure(figsize=(12, 6))
sns.heatmap(attn_weights_np[:10], cmap="viridis", annot=True, cbar=True)
plt.title("Self-Attention Weights (First 10 samples)")
plt.xlabel("Time Steps")
plt.ylabel("Samples")
plt.show()

# 7️⃣ 预测效果可视化
with torch.no_grad():
    Y_pred, _ = model(X_tensor)
    Y_pred_np = Y_pred.numpy()
    Y_true_np = Y

plt.figure(figsize=(6, 6))
sns.scatterplot(x=Y_true_np.squeeze(), y=Y_pred_np.squeeze())
plt.plot([0, 1], [0, 1], 'r--')
plt.title("Predicted vs True SWH")
plt.xlabel("True SWH")
plt.ylabel("Predicted SWH")
plt.grid(True)
plt.show()

# 8️⃣ 打印 R2 和 MSE
mse = mean_squared_error(Y_true_np, Y_pred_np)
r2 = r2_score(Y_true_np, Y_pred_np)
print(f"MSE: {mse:.4f}, R2: {r2:.4f}")

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值