大家好,我是你们的技术伙伴。👋
在2026年的今天,当我们谈论AI翻译时,往往会被Transformer架构的光芒所吸引。然而,在那些庞大的模型背后,有一套经典且优雅的架构至今仍在特定领域发光发热------Seq2Seq(Sequence to Sequence)模型。
更重要的是,想要真正吃透现在的主流大模型,我们必须理解Attention(注意力)机制 和底层的矩阵运算。
今天,我不讲那些虚无缥缈的理论,我们来一场 "显微镜"级的代码实战。我们将从最基础的张量乘法开始,一步步搭建一个能将英文翻译成法文的AI系统。
准备好了吗?让我们开始吧!🚀
🔢 第一章:基石------深入理解批量矩阵乘法 (bmm)
在进入复杂的神经网络之前,我们必须先搞懂PyTorch中的两个"乘法"函数:torch.matmul 和 torch.bmm。这不仅是面试高频考点,更是理解后续Attention机制的关键。
1. matmul vs bmm:通用与专用的较量
torch.matmul:它是通用的"瑞士军刀",能处理各种维度的张量,支持广播机制(Broadcasting)。但在处理明确的3D张量(批量数据) 时,它可能会因为过于灵活而牺牲效率。torch.bmm(Batch Matrix Multiply) :它是专门处理3D张量 的"特种兵"。格式严格为(batch_size, n, m) * (batch_size, m, p)。在处理RNN、Transformer等序列数据时,它效率更高,且不支持广播,这反而能帮我们避免很多维度上的低级错误。
2. 代码实证:看它们如何处理数据
假设我们有一个批次(Batch)的数据,包含10个矩阵,每个矩阵是3x4;我们要将其与另一个10个矩阵(每个4x5)相乘。
python
import torch
# 1. 准备数据
# input: 10个 3x4 的矩阵
input = torch.randn(10, 3, 4)
# mat2: 10个 4x5 的矩阵
mat2 = torch.randn(10, 4, 5)
# 2. 使用 matmul (通用方案)
res1 = torch.matmul(input, matim2)
print(f'matmul 结果形状: {res1.shape}')
# 输出: torch.Size([10, 3, 5])
# 3. 使用 bmm (专用方案)
res2 = torch.bmm(input, mat2)
print(f'bmm 结果形状: {res2.shape}')
# 输出: torch.Size([10, 3, 5])
💡 核心洞察:
虽然结果一样,但bmm明确告诉阅读代码的人:"我这里处理的是批量数据,且批次对齐"。在后续的Attention计算中,我们将大量使用bmm来计算权重与值(Value)的乘积。
🧠 第二章:灵魂------手写 Attention 机制 (QKV揭秘)
Attention机制是Seq2Seq模型从"平庸"走向"强大"的转折点。很多同学被QKV(Query, Key, Value)搞晕了,其实用一句话解释就是:
- Query (查询) :我现在在看的词(比如翻译时的当前目标词)。
- Key (键) :源句子中所有待匹配的词。
- Value (值) :源句子中对应的真正内容。
通俗比喻: 就像查字典。Query是你想查的字,Key是字典目录里的字,Value是字的解释。Attention就是帮你快速找到"目录"并翻到对应"解释"的过程。
1. 核心代码实现
基于文档中的逻辑,我们自定义一个MyAtt类,不依赖任何高级API,纯手写Attention流程。
ini
import torch
import torch.nn as nn
import torch.nn.functional as F
class MyAttention(nn.Module):
def __init__(self, query_size, key_size, value_size1, value_size2, output_size):
super().__init__()
# 1. 注意力权重计算层:将 Q 和 K 拼接后打分
# 输入维度: query + key, 输出维度: 源序列长度 (即有多少个Key)
self.attn = nn.Linear(query_size + key_size, value_size1)
# 2. 注意力融合层:将原始Q与加权后的V结合,输出最终结果
self.attn_combine = nn.Linear(query_size + value_size2, output_size)
def forward(self, Q, K, V):
# Q: [1, 1, 32] (查询向量)
# K: [1, 1, 32] (键向量)
# V: [1, 32, 64] (值向量,假设32个单词,每个64维)
# Step 1: 计算注意力权重分布
# 拼接 Q 和 K
qk_cat = torch.cat((Q[0], K[0]), dim=-1) # [1, 64]
# 通过线性层计算得分
attn_scores = self.attn(qk_cat) # [1, 32] (32个Key的分数)
# Softmax归一化为概率分布
attn_weights = F.softmax(attn_scores, dim=-1) # [1, 32]
# Step 2: 计算注意力结果表示
# 扩展维度以匹配bmm要求
attn_weights_expanded = attn_weights.unsqueeze(0) # [1, 1, 32]
# 核心运算:批量矩阵乘法
# [1, 1, 上下文长度] * [1, 上下文长度, 特征维度] = [1, 1, 特征维度]
attn_applied = torch.bmm(attn_weights_expanded, V) # [1, 1, 64]
# Step 3: 融合原始查询与注意力结果
# 拼接 Q 和 加权后的 V
output_cat = torch.cat((Q[0], attn_applied[0]), dim=-1) # [1, 96]
# 降维输出
output = self.attn_combine(output_cat).unsqueeze(0) # [1, 1, output_size]
return output, attn_weights
# 测试运行
if __name__ == '__main__':
# 实例化参数
my_att = MyAttention(query_size=32, key_size=32, value_size1=32, value_size2=64, output_size=32)
# 模拟输入数据
Q = torch.randn(1, 1, 32)
K = torch.randn(1, 1, 32)
V = torch.randn(1, 32, 64)
output, weights = my_att(Q, K, V)
print(f"Attention输出形状: {output.shape}") # [1, 1, 32]
print(f"注意力权重形状: {weights.shape}") # [1, 32]
代码解析:
看到torch.bmm了吗?这就是第一章知识的应用。我们用权重矩阵去"筛选"Value矩阵,提取出对当前Query最有用的信息。
🗣️ 第三章:实战------构建 Seq2Seq 英译法模型
有了底层的积木,现在我们来搭建高楼------Seq2Seq模型。它由两部分组成:
- Encoder (编码器) :读取英文句子,压缩成一个包含所有信息的"上下文向量"。
- Decoder (解码器) :读取上下文向量,逐个单词生成法文句子。
1. 数据预处理:让机器看懂"人话"
在训练之前,我们需要清洗数据并建立字典。文档中提供了一个非常实用的清洗函数,能处理大小写和标点。
python
import re
# 数据清洗函数
def normalizeString(s):
s = s.lower().strip() # 转小写
s = re.sub(r'([.?!])', r' \1', s) # 标点前加空格
s = re.sub(r'[^a-zA-Z.?!]+', ' ', s) # 过滤非法字符
return s
# 构建词汇表
english_word2index = {'SOS': 0, 'EOS': 1} # 起始和结束标记
french_word2index = {'SOS': 0, 'EOS': 1}
2. 编码器 (Encoder)
我们使用GRU(比LSTM更轻量)作为核心网络。
python
class EncoderGRU(nn.Module):
def __init__(self, input_size, hidden_size):
super().__init__()
self.hidden_size = hidden_size
# 词嵌入层
self.embedding = nn.Embedding(input_size, hidden_size)
# GRU层
self.gru = nn.GRU(hidden_size, hidden_size, batch_first=True)
def forward(self, input, hidden):
output = self.embedding(input)
output, hidden = self.gru(output, hidden)
return output, hidden
3. 解码器 (Decoder) - 带Attention机制
这是最精彩的部分!解码器在生成每一个法文单词时,都会回头去看一眼英文句子的哪些部分是重点(Attention)。