Transformer与RNN对比:为什么它能更好?

RNN 就像一个“记忆机器”,它会把之前的信息传给后面的步骤,就像在读一篇文章时,你会记住前面的内容来理解后面的句子。

优点是能处理序列信息(比如语言中的词序)。缺点是一次只能处理一个词,长序列时容易遗忘早期信息,而且计算起来无法充分并行,效率较低。

但是对于Transformer,它抛弃了“一个词接一个词”的处理方式,而是利用一种叫做“自注意力”(Self-Attention)的机制,让每个词在处理时能“看到”整个句子。这就像同时打开所有的词卡,每个词都可以直接关注其他所有词的内容。优点是可以并行计算,速度快,且捕捉长距离依赖关系更好;缺点则是模型参数较多,对计算资源要求高。

原理部分

RNN

基本结构

对于一个输入序列 ,RNN 通过以下递归公式计算隐藏状态:

其中:

  •  是时刻  的隐藏状态

  •  是时刻  的输入

  •  和  分别为输入和隐藏状态的权重矩阵

  •  为偏置项

输出  可以用下式计算:

其中  是输出权重矩阵, 为偏置。

LSTM 和 GRU(改进版本)

为了解决标准 RNN 在长序列中梯度消失或爆炸的问题,提出了 LSTM(长短期记忆)和 GRU(门控循环单元)。以 LSTM 为例,其核心在于使用多个门控机制来控制信息的遗忘和更新。
LSTM 的主要公式如下:

  1. 遗忘门

  2. 输入门

  3. 候选记忆

  4. 更新记忆单元

  5. 输出门

  6. 隐藏状态更新:其中:

  •  表示 Sigmoid 函数

  •  表示元素级乘法

  •  分别为各门的权重和偏置

Transformer

Transformer 模型完全依赖自注意力机制,不再使用循环结构,其主要组成模块包括多头自注意力机制和前馈神经网络。

自注意力机制

对于输入序列,首先通过线性变换得到查询 、键  和值 :

然后,计算注意力得分:

其中:

  •  为键向量的维度,用于缩放防止数值过大

  • softmax 函数用于归一化每个位置的注意力权重

多头注意力

将自注意力机制扩展到多头注意力,通过并行的多个自注意力计算使得模型可以从多个角度关注不同信息:

其中,每个 head 的计算为:

 分别是第  个头对应的权重矩阵, 是最终的输出投影矩阵。

位置编码(Positional Encoding)

由于 Transformer 没有递归结构,不能直接感知序列中词语的位置,因此需要加入位置编码。常用的正弦和余弦函数构造位置编码:

其中:

  •  表示词在序列中的位置

  •  表示维度索引, 为模型维度

前馈神经网络

在每个 Transformer 层中,除了多头注意力,还有一个位置前馈网络,该网络对每个位置独立作用:

通常使用 ReLU 作为激活函数。

编码器与解码器结构

Transformer 包括编码器(Encoder)和解码器(Decoder)两部分:

  • 编码器: 多层堆叠的自注意力和前馈网络,通过层归一化和残差连接提高训练稳定性。

  • 解码器: 同样是多层堆叠,但在自注意力部分加入了屏蔽机制(masking),以防止模型在生成时看到未来的信息,并且在编码器-解码器注意力中将编码器的输出作为查询键值对。

完整案例

下面给出一个完整的实际案例,包含了虚拟数据集的生成、模型(基于RNN和Transformer)的定义、模型训练过程~

  • RNN 模型(LSTM):本模型主要由嵌入层、单层 LSTM 和全连接层组成。模型会将序列中的每个 token 经过嵌入后输入 LSTM,取最后一个隐藏状态作为特征,再经过全连接层输出分类结果。

  • Transformer 模型:Transformer 模型主要由嵌入层、位置编码、多头自注意力层、前馈神经网络、以及全连接层构成。这里我们利用 PyTorch 内置的 nn.TransformerEncoder 来实现编码器部分。由于 Transformer 不具备序列顺序的固有传递性,因此我们采用正弦和余弦函数构造位置编码,加入到 token 嵌入中。

import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
import random
from sklearn.metrics import confusion_matrix
import seaborn as sns

# 设置随机种子,保证实验可重复性
seed = 42
np.random.seed(seed)
random.seed(seed)
torch.manual_seed(seed)

# 1. 数据集构造

class SyntheticSequenceDataset(Dataset):
    """
    自定义数据集:生成虚拟序列数据,每个序列长度为 seq_length,
    每个元素为整数,范围在 1 到 vocab_size-1 之间(0 保留作 padding)。
    标签生成规则:若序列所有数字之和超过阈值,则标签为 1,否则为 0。
    """
    def __init__(self, num_samples, seq_length=20, vocab_size=50, threshold=500):
        super(SyntheticSequenceDataset, self).__init__()
        self.num_samples = num_samples
        self.seq_length = seq_length
        self.vocab_size = vocab_size
        self.threshold = threshold
        
        self.data = []
        self.labels = []
        for _ in range(num_samples):
            # 随机生成一个序列
            seq = np.random.randint(1, vocab_size, size=seq_length)
            label = 1 if np.sum(seq) > threshold else 0
            self.data.append(seq)
            self.labels.append(label)
        
        self.data = np.array(self.data)
        self.labels = np.array(self.labels)
    
    def __len__(self):
        return self.num_samples
    
    def __getitem__(self, idx):
        return torch.LongTensor(self.data[idx]), self.labels[idx]


# 定义训练集和测试集
train_dataset = SyntheticSequenceDataset(num_samples=1000, seq_length=20, vocab_size=50, threshold=500)
test_dataset = SyntheticSequenceDataset(num_samples=300, seq_length=20, vocab_size=50, threshold=500)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 2. 模型定义

# 2.1 RNN 模型(使用 LSTM)
class LSTMClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_dim, num_layers, num_classes, dropout=0.3):
        super(LSTMClassifier, self).__init__()
        # 嵌入层:将整数序列转换为向量序列
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
        # LSTM 层:多层 LSTM 结构
        self.lstm = nn.LSTM(embed_dim, hidden_dim, num_layers=num_layers, 
                            batch_first=True, dropout=dropout)
        # 全连接层:将 LSTM 的输出映射到类别上
        self.fc = nn.Linear(hidden_dim, num_classes)
    
    def forward(self, x):
        # x shape: (batch_size, seq_length)
        embedded = self.embedding(x)  # (batch_size, seq_length, embed_dim)
        lstm_out, _ = self.lstm(embedded)  # lstm_out: (batch_size, seq_length, hidden_dim)
        # 取序列最后一个时间步的输出作为序列表示
        last_hidden = lstm_out[:, -1, :]  # (batch_size, hidden_dim)
        logits = self.fc(last_hidden)  # (batch_size, num_classes)
        return logits

# 2.2 Transformer 模型
class PositionalEncoding(nn.Module):
    """
    位置编码模块:利用正弦和余弦函数生成位置编码,并与输入嵌入相加。
    """
    def __init__(self, d_model, max_len=5000):
        super(PositionalEncoding, self).__init__()
        pe = torch.zeros(max_len, d_model)  # (max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)  # (max_len, 1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * -(np.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)  # 偶数下标使用正弦函数
        pe[:, 1::2] = torch.cos(position * div_term)  # 奇数下标使用余弦函数
        pe = pe.unsqueeze(0)  # (1, max_len, d_model)
        self.register_buffer('pe', pe)
    
    def forward(self, x):
        # x: (batch_size, seq_length, d_model)
        x = x + self.pe[:, :x.size(1), :]
        return x

class TransformerClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim, num_heads, hidden_dim, num_layers, num_classes, dropout=0.3):
        super(TransformerClassifier, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
        self.pos_encoder = PositionalEncoding(embed_dim)
        encoder_layer = nn.TransformerEncoderLayer(d_model=embed_dim, nhead=num_heads, 
                                                   dim_feedforward=hidden_dim, dropout=dropout, batch_first=True)
        self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
        self.fc = nn.Linear(embed_dim, num_classes)
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x):
        # x shape: (batch_size, seq_length)
        embedded = self.embedding(x)  # (batch_size, seq_length, embed_dim)
        embedded = self.pos_encoder(embedded)  # 加入位置编码
        encoded = self.transformer_encoder(embedded)  # (batch_size, seq_length, embed_dim)
        # 取序列第一个 token 的输出作为全局特征
        feature = encoded[:, 0, :]  # (batch_size, embed_dim)
        feature = self.dropout(feature)
        logits = self.fc(feature)  # (batch_size, num_classes)
        return logits

# 3. 模型训练函数

def train_model(model, train_loader, criterion, optimizer, num_epochs=20, device="cpu"):
    """
    模型训练过程
    参数说明:
        model:待训练模型
        train_loader:训练数据加载器
        criterion:损失函数
        optimizer:优化器
        num_epochs:训练轮数
        device:设备设置
    返回:
        loss_list: 每个 epoch 的平均损失值列表
        acc_list: 每个 epoch 的训练准确率列表
    """
    model.to(device)
    loss_list = []
    acc_list = []
    
    for epoch in range(num_epochs):
        model.train()
        epoch_loss = 0.0
        correct = 0
        total = 0
        
        for batch_x, batch_y in train_loader:
            batch_x, batch_y = batch_x.to(device), torch.LongTensor(batch_y).to(device)
            optimizer.zero_grad()
            outputs = model(batch_x)
            loss = criterion(outputs, batch_y)
            loss.backward()
            optimizer.step()
            
            epoch_loss += loss.item() * batch_x.size(0)
            # 预测类别:取概率最大的类别
            _, predicted = torch.max(outputs.data, 1)
            total += batch_y.size(0)
            correct += (predicted == batch_y).sum().item()
        
        epoch_loss = epoch_loss / total
        accuracy = correct / total
        loss_list.append(epoch_loss)
        acc_list.append(accuracy)
        print("Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.4f}".format(epoch+1, num_epochs, epoch_loss, accuracy))
    
    return loss_list, acc_list

def evaluate_model(model, test_loader, device="cpu"):
    """
    模型评估函数:在测试集上计算准确率并返回真实标签和预测标签列表,用于后续绘制混淆矩阵。
    """
    model.to(device)
    model.eval()
    correct = 0
    total = 0
    all_preds = []
    all_labels = []
    
    with torch.no_grad():
        for batch_x, batch_y in test_loader:
            batch_x, batch_y = batch_x.to(device), torch.LongTensor(batch_y).to(device)
            outputs = model(batch_x)
            _, predicted = torch.max(outputs.data, 1)
            total += batch_y.size(0)
            correct += (predicted == batch_y).sum().item()
            all_preds.extend(predicted.cpu().numpy())
            all_labels.extend(batch_y.cpu().numpy())
    
    accuracy = correct / total
    print("Test Accuracy: {:.4f}".format(accuracy))
    return accuracy, all_labels, all_preds

# 4. 主程序:训练并比较模型
if __name__ == "__main__":
    # 设置设备(如果有 GPU 则使用 GPU)
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print("Using device:", device)
    
    # 定义模型超参数
    vocab_size = 50      # 词汇表大小(包含padding索引0)
    embed_dim = 32       # 嵌入层维度
    hidden_dim = 64      # 隐藏层维度
    num_layers = 2       # LSTM或TransformerEncoder的层数
    num_heads = 4        # Transformer中多头注意力的头数
    num_classes = 2      # 二分类任务
    dropout = 0.3
    num_epochs = 20
    learning_rate = 0.001
    
    # 4.1 训练 LSTM 模型
    print("\nTraining LSTM Model...")
    lstm_model = LSTMClassifier(vocab_size=vocab_size, embed_dim=embed_dim, hidden_dim=hidden_dim, 
                                num_layers=num_layers, num_classes=num_classes, dropout=dropout)
    criterion = nn.CrossEntropyLoss()
    optimizer_lstm = optim.Adam(lstm_model.parameters(), lr=learning_rate)
    
    lstm_loss_list, lstm_acc_list = train_model(lstm_model, train_loader, criterion, optimizer_lstm, 
                                                  num_epochs=num_epochs, device=device)
    
    lstm_test_acc, lstm_true, lstm_pred = evaluate_model(lstm_model, test_loader, device=device)
    
    # 4.2 训练 Transformer 模型
    print("\nTraining Transformer Model...")
    transformer_model = TransformerClassifier(vocab_size=vocab_size, embed_dim=embed_dim, num_heads=num_heads,
                                                hidden_dim=hidden_dim, num_layers=num_layers, 
                                                num_classes=num_classes, dropout=dropout)
    optimizer_transformer = optim.Adam(transformer_model.parameters(), lr=learning_rate)
    
    transformer_loss_list, transformer_acc_list = train_model(transformer_model, train_loader, criterion, optimizer_transformer, 
                                                              num_epochs=num_epochs, device=device)
    
    transformer_test_acc, transformer_true, transformer_pred = evaluate_model(transformer_model, test_loader, device=device)
    
    # 5. 数据分析与图形绘制
  
    plt.figure(figsize=(16, 12))
    
    # 子图1: Loss Curves
    plt.subplot(2, 2, 1)
    epochs = np.arange(1, num_epochs + 1)
    plt.plot(epochs, lstm_loss_list, marker='o', color='red', label="LSTM Loss")
    plt.plot(epochs, transformer_loss_list, marker='s', color='blue', label="Transformer Loss")
    plt.xlabel("Epochs")  
    plt.ylabel("Loss")    
    plt.title("Loss Curves", fontsize=14)  
    plt.legend()
    plt.grid(True)
    
    # 子图2: Accuracy Curves
    plt.subplot(2, 2, 2)
    plt.plot(epochs, lstm_acc_list, marker='o', color='green', label="LSTM Accuracy")
    plt.plot(epochs, transformer_acc_list, marker='s', color='purple', label="Transformer Accuracy")
    plt.xlabel("Epochs")  
    plt.ylabel("Accuracy")  
    plt.title("Accuracy Curves", fontsize=14)  
    plt.legend()
    plt.grid(True)
    
    # 子图3: Final Accuracy Comparison
    plt.subplot(2, 2, 3)
    models = ["LSTM", "Transformer"]
    final_acc = [lstm_test_acc, transformer_test_acc]
    bar_colors = ['orange', 'cyan']
    plt.bar(models, final_acc, color=bar_colors)
    plt.xlabel("Model")  
    plt.ylabel("Test Accuracy")  
    plt.title("Final Accuracy Comparison", fontsize=14)  
    for i, v in enumerate(final_acc):
        plt.text(i, v+0.01, "{:.2f}".format(v), ha='center', fontsize=12)
    
    # 子图4: Confusion Matrix for Transformer Model
    plt.subplot(2, 2, 4)
    cm = confusion_matrix(transformer_true, transformer_pred)
    sns.heatmap(cm, annot=True, fmt="d", cmap="YlGnBu", cbar=True,
                xticklabels=["Pred 0", "Pred 1"], yticklabels=["True 0", "True 1"])
    plt.xlabel("Predicted Labels")  
    plt.ylabel("True Labels")       
    plt.title("Confusion Matrix", fontsize=14)  
    
    plt.tight_layout()
    plt.show()

图片

  1. Loss Curves:从左上角的损失曲线图中,我们可以看到两个模型在训练过程中损失值均在逐渐下降,说明模型在不断学习。不同的是,Transformer 的损失下降可能更平稳,而 LSTM 的下降曲线可能略有波动。

  2. Accuracy Curves:从右上角的准确率曲线图中,可以观察到随着训练轮数增加,两种模型的准确率均在提升,但在部分轮次上 Transformer 模型的准确率更高,这说明 Transformer 在捕捉序列全局信息方面具有一定优势。

  3. Final Accuracy Comparison:从左下角的柱状图中,直观地对比了两种模型在测试集上的最终表现,可以看出 Transformer 模型在测试集上的准确率略高于 LSTM 模型。这一结果与 Transformer 并行计算和全局注意力机制的优势一致。

  4. Confusion Matrix:右下角的混淆矩阵展示了 Transformer 模型在测试集上的预测分布情况。从中可以看出,模型在某些类别上的预测错误较少,而在另一类别上可能存在一定误判。通过该图,我们可以进一步分析模型在不同类别上的表现,进而针对性地进行改进。

最后

总体来说,本案例通过虚拟数据集构建了一个简单的二分类任务,并对 RNN 与 Transformer 两种模型进行了对比。通过详细的代码实现、模型训练以及可视化结果展示,不仅帮助初学者理解两种模型的基本原理,还能直观地看到它们在实际任务中的表现差异。

 一、大模型风口已至:月薪30K+的AI岗正在批量诞生

2025年大模型应用呈现爆发式增长,根据工信部最新数据:

国内大模型相关岗位缺口达47万

初级工程师平均薪资28K(数据来源:BOSS直聘报告)

70%企业存在"能用模型不会调优"的痛点

真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!

二、如何学习大模型 AI ?


🔥AI取代的不是人类,而是不会用AI的人!麦肯锡最新报告显示:掌握AI工具的从业者生产效率提升47%,薪资溢价达34%!🚀

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

1️⃣ 提示词工程:把ChatGPT从玩具变成生产工具
2️⃣ RAG系统:让大模型精准输出行业知识
3️⃣ 智能体开发:用AutoGPT打造24小时数字员工

📦熬了三个大夜整理的《AI进化工具包》送你:
✔️ 大厂内部LLM落地手册(含58个真实案例)
✔️ 提示词设计模板库(覆盖12大应用场景)
✔️ 私藏学习路径图(0基础到项目实战仅需90天)

 

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

*   大模型 AI 能干什么?
*   大模型是怎样获得「智能」的?
*   用好 AI 的核心心法
*   大模型应用业务架构
*   大模型应用技术架构
*   代码示例:向 GPT-3.5 灌入新知识
*   提示工程的意义和核心思想
*   Prompt 典型构成
*   指令调优方法论
*   思维链和思维树
*   Prompt 攻击和防范
*   …

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

*   为什么要做 RAG
*   搭建一个简单的 ChatPDF
*   检索的基础概念
*   什么是向量表示(Embeddings)
*   向量数据库与向量检索
*   基于向量检索的 RAG
*   搭建 RAG 系统的扩展知识
*   混合检索与 RAG-Fusion 简介
*   向量模型本地部署
*   …

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

*   为什么要做 RAG
*   什么是模型
*   什么是模型训练
*   求解器 & 损失函数简介
*   小实验2:手写一个简单的神经网络并训练它
*   什么是训练/预训练/微调/轻量化微调
*   Transformer结构简介
*   轻量化微调
*   实验数据集的构建
*   …

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

*   硬件选型
*   带你了解全球大模型
*   使用国产大模型服务
*   搭建 OpenAI 代理
*   热身:基于阿里云 PAI 部署 Stable Diffusion
*   在本地计算机运行大模型
*   大模型的私有化部署
*   基于 vLLM 部署大模型
*   案例:如何优雅地在阿里云私有部署开源大模型
*   部署一套开源 LLM 项目
*   内容安全
*   互联网信息服务算法备案
*   …

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐