模型的 generate 方法

在 MiniMind 系列的 eval 部分我们已经学习了如何通过 transformers 库里 GenerateMixin 基类来生成文本,这一章学习一下 model.generate() 方法到底是怎么实现的。

Transformer 模型在训练时有一个 forward 方法,是用于针对模型的输入来产生输出,从而计算损失 loss,更新模型的参数。既然有这么一个生成的函数了,为什么 Transformer 中还有专门设计 generate 方法来负责在推理时生成文本呢?

MoE 混合专家模型

MoE means Mixture of Experts,它是一种神经网络架构,可以把一个大模型拆分成多个小型的 expert,再用一个门控网络来决定每个输入该路由到哪些专家处理。

分布式训练技术 - 张量并行

上一篇文章我们学的是 DP 和 DDP,它们的思路是 用显存冗余换吞吐量。每张 GPU都有完整模型,但是只处理不同的数据,它的本质是复制模型 → 并行处理数据 → 最后通过 AllReduce 同步梯度,代价是模型被复制 N 份,占用 N 倍显存。张量并行 Tensor Parallel 的思路正好相反是 用通信换显存。现在的大模型参数量巨大一张卡很可能放不下,所以把模型拆到多卡,每张 GPU 只有部分模型,但是处理完整的数据,最后进行合并。

分布式训练技术 - 数据并行

我们先回忆一下传统的单机单卡训练模式:

首先硬盘读取数据,CPU 处理数据,将数据组成一个 batch,再传入 GPU,网络前向传播算出 loss,再反向传播计算梯度,用梯度更新参数完成一次训练。这种传统模式在大参数量或者大数据量的情况下就容易陷入显存的瓶颈,于是就引出了多卡并行训练。

transformer库的基类

今天看了一下源码和官方文档,梳理过后会发现其实也不是很复杂,简单理解就两条:

  • ModelOutput(transformers.utils.ModelOutput)是所有模型输出的基类。简单理解它就是一个字典,在模型的 forward函数里把原本的输出做了一下封装而已,方便用户能直观地知道输出是什么。例如CausalLMOutput顾名思义就是用于像 GPT 这样自回归模型的输出。
  • PreTrainedModel (transformers.modeling_utils.PretrainedModel) 是所有模型的基类。所以你如果看到一个模型取名为LlamaForCausalLM,那你就可以知道这个模型的输出格式大概率就是自回归输出,即前面提到的CausalLMOutput。为什么说大概率呢,因为自回归输出还有蛮多种的,赶时间的朋友看到这就可以切换到其他文章了,至此你应该也能了解 transformers 最核心的模块了。感兴趣的可以继续往下看,下面做一个简单的总结和介绍。

前面已经介绍过了,ModelOutput是所有模型输出的基类。下面是其源码核心部分,一些具体实现代码删除了,不过不影响理解。

Mask On Transformer

在 Transformer 中同时运用了两种掩码技术:

  1. 用于处理非定长序列的 padding mask
  2. 用于防止标签泄露的 causal mask

NLP 任务中,输入的长度往往不是统一的,训练的数据集里面样本长度各有不同。但是我们在实际训练中,往往需要把多个数据合成一个大的 batch 一同训练,这样可以充分利用显卡的性能。那么问题就来了,不同长度的文本如何合成一个大 batch 呢。NLP 的解决思路是:把所有输入的文本统一成一个固定长度,多余的位置用特殊字符 <PAD> 来填充。

算法刷题记录

二分查找的原理就是不断收缩 left 和 right 指针,使得最终希望找的的元素 target 在他们围成的区域里。所以这就引申出两种写法,如果区域是左闭右闭的 [left, right],那么最终 target 就是 left==right 的那个值;如果是左闭右开的 [left, right),那么当 left+1==right 时候 target 就在左端点的位置。

CDN 加速博客和图床

把博客部署到 Github Pages 确实很方便,不过由于种种原因在内地没法直连,于是研究用 Cloudflare 加速一下。

Cloudflare 如何加速 GitHub Pages

首先,我们在域名提供商(例如我用的是阿里云的域名)将域名的 Nameserver 指向 Cloudflare: