AstrAI/assets/docs/introduction.md

118 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 模型介绍
### 1. 模型搭建
本模型采用Transformer架构 使用GQAq_head=24, kv_head=4 机制相较于传统的MHA可以节省KV cache 的显存占用但是目前没有做KV cache通过堆叠24层Transformer实现模型的搭建 参数量为1.0b。Transformer 是自回归模型, 是通过计算前面所有的token的关系得到下一个token的概率分布
![structure](../images/structure.png)
什么是自回归模型呢, 在把句子拆分成token之后, 模型会预测下一个token的概率分布。这意味着模型会根据给定的上下文即已经出现的tokens序列计算出下一个可能的token及其对应的概率。
#### 1. 自回归
假设我们有一个句子被拆分成如下tokens列表
```
["你好", "" "今天", "天气"]
```
接下来模型会基于这个序列预测下一个可能出现的token。这通常以概率分布的形式给出比如
```
-> {"token": "不错", "probability": 0.4}
-> {"token": "晴朗", "probability": 0.2}
-> ......
```
这里“不错”和“晴朗”是两个可能跟随在“天气”之后的tokens并且给出了每个token成为下一个token的可能性大小。
之后我们通过采样通过top_k, top_p, temperature参数调整采样后的结果得到下一个token并且将下一个token加入序列作为输入
```
["你好", "" "今天", "天气", "不错"]
```
之后都是在重复这个流程, 直到遇到控制流程结束的token<|end_of_seqence|>模型停止处理一般模型都会设置控制token 不然模型会一直输出到显存爆炸)。
#### 2. 因果掩码
transformer 中采用注意力机制,输入的形状一般为[bsz, seq_len] 输出为[bsz, seq_lenn_dim] 为了实现预测下一个token 模型的输入和输出必须错开来一个位置。模型预测的target必须错开一个位置 在训练的时候我们也采用错开一个位置的方法
```
sequence : [[1, 2, 3, 4, 5, 6]]
input_ids: [[1, 2, 3, 4, 5]]
target_ids: [[2, 3, 4, 5, 6]]
```
注意力得分计算的公式为
$$ s_{ij} = softmax(\frac{q_i^Tk_j}{\sqrt{d_k}}) $$
$$ s_{ij} := s_{ij} + mask_{ij} $$
其中注意力得分代表了模型对两个token之间相似程度的关注程度
对于decoder only结构的模型 为了防止模型从未来的位置偷到信息, 在注意力的计算过程中需要增加掩码我们需要在注意力得分计算之前应用一个掩码。这个掩码通常是一个下三角矩阵对于长度为n的序列它的形状是[n, n]。下面以一个长度为5的序列为例展示如何创建这样的因果掩码矩阵
```
[[0, -inf, -inf, -inf, -inf],
[0, 0, -inf, -inf, -inf],
[0, 0, 0, -inf, -inf],
[0, 0, 0, 0, -inf],
[0, 0, 0, 0, 0]]
```
在这个矩阵中0表示可以注意到的位置而-inf表示应该被掩盖即不应注意到的位置。因为这个句子保证了注意力得分中 $j > i$ 的部分通过softmax 之后由`inf` 变成0 也就是模型不能看到未来的信息
#### 3. 旋转位置编码
旋转位置编码Rotary Position Embedding, RoPE是一种为了解决Transformer模型中缺乏对序列位置信息直接建模的问题而设计的位置编码方法。与传统的位置编码如正弦和余弦函数的位置编码不同RoPE通过将位置信息直接嵌入到查询Query, Q和键Key, K向量中来实现使得模型能够更自然地处理序列中的相对位置关系。
$$ q_i = R_i W_q x_i $$
$$ k_j = R_j W_k x_j $$
$$ q_i^T k_j = (R_i W_q x_i)^T( R_j W_k x_j) = x_i^T W_q^T R_{i-j} W_k x_j $$
其中的 $R_{i-j}$ 控制了模型的不同token 在不同相对距离上注意力的衰减,在 $i - j$ 绝对值越大的时候, 衰减的程度越强, 通过这种方式能让模型学习到相对位置关系, 从而使得模型可以扩展和适应长序列
## kv_cache 实现
根据注意力的计算公式
$$
\begin{align*}
o_i &= \sum_j s_{ij} v_{j} \newline
s_{ij} &= \text{softmax}\left( \frac{q_{i} k_{j}}{\sqrt{d_k}} \right)
\end{align*}
$$
由于模型是自回归模型, 我们只用求序列最后一个部分,也就是说 $ i $ 的下标是确定的, 是序列最后一个元素, 我们求的是 $o_{n} $
$$
\begin{align*}
o_n &= \sum_j s_{j}v_{j} \newline
s_j &= \text{softmax}\left(\frac{q_n k_{j}}{\sqrt{d_k}} \right)
\end{align*}
$$
如果我们把式子展开
$$
o_n = \sum_j \text{softmax}\left(\frac{q_n k_{j}}{\sqrt{d_k}}\right)v_{j}
$$
以上表达式只有k和v存在长度下标, 而 $q$ 没有, 所以计算过程中 $q$ 的输入是确定的上次输入的最后一个token, 而 $k, v$ 是需要对不同长度的部分进行缓存的同时缓存的时候应该注意位置编码的计算应该在kvcache的计算之前进行否则会存在位置编码的计算错误