前言
本文最开始先全面介绍Mistral 7B,然后再全面介绍的Mixtral 8x7B
但考虑到MoE的重要性——特别是MoE决定后来2025年春节前后火爆全球deepseek的架构,故把本文介绍的MoE相关的部分 全部独立出去,成此文:《一文速览DeepSeekMoE:从Mixtral 8x7B到DeepSeekMoE(含DeepSeek LLM的简介)》
最后把这篇文章《七月论文审稿GPT第3.2版和第3.5版:通过paper-review数据集分别微调Mistral、gemma》拆分了
- 其中的Mistral 7B微调内容,放到了本文第二部分
- 至于该文的gemma微调部分则放到了此文之中《一文速览Gemma 2及其微调:从论文审稿GPT第3.5版(基于Gemma),到第5.2版(早期paper-7方面review微调Gemma2)》
第一部分 23年5月Mistral AI发布的Mistral 7B
1.1 Mistral 7B:通过分组查询注意力 + 滑动窗口注意力超越13B模型
23年5月,DeepMind和Meta的三位前员工在巴黎共同创立了Mistral AI(其CEO Arthur Mensch此前在DeepMind巴黎工作,CTO Timothée Lacroix和首席科学家Guillaume Lample则在Meta共同参与过LLaMA一代的研发,很像当年OpenAI的部分员工出走成立Anthropic啊)
23年9.27,他们发布了第一个基座大模型,即Mistral 7B (这是当时Mistral AI关于Mistral 7B发布的新闻 )
1.1.1 Mistral 7B:超过llama2 13B、GQA、SWA、RoPE
Mistral 7B对应的论文为《Mistral 7B》称( 另,这是其GitHub地址),以下是「模型参数图」
- Mistral 7B在所有评估基准中均胜过了目前最好的13B参数模型(Llama 2,对标的第二代),并在推理、数学和代码生成方面超越了Llama 34B(对,这里其对标Llama第一代的34B,原因是当时Llama 2 34B 尚未发布)
Mistral 7B outperforms the previous best 13B model (Llama 2, [Llama 2: Open foundation and fine-tuned chat models]) across all testedbenchmarks, and surpasses the best 34B model (LLaMa 34B, [Llama: Open and efficient foundation language models]) in mathematics and codegeneration. - 该模型采用了分组查询注意力(GQA),GQA显著加快了推理速度,还减少了解码期间的内存需求,允许更高的批处理大小,从而提高吞吐量
GQA significantly accelerates the inference speed, and also reduces the memory requirement during decoding, allowing for higher batch sizes hence higher throughput
所以你看上面的「模型参数图」,维度(dim):4096,总计32个头(n_heads),每个头的维度(head_dim):128,这一眼可以看出来,而等于8的n_kv_heads是啥呢?
咋一看好像不太好理解 是不?其实,正是因为Mistral用了GQA
n_heads的个数便是Q的个数(相当于多少个头 则多少个Q)
而n_kv_heads指的是K、V的个数(因为多个头会共享一个K或V,则头和Q的个数会大于K V的个数,比如可能8个头下:8个Q、4个K、4个V)
不过要注意的是,与上图中间所示部分不太一样的地方在于:
上图中间所示部分中,Q的个数是K V个数的2倍,Q为8, K V均为4
但在Mistral的GQA中,Q的个数是K V个数的4倍,Q为32,K V均为8
关于GQA的更多介绍,请参见《一文通透各种注意力:从多头注意力MHA到分组查询注意力GQA、多查询注意力MQA》 - 同时结合滑动窗口注意力(sliding window attention,简称SWA)以有效处理任意长度的序列
SWA is designed to handle longer sequences more effectively at a reduced computational cost
当然,SWA也不是Mistral的首创,而是基于这两篇论文实现的:Generating Long Sequences with Sparse Transformers、Longformer: The Long-Document Transformer
具体而言,你再看上上张图所示的「模型参数图」,可知context_len 8192是说它训练的时候,传进来的数据最大只能到8192个tokens,也就是训练时的上下文长度上限
windows_size 4096是sliding windows attention的滑窗大小,1次attention计算的上下文范围只4096个tokens
言外之意是,每个token只最多计算4096的范围
第5000个token只计算[905: 5000]这个范围的attention
第5001个token只计算[906: 5001]这个范围的attention
以此类推.. - 位置编码方面,和llama统一用的RoPE(顺带插一嘴,包括后来Google开源的gemma也用的RoPE,所以RoPE算是标配了,至于关于位置编码和RoPE的详尽细致的介绍,请参见此文)
RoPE所对应的代码如下所示(代码来源:mistral-src/mistral /rope.py)import torch from typing import Tuple def precompute_freqs_cis(dim: int, end: int, theta: float) -> torch.Tensor: freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) t = torch.arange(end, device=freqs.device) # type: ignore freqs = torch.outer(t, freqs).float() # type: ignore return torch.polar(torch.ones_like(freqs), freqs) # complex64 def apply_rotary_emb( xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor, ) -> Tuple[torch.Tensor, torch.Tensor]: xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2)) freqs_cis = freqs_cis[:, None, :] xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(2) xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(2) return xq_out.type_as(xq), xk_out.type_as(xk)
1.1.2 Mistral 7B-Instruct
与Mistral 7B同期发布的Mistral 7B – Instruct(We also provide a model fine-tuned to follow instructions,Mistral 7B –Instruct),在MT-Bench的表现可以略微超过LLaMA2 13B –Chat模型
再后来到23年12月时,instruct升级到了0.2版,但此时的上下文长度依然只有8K,但好在24年3月随着Mistral 7B 0.2版的发布,Mistral 7B-Instruct-0.2也顺势做了升级,上下文长度扩展到了32K
更具体的细节,以及关于Mistral instruct 0.2的微调,则详见此文《七月论文审稿GPT第3.1版和第3.2版:通过paper-review数据集分别微调Mistral、gemma》
1.2 Mistral 7B更多细节:滑动窗口注意力、滚动缓冲区缓存、预填充与分块
1.2.1 滑动窗口注意力:扩展上下文长度
vanilla attention的操作次数在序列长度上是二次型的,记忆量随着token数量线性增加。在推理时,由于缓存可用性的降低,这导致了更高的延迟和更小的吞吐量(The number of operations in vanilla attention is quadratic in the sequence length, and the memory increases linearly with the number of tokens. At inference time, this incurs higherlatency and smaller throughput due to reduced cache availability)
为了缓解这个问题,Mistral 7B使用滑动窗口注意力(sliding window attention)
- 每个token最多可以关注来自上一层的W个token(上图中,W = 3)。请注意,滑动窗口之外的token仍然影响下一个单词预测
each token can attend to at most W tokens from the previous layer (here, W = 3). Note that tokensoutside the sliding window still influence next word prediction.
举个例子,在面对这个序列时:The cat sat on the
如果是标准注意力,在计算最后一个token “the”时,得计算the本身所对应的query与整个上文每个token对应的key的内积,当序列长度一长时,该计算量还是比较大的
但如果是滑动窗口注意力,则在计算最后一个token “the”时,只需计算the本身所对应的query与上文中3个token对应的key的内积(这里说的上文中的3个token 包括the自己在内) - 在每个注意力层,信息可以向前移动W个token。因此,在k层注意力之后,信息最多可以向前移动k个×W个token
At each attention layer, information can moveforward by W tokens. Hence, after k attention layers, information can move forward by up to k ×W tokens.
1.2.2 滚动缓冲区缓存(Rolling Buffer Cache)
固定的注意力长度意味着可以使用滚动缓存来限制的缓存大小(A fixed attention span means that we can limit our cache size using a rollingbuffer cache)
- 缓存的大小是固定的W,时间步长i的键和值存储在缓存的位置i mod W中。因此,当位置i大于W时,缓存中过去的值就会被覆盖,缓存的大小就会停止增加
The cache has a fixed size of W, and the keys and values for the timestep i are storedin position i mod W of the cache. As a result, when the position i is larger than W, past valuesin the cache are overwritten, and the size of the cache stops increasing
以“The cat sat on the mat”为例..
当 i = 0 时,指The,0 mod 3=0
当 i = 1 时,指cat,1 mod 3=1
当 i = 2 时,指sat,2 mod 3=2
当 i = 3 时,指on,3 mod 3=0
当 i = 4 时,指the,4 mod 3=1
当 i = 5 时,指mat,5 mod 3 = 2 - 在32k token的序列长度上,这减少了8倍的缓存内存使用,而不影响模型质量
On a sequence length of 32k tokens, this reduces the cache memory usageby 8x, without impacting the model quality.
如果把缓冲区比作一座仓库,每存进一个新东西,都会占据相应的位置,而仓库的总容量是固定的,当仓库被装满时,就会把最早放入的东西移除,让新的物品继续进仓,相当于入仓时间更接近当前时间的物品则会留在仓库中,如此,即能在节约资源的同时保留一定长度的序列
1.2.3 预填充与分块:减少重复运算
在生成序列时,需要一个一个地预测token,因为每个token都以前面的token为条件。然而,prompt是提前知道的,可以用prompt预填充(k, v)缓存,即
- 如果prompt非常大,可以把它分成更小的块,用每个块预填充缓存。为此,可以选择窗口大小作为分块大小。因此,对于每个块,需要计算缓存和块上的注意力
- 下图展示了注意力掩码在缓存和分块上的工作原理
在预填充缓存时,长序列被分块,以限制内存使用
我们把一个序列分成三个块来处理,“The cat sat on”,“the mat and saw”,“the dog go to”。上图中显示了第三块(“the dog go to”)发生的情况:它使用因果掩码(最右块)来关注自己,使用滑动窗口(中心块)来关注缓存,并且不关注过去的token,因为它们在滑动窗口之外(左块)
第二部分 论文审稿GPT第3.2版:微调Mistral 7B instruct 0.2
提前说下,本部分最初属于发表于24年3月份的此文《七月论文审稿GPT第3.2版和第3.5版:通过paper-review数据集分别微调Mistral、gemma》的第一部分,当时的前言是
- 去年Mistral instruct 0.1因为各种原因导致没跑成功时(详见此文的4.2.2节直接通过llama factory微调Mistral-instruct),我总感觉Mistral应该没那么拉胯,总感觉得多实验几次,所以打算再次尝试下Mistral instruct 0.2「当然,本文只展示部分细节,更多细节则见七月的《大模型商用项目审稿GPT微调实战》」
- 最后值得一提的是,我司「七月在线」审稿项目组还在通过80G的A100微调mixtral 8×7b中了,历经9个月,连续迭代7个版本,只为把审稿效果不断做到极致(超越GPT4在第2个版本就做到了),最终以「无限接近人工reviewer的效果」辅助审稿者审稿、辅助作者修订论文,但如下图所示,过程中也走了不少弯路
2.1 23年12月版的Mistral-7b-Instruct-v0.2:上下文长度8K
关于Mistral 7B的介绍,请看此文《从Mistral 7B到MoE模型Mixtral 8x7B的全面解析:从原理分析到代码解读》的1.1节Mistral 7B:通过分组查询注意力 + 滑动窗口注意力超越13B模型
2.1.1 Mistral 7B-Instruct:微调时其长度扩展的能力从何而来
由于Mistral 7B-Instruct(特指在24年3.24之前的版本)和Mistral 7B一样,其长下文长度都只有8192
而论文审稿GPT这个项目对模型上下文的长度要求12K以上,故需要扩展Mistral 7B-Instruct的上下文长度,如何扩展呢
考虑到如此文《七月论文审稿GPT第2版:用一万多条paper-review数据集微调LLaMA2 7B最终反超GPT4》4.1节所介绍的
- Yarn-Mistral-7b-64k自己实现了modeling,即把mistral的sliding windows attention改了,相当于把sliding windows的范围从滑窗大小直接调到了65536即64K(即直接滑65536那么个范围的滑窗,其实就是全局)
那类似的,给Mistral 7B–Instruct加YaRN行不行?
然问题是不好实现:YaRN-Mistral 7B – Instruct,因为Yarn是全量训的方案,而大滑窗范围+全量很吃资源- 受LongLora LLaMA的启发,既然没法给Mistral 7B–Instruct加YaRN,那可以给其加longlora么?
然问题是mistral又没法享有longlora,因为mistral的sliding windows attention和longlora的shift short attention无法同时兼容,但要对原chat模型的上下文长度进行有效扩展又会需要shift short attention
不得已,故再考察下它所用的RoPE(相关代码见:transformers/src/transformers/models/mistral/modeling_mistral.py),毕竟RoPE可以使得模型的上下文长度直接外推10-20%
然,在我们后续实际微调23年12月份版本的Mistral 7B-Instruct 0.2时(其上下文长度还只有8K),实际支持其获得更长上下文能力的还是归结于其滑动窗口注意力(sliding window attention,简称SWA),毕竟SWA可以有效处理任意长度的序列
- 怎么发现的呢?如下图所示的“大海捞针”实验,纵轴是对应语句放在文章中的位置(从头到尾),如果是外推的话 不会有图中那个斜杠(因为外推的话无论输入多长的序列,它的ppl都是稳定的,即右上角应该是绿色才对),故从图中可以很明显的看出来Mistral的window size就是4k(每次只计算4k范围内的注意力)
- 总之,对于Mistral或gemma如果通过rope去外推,算是没有办法的办法,但Mistral有滑动窗口注意力的话,反正无论输入长度多长,它每一个token只计算在它之前(含它自己)的4096个token的注意力,相当灵活,故自然也就轮不到用rope去外推了
2.1.2 7b-Instruct-v0.2基于「新上线的Mistral-7B-v0.2」把上下文长度升级到32K
24年3.24日,我司「七月在线」审稿项目组的文弱发现,Mistral AI悄悄发布了Mistral-7B-v0.2(我们最早是在mistralai/Mistral-7B-Instruct-v0.2在hg上的页面上确认到的,其次是redit上有用户说Mistral-7B-v0.2已上传至HF )
Mistral-7B-v0.2 has the following changes compared to Mistral-7B-v0.1
然后他们又把三个月之前发布的Mistral-7b-instruct-0.2基于最新的Mistral-7b-v0.2升级了下(但他们当天只是更新一下readme,32K的instruct-0.2在当天还没有正式放出来啊 )
相当于
- Mistral于23年9月 就发了7b第一个版本,和Mistral-7b-instruct-0.1(当时,他们用滑动窗口注意力 把7b-0.1扩展到的8K上下文)
- 再后来(即大概23年12月),他们推出了Mistral-7b-instruct-0.2
- 然后现在(大约24年3.24日早上8点),推出了Mistral-7b-0.2版本(7b-0.2版本 没用滑动窗口注意力了,毕竟现在上下文扩展 没半年前那么困难了,所以不需要再依赖滑窗 便可让7b-0.2直接干到32K,当然 还没看到怎么直接干到32K的 )
同时把之前的Mistral-7b-instruct-0.2 基于Mistral-7b-0.2 升级了下,升级之后还是叫Mistral-7b-instruct-0.2,但上下文窗口从升级之前的8K到了现在的32K了
但遗憾的是,截止到3.25,Mistral AI还未对外上传32K的instruct-0.2
2.2 基于llama factory + 5K/15K数据微调Mistral-7b-Instruct-v0.2(23年12月份的版本) by鸿飞
把训练数据,格式是:{"input":"论文内容", "output": "review data"}}的数据,按照LLama-Factory目录下面的dataset_info_zh.md中的步骤,把数据整理成为羊驼alpaca的格式
- 一开始--per_device_train_batch_size 1设置为1,启动程序,还会发生内存不足的问题
经过检查以后,发现是论文长度比较长,又把论文和review数据截断为12288的数据长度,再放到data目录下面,per_device_train_batch_size设置为3,正常运行,但是内存已经到了47G了,但是早上发现在运行到了晚上4点,程序因为内存不足而退出了 - 断点续跑:
重新启动程序,设置--resume_from_checkpoint checkpoint-660,修改运行的batch_size为2,重新把程序从上次退出的地方跑起来。发现内存占用为33G/48G。剩余时间大约12个小时跑完
以下是训练过程中的其他细节
- 模型超时解决:--ddp_timeout 180000000
- 长度外推方式
目前只支持Linear和dynamic NTK
为了加快训练速度,使用deepspeed s2 + 4bit+NF 量化 - 使用了flash-attn:不过训练速度没有明显地提升
- 租的机器的cuda版本是11.8,安装了最新的torch,发现和cuda不匹配,更新cuda的话太麻烦,所以按照llama factory开发者的建议:
pip uninstall torch torchvision torchaudio
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 - LLamaFactory推荐deepspeed==0.13.5
但运行以后,json.dumps表示不能保存这种数据,怎么办?
最后通过安装 deepspeed==0.13.1 解决{ 'loss': 1.9611, 'grad_norm': tensor(4.6666), 'learning_rate': 2.5e-05, 'epoch': 0.0 },
如鸿飞如说
- 运行程序的时候,尽量留够一定的内存空间,否则会出现中途退出的问题
- 对于一些特定的错误,不会解决的时候,最好找LLama-Factory的开发者去解决,否则自己很难定位出错误的位置。trick: LLama-Factory上面的多加几个群,这样子可以多学习官方人员的解决思路
- 机器cuda与python的版本号最好是一致的。
- 量化后的模型与主模型不能合并。量化模型不能合并
最后推理时,务必注意把推理时的数据组织格式 改成「Mistral推理时所要求的格式」
- 即用Mistral提供的API,进行组织数据格式
- 总之,如鸿飞所说,在预测的时候,我自己不瞎组织测试数据。严格按照mistral要求的数据格式进行输入,然后输出就没有问题了
更多见七月的《大模型商用项目审稿GPT微调实战》
2.3 对「Mistral-7b-Instruct-v0.2(23年12月版)之paper-review微调版」的评估
下图是通过5K数据微调Mistral 7B instruct的评估结果
更多见七月的《大模型商用项目之审稿GPT微调实战》