Skip to content

Satorica/BUAA-LLM-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

考题17、知识点剖析:《注意力机制:大模型 “聚焦关键信息” 的核心逻辑是什么?—— 从“自注意力” 到 “多头注意力” 的原理拆解与代码复现》​ 剥洋葱逻辑:先解释 “为什么需要注意力”(解决 RNN 长序列依赖问题),再拆解自注意 力“QKV 计算” 三步法(Query 生成→Key 匹配→Value 加权),最后扩展多头注意力的 “并 行聚焦” 优势;​ 案例实现:用 PyTorch 手动实现自注意力模块,输入 “我爱北京天安门” 文本,输出每个 字的注意力权重热力图。


一、目标与核心问题

目标:从工程与可解释性上系统比较

  1. 经典 RNN(或 LSTM/GRU)在长序列学习上的缺陷;
  2. 加入(对齐型)注意力如何缓解长依赖并提供可解释的对齐权重;
  3. 自注意力 / 多头注意力(Transformer 风格)如何通过并行化、多尺度关注实现更好性能与更丰富的表征。

研究问题 / 假设

  • 假设 A:在长距离依赖任务(如 copy / long-range language modeling)上,注意力模型胜过纯 RNN。
  • 假设 B:自注意力模型收敛更快、易并行,且多头能学习到不同关注模式(语义/位置/局部)。
  • 假设 C:注意力权重可解释,通过热图能看到合理的对齐(在合成对齐任务上可量化)。

二、实验总体设计(四个阶段 / 四类模型)

  1. Baseline RNN:单层/双层 LSTM(character-level)
  2. RNN + 对齐注意力(Bahdanau 或 Luong):decoder 用 attention 对 encoder 隐状态加权 — 用于 seq2seq 任务(适合对齐可视化)
  3. Self-Attention 单头:手写 QKV (你之前要的“真实 PyTorch 代码”)
  4. Multi-Head Self-Attention(Transformer Encoder Layer):标准多头(比如 4 heads / 8 heads)

对每类模型都在相同数据、相同训练设置下训练并对比。


三、任务与数据集(包含合成任务 + 真实语料)

为全面衡量,建议做 3 种任务:

A. 合成 Long-Range Dependency 任务(可量化对齐)

  • Copy task / Delayed copy:输入一长串 token,模型需复制开头部分到末尾(控制距离)。
  • Matching task:给序列与一个标记,要求模型输出与某个早先位置 token 相关的答案(便于量化注意力对齐的准确率)。 目的:精确测量“长距离依赖”能力与注意力对齐质量(有 ground-truth alignment)。

B. 字符级语言建模(中文)

  • 数据源建议:中文维基百科切片、THUCNews(新闻),或任意中文语料(小规模即可用于教学实验)。
  • 任务:以字符/字为单位做 next-token 预测(cross-entropy),可直接对比 perplexity / token accuracy。 目的:真实语言分布下评测泛化与训练效率。

C. 简单 seq2seq 对齐任务(可视化)

  • 例如汉字替换/翻译任务(短句子对短句子),或 English-Chinese toy 对齐。
  • 方便可视化 attention 矩阵作为对齐热图(比如 “我爱北京天安门” 的输入到 decoder 的 attention)。

四、评价指标(量化 + 可视化)

量化指标

  • 主要:Cross-Entropy Loss, Perplexity(language modeling)
  • 分类/预测任务:Accuracy / F1 / Exact Match(依任务)
  • 长依赖任务:成功率(模型能否正确复制/恢复远距离信息)随距离变化的曲线
  • 训练速度:每 epoch 时间、收敛epoch数(或达到某阈值的 epoch)
  • 资源:GPU 内存占用、前向 / 反向计算耗时

可解释性/注意力指标

  • Attention Entropy(每个 query 的注意力熵,熵低表示更集中)
  • Top-k 覆盖率(ground truth alignment 是否在 top-k attention 中)
  • Attention sparsity(L1/L2)
  • Attention heatmap(示例级别,可视化“我爱北京天安门”)

统计分析

  • 对多次随机 seed 重复实验,报告均值 + 标准差。
  • 显著性检验(t-test)用于主性能差异判定(例如 RNN vs Transformer)。

五、模型实现要点(PyTorch 伪/真实代码片段)

下列提供你需要的核心实现(可直接拷贝运行),包含:LSTM baseline、Bahdanau 注意力的 seq2seq、手写 Self-Attention、Multi-Head 注意力,以及训练/可视化脚手架。

(我会给出可运行的精简实现,便于教学实验与可视化)


1) LSTM baseline(字符级 next-token)

import torch, torch.nn as nn, torch.nn.functional as F

class LSTMModel(nn.Module):
    def __init__(self, vocab_size, embed_dim=128, hidden=256, num_layers=1):
        super().__init__()
        self.embed = nn.Embedding(vocab_size, embed_dim)
        self.lstm = nn.LSTM(embed_dim, hidden, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden, vocab_size)

    def forward(self, x, hidden=None):
        # x: (batch, seq)
        e = self.embed(x)  # (batch, seq, embed_dim)
        out, hidden = self.lstm(e, hidden)  # out: (batch, seq, hidden)
        logits = self.fc(out)  # (batch, seq, vocab)
        return logits, hidden

2) Seq2Seq + Bahdanau(对齐可视化)

(encoder: LSTM,decoder: LSTM + attention)

class BahdanauAttention(nn.Module):
    def __init__(self, hidden_size):
        super().__init__()
        self.W1 = nn.Linear(hidden_size, hidden_size)
        self.W2 = nn.Linear(hidden_size, hidden_size)
        self.V = nn.Linear(hidden_size, 1)

    def forward(self, enc_outputs, dec_hidden):
        # enc_outputs: (batch, seq_enc, hidden)
        # dec_hidden: (batch, hidden)  -- take last layer
        # score = V(tanh(W1*enc + W2*dec))
        dec_hidden_exp = dec_hidden.unsqueeze(1).expand_as(enc_outputs)
        score = self.V(torch.tanh(self.W1(enc_outputs) + self.W2(dec_hidden_exp))).squeeze(-1)
        # score: (batch, seq_enc)
        attn_weights = F.softmax(score, dim=-1)
        context = torch.bmm(attn_weights.unsqueeze(1), enc_outputs).squeeze(1)
        return context, attn_weights  # attn_weights用于可视化

3) 手写 Self-Attention(单头) — 你之前要“真实 PyTorch”

class SelfAttention(nn.Module):
    def __init__(self, embed_dim):
        super().__init__()
        self.embed_dim = embed_dim
        self.W_Q = nn.Linear(embed_dim, embed_dim)
        self.W_K = nn.Linear(embed_dim, embed_dim)
        self.W_V = nn.Linear(embed_dim, embed_dim)

    def forward(self, x):
        # x: (batch, seq, embed)
        Q = self.W_Q(x)
        K = self.W_K(x)
        V = self.W_V(x)
        scores = torch.matmul(Q, K.transpose(-2,-1)) / (self.embed_dim ** 0.5)
        attn = F.softmax(scores, dim=-1)  # (batch, seq, seq)
        out = torch.matmul(attn, V)
        return out, attn

4) Multi-Head Attention(简洁实现)

class MultiHeadAttention(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super().__init__()
        assert embed_dim % num_heads == 0
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads
        self.W_Q = nn.Linear(embed_dim, embed_dim)
        self.W_K = nn.Linear(embed_dim, embed_dim)
        self.W_V = nn.Linear(embed_dim, embed_dim)
        self.fc = nn.Linear(embed_dim, embed_dim)

    def forward(self, x):
        B, T, E = x.size()
        Q = self.W_Q(x).view(B, T, self.num_heads, self.head_dim).transpose(1,2) # (B, H, T, D)
        K = self.W_K(x).view(B, T, self.num_heads, self.head_dim).transpose(1,2)
        V = self.W_V(x).view(B, T, self.num_heads, self.head_dim).transpose(1,2)
        scores = torch.matmul(Q, K.transpose(-2,-1)) / (self.head_dim ** 0.5) # (B, H, T, T)
        attn = F.softmax(scores, dim=-1)
        context = torch.matmul(attn, V) # (B, H, T, D)
        context = context.transpose(1,2).contiguous().view(B, T, E)
        out = self.fc(context)
        return out, attn  # attn: (B, H, T, T)

5) 简单训练 loop (通用骨架)

def train_epoch(model, dataloader, opt, device):
    model.train()
    total_loss = 0.0
    for x, y in dataloader:
        x, y = x.to(device), y.to(device)
        logits, *_ = model(x)
        loss = F.cross_entropy(logits.view(-1, logits.size(-1)), y.view(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
        total_loss += loss.item()
    return total_loss / len(dataloader)

六、可视化:把“我爱北京天安门”的注意力画成热图

下面给出示例脚本:输入句子 -> embedding -> forward 得到 attn -> matplotlib 画 heatmap。

import matplotlib.pyplot as plt
import numpy as np
import torch

def visualize_attention(model, token_ids, id2tok):
    # token_ids: list of ints, model should return attention
    model.eval()
    with torch.no_grad():
        x = torch.tensor(token_ids).unsqueeze(0)  # (1, seq)
        # assume model returns (out, attn) where attn shape is (1, seq, seq) for single head
        out, attn = model.embed_forward_with_attn(x)  # 你需要包装一下模型接口
        attn = attn[0].cpu().numpy()  # (seq, seq)
    
    toks = [id2tok[i] for i in token_ids]
    plt.figure(figsize=(6,5))
    plt.imshow(attn, aspect='auto')
    plt.xticks(range(len(toks)), toks)
    plt.yticks(range(len(toks)), toks)
    plt.colorbar()
    plt.title("Attention Heatmap")
    plt.xlabel("Key / Value positions")
    plt.ylabel("Query positions")
    plt.show()

说明model.embed_forward_with_attn 是示意,你可以在模型 forward 中返回 attn(上面 SelfAttention / MultiHeadAttention 已返回 attn),在语言模型里直接取 attn(batch=1),并绘制。


七、实验具体超参(建议)

  • Batch size: 32(合成任务可用更大)
  • Embedding dim: 128(教学实验)
  • Hidden size(LSTM): 256
  • Multi-head heads: 4 / 8(做对比)
  • Optimizer: Adam lr=1e-3(或 3e-4 for Transformer)
  • Epochs: 20–100 视数据量(合成任务 20 就够)
  • Dropout: 0.1(防过拟合)
  • 随机 seed: 固定 42、重复 3 次实验取平均

八、对比/消融实验建议(必须的)

  1. 序列长度敏感度:固定模型,分别把输入序列长度设为 [20, 50, 100, 200],记录性能随长度的衰减。
  2. 头数 Ablation:multi-head 中分别用 1, 2, 4, 8 heads,看性能和注意力多样性。
  3. Embedding 维度与模型深度:对比 embed dim(64/128/256)和层数(1/2/4)。
  4. 带/不带位置编码(自注意力在没有位置编码时会丢失位置信息) — 比较绝对位置编码与相对位置编码对长依赖的影响。
  5. 噪声鲁棒性:在输入插入噪声 token,看模型能否忽略噪声并关注真正相关位置(衡量 attention 熵与 top-k 覆盖)。

九、结果展示板块(样例)

对每种模型绘制下列图表(横轴为 epoch 或序列长度):

  • 训练/验证 loss 曲线
  • Perplexity 曲线
  • 长依赖成功率随距离变化的曲线(copy task)
  • 注意力熵统计直方图(不同模型比较)
  • 若干示例 attention heatmap(含“我爱北京天安门”)
  • 多头 attention 各头 heatmap(观察每头关注模式差异)

对照表格:列出模型、参数量、训练时间/epoch、最大验证性能、平均 attention entropy。


十、示例结论(你大概率会看到的趋势)

  • LSTM 在短序列表现不错,但随着距离增长性能下降明显(梯度与记忆瓶颈)。
  • 加入对齐注意力的 seq2seq 能显著恢复长距离信息(在 copy/translation 类任务上效果尤其明显),并给出明确的对齐热图。
  • 单头自注意力与多头相比:单头能学习到某一类关系,但多头可以并行捕捉局部(邻域)与全局(长距离)关系,表现更稳定。
  • Transformer(自注意力堆叠)在并行化训练上优势明显(更少的训练 epoch 达成同等性能,且易扩展)。
  • 可视化:在中文短句 “我爱北京天安门” 上,你会看到明显的对称/集中模式(例如“北京”与“天安门”相互关注等),多头会展示不同的关注模式。

十一、可复现性与环境(建议)

  • Python >=3.8,PyTorch >=1.12(或你本地版本)
  • 固定随机种子:torch.manual_seed(42); np.random.seed(42)
  • requirements.txt 示例:
torch
numpy
matplotlib
tqdm
  • 实验日志:使用 TensorBoard / WandB 记录 loss、attention 熵与 heatmaps(建议使用 WandB 以便比较多次运行)。

十二、交付物(我可以立即帮你生成)

  1. 完整的 GitHub 风格实验脚本集:models.pytrain.pydata.pyviz.py
  2. 一份实验报告模板(包含图表与结论段落),便于课堂展示。
  3. 直接可运行的 notebook:从数据准备 → 训练 → 可视化(包含“我爱北京天安门”的注意力热图)。

如果你现在想要我立刻生成其中一个交付物,请选择其中一项(别担心 — 我会直接在当前回复里把代码 / notebook 内容给出):

  • A:完整的最小可运行 PyTorch 脚本(包含 LSTM、Bahdanau attention、SelfAttention、MultiHead,并生成“我爱北京天安门”的热图)
  • B:只要“我爱北京天安门”示例的完整可运行 notebook(包含模型定义、前向、可视化)
  • C:一份详细实验计划文档(Markdown),含表格、对照实验与预期图示(适合直接贴进课件)

告诉我你选哪一个(A/B/C),我马上把相应的代码/文档发给你(全部在本次回复中完成)。

下面给你 最适合做“4 个注意力版本对比实验”的 3~4 个任务 + 对应数据集 + 可使用的评价指标。 这些任务都可以让:

  • Baseline:RNN/LSTM/GRU(无注意力)
  • RNN + Bahdanau/Luong 注意力
  • 单头 Self-Attention
  • Multi-Head Attention / Transformer Encoder

全部参与,并且能体现出注意力机制在 长依赖建模、对齐能力、语义抽取能力 上的性能差异。

内容包括:

  • ✔ 任务是否适合 4 个模型
  • ✔ 推荐数据集(公开、可直接下载)
  • ✔ 每个任务评什么指标(除了 ACC、F1 之外的“深度模型专用指标”)
  • ✔ 推荐实验重点(哪里能看出差异)

任务 1:字符级语言建模(长依赖任务)

非常适合对比 RNN vs Attention,因为字符级语言建模对长距离依赖非常敏感。

推荐数据集

数据集 说明 下载
Penn Treebank (PTB) – Character Level NLP 经典数据集,小巧,适合教学与实验 torchtext 自带
WikiText-2 / WikiText-103 更大规模,可测试 Transformer 的优势 HuggingFace Datasets

⚠ 该任务非常经典,是 Attention = 取代 RNN 的代表性场景


适合所有 4 种模型?

模型 能否胜任 备注
RNN/LSTM/GRU 基线差距大,长依赖失败明显
Bahdanau 注意力 能减轻部分长依赖问题
单头 Self-Attention 明显优于 RNN(全局建模)
Multi-Head Attention 最佳表现

评价指标(除了 ACC/F1)

指标 含义 适用性
Perplexity (PPL) 语言模型的标准指标,越低越好 ⭐ 强推荐
平均序列 Loss 交叉熵
BPC(bits per character) 字符级建模常用指标
长依赖成功率 在距离 d 的 token 是否能预测对 ⭐ 出体现 Attention 优势

实验亮点(非常适合作为论文/课题重点)

  • RNN 的 PPL 会显著比 Transformer 高
  • 随着依赖距离增大(例如隔 50、100 字),RNN 准确率显著下降
  • Self-Attention / Multi-head 基本不下降

这是最容易得到 强对比效果 的任务。


任务 2:序列到序列翻译(seq2seq,注意力的“发源地”)

这是 Bahdanau / Luong 注意力机制的经典应用场景。

推荐数据集

数据集 语言 规模 链接
IWSLT14 De→En / En→De 小规模翻译数据集,适合实验 HuggingFace
Multi30k 图像字幕翻译 + 文本翻译,小巧 HuggingFace
WMT14 En-De 大规模,高难度(可选) 官方网站

适合所有 4 种模型?

模型 能否胜任
RNN baseline
RNN + Bahdanau / Luong ✔ → 最优 (RNN 系)
Self-Attention 单头 ✔ → 会超越 RNN
Multi-Head Transformer ✔ → SOTA

评价指标

指标 解释
BLEU 分数 翻译任务的标准指标(最重要)
NLL / Cross-Entropy Loss
Token-level Accuracy 基本指标
Attention Alignment Score(如果有对齐标签) 测 attention 是否学到真实对齐

实验亮点

  • Bahdanau 注意力能够明显提升 RNN 译码效果
  • 单头 Self-Attention 可能略优于 Bahdanau(取决于模型大小)
  • Multi-Head Transformer 明显胜出(BLEU 最高)

这是最“符合历史发展”的任务,适合写成长篇实验章节。


任务 3:情感分类 / 文本分类(效率与性能皆可展示)

这是最容易训练、最快得到结果、最稳定的任务。

推荐数据集

数据集 内容
IMDB Movie Reviews 二分类情感任务(长文本)
SST-2 二分类,短文本
AG News 四分类

适合所有 4 种模型?

模型 能否胜任
RNN / GRU
RNN + Attention ✔(提升明显)
Single-Head Self-Attn ✔(更强)
Multi-Head Transformer ✔(最好)

评价指标(重点在分类质量 + attention 解释性)

指标 作用
Accuracy / F1 分类性能
AUC(如果是二分类)
Attention Heatmap 可解释性评分 看模型关注的词是否合理
Attention Entropy 注意力集中程度
Inference Latency 测 self-attention 的加速优势(短序列)

实验亮点

  • 情感分类是观察 Attention 可解释性的最佳任务

  • Attention heatmap 能看到模型关注:

    • “好”、“差”、“垃圾”、“完美”等情绪词
  • 比较 4 种 attention:

    • RNN 权重无解释性
    • Bahdanau 对齐常关注动词、情感基词
    • Self-Attention 关注句子全局结构
    • Multi-Head 更稳定/多角度

实验亮点

  • RNN 预测长时间序列时效果明显下降
  • Transformer(尤其是单头/多头)稳定性更强
  • 注意力可视化可以显示模型关注关键时间点

⭐ 最推荐你用的三个任务(按“效果明显、实验易做、差距大”排序)

排名 任务 why
① 字符级语言建模(PTB / WikiText) Attention 对长依赖的优势最大,结果最好看
② 翻译(IWSLT/Multi30k) Attention 发源地,Bahdanau 非常亮眼
③ 文本分类(IMDB/SST-2) 最容易训练,Attention 可视化非常漂亮

⭐ 除了 ACC/F1,你可以比较的“深度模型专用指标”

你问的“除了传统指标还有什么可比较的”,我给你总结最有说服力的:

注意力相关指标(Attention Only)

  • 注意力熵(Attention Entropy)
  • Top-k Coverage(是否关注到关键 token)
  • 对齐准确率(Alignment Accuracy)
  • Head Diversity(头之间的多样性)
  • 注意力集中度(max α / sum α)

模型表现/效率指标

  • Perplexity(语言建模)
  • BLEU(翻译)
  • Inference Latency(推理速度)
  • 显存占用 / 训练速度
  • 收敛速度(N epoch 收敛)

这些指标都能体现 Attention 不只是准确率强,更是效率、可解释性都优越


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors