Transformer 结构推导:一步一步搭出最小可运行 PyTorch 实现
副标题 / 摘要 这篇文章不把 Transformer 当成一个现成黑盒来介绍,而是直接从一个最小翻译任务开始,让需要的结构一层一层长出来,最后收束成一份最小可运行的 PyTorch encoder-decoder Transformer。 从一个最小翻译任务开始 假设源序列是: <bos> I love apples <eos> 目标序列是: <bos> 我 喜欢 苹果 当模型要生成“苹果”时: 它不能看目标序列里未来还没生成的位置 它需要重点读取源序列中的 apples 它可能还需要参考前面的“我 喜欢”来决定当前词 所以这里天然会逼出三件事: 目标侧必须有因果约束 源侧和目标侧都需要全局读取 解码器不仅要读自己,还要读编码器输出 RNN 和 CNN 也能处理序列,但它们在长距离依赖和全并行训练上都有明显限制。 所以这里真正要解决的,不只是“做一个更深的网络”,而是让任意位置能直接交互,并且显式控制信息流方向。 下面开始按这个压力一步一步长代码。 Step 1:先有输入表示,但先不谈注意力 先看一个已经分词并编号后的最小输入: <bos> I love apples <eos> -> [1, 15, 982, 204, 2] 这里的 1, 15, 982, 204, 2 还不是模型已经理解后的表示。 它们只是词表里的编号,作用更接近“标签”或“学号”: 15 比 204 小,不代表它们语义上更接近 直接拿这种离散编号去做线性变换或点积,含义也不对 所以第一步只解决一个更具体的问题: 怎样把“词表编号”变成“模型后面可以继续计算的一组连续数值”? 这里再引入两个词: token id:分词后查词表得到的离散编号 embedding:把每个离散编号映射成长度为 d_model 的可学习向量 先写最小版,不额外引入别的机制: ...