NLP领域————GPT算法

1. GPT 的核心概念

GPT 的全称是Generative Pre-trained Transformer,核心是基于 Transformer 的 Decoder 架构,用自回归方式生成文本,关键概念拆解:

  • Decoder-only 架构:只使用 Transformer 的解码器部分,不依赖编码器;
  • 自回归(Autoregressive):生成文本时,先算第 1 个词的概率→用第 1 个词算第 2 个词的概率→直到生成结束符,核心是 "用过去预测未来";
  • 因果掩码(Causal Mask):保证预测第 i 个词时,只能看到前 i-1 个词,看不到后面的词,符合人类阅读生成逻辑;
  • Softmax 概率输出:每个位置输出词汇表中所有词的概率,选概率最高的作为生成结果。

2.GPT的数学原理

(1)输入嵌入

GPT 的输入是文本 token 的索引,先转成向量,再加上位置编码,因为 Transformer 本身没有时序信息:

  • E(x):Token 嵌入矩阵,把 token 索引转成 d 维向量,d 是模型维度;
  • PE(pos):位置编码,给每个位置pos分配唯一向量,GPT 用的是可学习的位置编码,区别于原始 Transformer 的正弦位置编码;
  • h0:初始输入向量,嵌入 + 位置。
(2)Decoder 层的核心计算

GPT 的 Decoder 由 N 层堆叠而成,每层做两件事:

① 多头因果自注意力(Multi-Head Causal Self-Attention)

先拆分为多个 "注意力头",每个头计算局部注意力,再拼接。

② 前馈网络

注意力输出后,通过两层全连接 + 激活函数,GPT 用 GELU:

③ 层归一化 + 残差连接(稳定训练)

每层的输入和输出做残差连接,且先做层归一化(Pre-LN):

(3)最终生成概率

最后一层输出经过线性变换 + Softmax,得到每个 token 的概率:

  • :映射到词汇表维度的矩阵;
  • :在已知前 t-1 个词的情况下,第 t 个词的概率。

3.GPT的运行代码

接下来简述一个简单的GPT运行代码,只保留核心逻辑,去掉复杂的预训练、优化器等,聚焦生成流程:

模块一:核心库导入

导入 PyTorch 核心库,用于构建神经网络、张量计算,是整个代码的基础框架。

导入 PyTorch 的神经网络模块(nn),包含所有预定义的层,如 Linear、Embedding、LayerNorm和模型基类。

导入 PyTorch 的函数式接口(F),包含常用的激活函数、损失函数、Softmax 等无参数的函数,区别于 nn 中带参数的层。

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

# 超参数(极简版,方便理解)
VOCAB_SIZE = 10000  # 词汇表大小
EMBED_DIM = 128     # 嵌入维度
NUM_HEADS = 4       # 注意力头数
NUM_LAYERS = 2      # Decoder层数
MAX_LEN = 50        # 最大生成长度
模块二:因果多头注意力层
python 复制代码
class CausalSelfAttention(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super().__init__()
        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads  # 每个头的维度
        
        # 定义Q/K/V的线性变换层
        self.q_proj = nn.Linear(embed_dim, embed_dim)
        self.k_proj = nn.Linear(embed_dim, embed_dim)
        self.v_proj = nn.Linear(embed_dim, embed_dim)
        # 多头输出的线性变换层
        self.out_proj = nn.Linear(embed_dim, embed_dim)
        
    def forward(self, x):
        # x: [batch_size, seq_len, embed_dim]
        batch_size, seq_len, _ = x.shape
        
        # 1. 生成Q/K/V:[batch_size, seq_len, embed_dim]
        q = self.q_proj(x)
        k = self.k_proj(x)
        v = self.v_proj(x)
        
        # 2. 拆分多头:[batch_size, num_heads, seq_len, head_dim]
        q = q.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
        k = k.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
        v = v.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
        
        # 3. 计算注意力分数:Q*K^T / sqrt(d_k),[batch_size, num_heads, seq_len, seq_len]
        attn_scores = (q @ k.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32))
        
        # 4. 加因果掩码:让每个位置只能看到前面的词
        # 生成掩码矩阵:下三角为0,上三角为-∞
        mask = torch.tril(torch.ones(seq_len, seq_len)).to(x.device)
        mask = mask.masked_fill(mask == 0, float('-inf'))
        attn_scores = attn_scores + mask
        
        # 5. Softmax归一化,得到注意力权重
        attn_weights = F.softmax(attn_scores, dim=-1)
        
        # 6. 加权求和V,得到注意力输出
        attn_output = attn_weights @ v  # [batch_size, num_heads, seq_len, head_dim]
        
        # 7. 拼接多头:转回[batch_size, seq_len, embed_dim]
        attn_output = attn_output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.embed_dim)
        
        # 8. 输出线性变换
        output = self.out_proj(attn_output)
        return output
模块三:定义Decoder层
python 复制代码
class DecoderLayer(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super().__init__()
        self.attn = CausalSelfAttention(embed_dim, num_heads)
        self.ffn = nn.Sequential(
            nn.Linear(embed_dim, 4 * embed_dim),  # 前馈网络第一层扩维4倍
            nn.GELU(),                            # GPT用的激活函数
            nn.Linear(4 * embed_dim, embed_dim)   # 缩维回原维度
        )
        # 层归一化(Pre-LN,先归一化再计算)
        self.norm1 = nn.LayerNorm(embed_dim)
        self.norm2 = nn.LayerNorm(embed_dim)
        
    def forward(self, x):
        # 1. 注意力层 + 残差连接 + 层归一化
        x = x + self.attn(self.norm1(x))
        # 2. 前馈网络 + 残差连接 + 层归一化
        x = x + self.ffn(self.norm2(x))
        return x
模块四:定义GPT模型
python 复制代码
class MiniGPT(nn.Module):
    def __init__(self, vocab_size, embed_dim, num_heads, num_layers, max_len):
        super().__init__()
        self.vocab_size = vocab_size
        self.embed_dim = embed_dim
        self.max_len = max_len
        
        # 1. Token嵌入层:把token索引转成向量
        self.token_emb = nn.Embedding(vocab_size, embed_dim)
        # 2. 可学习的位置编码(GPT的核心特点之一)
        self.pos_emb = nn.Embedding(max_len, embed_dim)
        
        # 3. 堆叠Decoder层
        self.decoder_layers = nn.Sequential(*[DecoderLayer(embed_dim, num_heads) for _ in range(num_layers)])
        
        # 4. 最终输出层:映射到词汇表维度
        self.final_proj = nn.Linear(embed_dim, vocab_size)
        
    def forward(self, x):
        # x: [batch_size, seq_len],输入是token索引序列
        batch_size, seq_len = x.shape
        
        # 1. Token嵌入:[batch_size, seq_len, embed_dim]
        token_emb = self.token_emb(x)
        # 2. 位置编码:生成0~seq_len-1的位置索引,再转成向量
        pos = torch.arange(0, seq_len, device=x.device).unsqueeze(0).repeat(batch_size, 1)
        pos_emb = self.pos_emb(pos)
        
        # 3. 嵌入+位置编码(核心输入)
        h = token_emb + pos_emb
        
        # 4. 经过所有Decoder层
        h = self.decoder_layers(h)
        
        # 5. 映射到词汇表,输出每个token的概率
        logits = self.final_proj(h)  # [batch_size, seq_len, vocab_size]
        return logits
模块五:定义生成函数
python 复制代码
def generate(self, start_tokens, max_new_tokens):
        # start_tokens: [batch_size, init_seq_len],初始token序列
        self.eval()  # 切换到评估模式
        with torch.no_grad():  # 禁用梯度计算,节省资源
            for _ in range(max_new_tokens):
                # 截取最后max_len个token(防止位置编码越界)
                input_seq = start_tokens[:, -self.max_len:]
                # 前向传播,得到最后一个位置的logits
                logits = self.forward(input_seq)  # [batch_size, seq_len, vocab_size]
                last_logits = logits[:, -1, :]    # 只取最后一个位置的输出
                # Softmax转概率,选概率最高的token(贪心采样)
                next_token = torch.argmax(F.softmax(last_logits, dim=-1), dim=-1).unsqueeze(1)
                # 把新生成的token拼接到输入序列后
                start_tokens = torch.cat([start_tokens, next_token], dim=1)
            return start_tokens
模块六:测试代码
python 复制代码
if __name__ == "__main__":
    # 1. 初始化模型
    model = MiniGPT(VOCAB_SIZE, EMBED_DIM, NUM_HEADS, NUM_LAYERS, MAX_LEN)
    
    # 2. 模拟输入:batch_size=1,初始序列长度=3(token索引为[10, 20, 30])
    start_tokens = torch.tensor([[10, 20, 30]])
    
    # 3. 生成文本:在初始序列后生成10个新token
    generated_tokens = model.generate(start_tokens, max_new_tokens=10)
    
    # 4. 打印结果
    print("初始token序列:", start_tokens.numpy())
    print("生成后的token序列:", generated_tokens.numpy())
运行结果

初始token序列: [[10 20 30]]

生成后的token序列: [[ 10 20 30 3519 2958 7700 3605 31 6336 4467 4838 5154 3128]]

4.结语

  • 核心概念:GPT 是 Decoder-only 架构,靠因果掩码 + 自回归生成文本,关键是 "用过去的词预测下一个词";
  • 核心公式:核心是因果注意力的计算,以及自回归的概率输出;
  • 代码核心:
    • Token 嵌入 + 可学习位置编码是输入基础;
    • 因果多头注意力保证只能看前面的词;
    • 自回归生成是循环拼接新 token,直到达到长度。
相关推荐
小程故事多_802 小时前
破局 LLM 黑盒困局,Phoenix 凭全链路可观测,重构大模型应用工程化落地规则
java·前端·人工智能·重构·aigc
love530love10 小时前
【ComfyUI】解决 ModuleNotFoundError: No module named ‘inference_core_nodes‘ 问题
人工智能·windows·python·comfyui·inference-core
大模型任我行10 小时前
华为:构建特征级LLM编码评测基准
人工智能·语言模型·自然语言处理·论文笔记
Jason_Honey210 小时前
【平安Agent算法岗面试-二面】
人工智能·算法·面试
Godspeed Zhao10 小时前
现代智能汽车中的无线技术106——ETC(0)
网络·人工智能·汽车
恋猫de小郭10 小时前
AGENTS.md 真的对 AI Coding 有用吗?或许在此之前你没用对?
前端·人工智能·ai编程
久邦科技10 小时前
OpenCode 完整入门(安装 + 配置 + 使用 + 模板)
人工智能
zhangshuang-peta11 小时前
模型上下文协议(MCP):演进历程、功能特性与Peta的崛起
人工智能·ai agent·mcp·peta