RWKV主页:https://www.rwkv.com
RWKV-5/6 Eagle/Finch 论文:https://arxiv.org/abs/2404.05892
Vision 中很棒的 RWKV: https://github.com/Yaziwel/Awesome-RWKV-in-Vision
RWKV-6 3B 演示:https://huggingface.co/spaces/BlinkDL/RWKV-Gradio-1
RWKV-6 7B 演示:https://huggingface.co/spaces/BlinkDL/RWKV-Gradio-2
RWKV-6 GPT 模式演示代码(带注释和解释) :https://github.com/BlinkDL/RWKV-LM/blob/main/RWKV-v5/rwkv_v6_demo.py
RWKV-6 RNN 模式演示:https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_v6_demo.py
作为参考,使用 python 3.10+、torch 2.5+、cuda 12.5+、最新的 deepspeed,但保持 pytorch-lightning==1.9.5
训练 RWKV-6 :使用 /RWKV-v5/ 并在 demo-training-prepare.sh 和 demo-training-run.sh 中使用 --my_testing "x060"
训练 RWKV-7 :使用 /RWKV-v5/ 并在 demo-training-prepare.sh 和 demo-training-run.sh 中使用 --my_testing "x070"
pip install torch --upgrade --extra-index-url https://download.pytorch.org/whl/cu121
pip install pytorch-lightning==1.9.5 deepspeed wandb ninja --upgrade
cd RWKV-v5/
./demo-training-prepare.sh
./demo-training-run.sh
(you may want to log in to wandb first)
您的损失曲线应该看起来几乎与此完全相同,具有相同的起伏(如果您使用相同的 bsz 和配置):
您可以使用 https://pypi.org/project/rwkv/ 运行模型(使用“rwkv_vocab_v20230424”而不是“20B_tokenizer.json”)
使用 https://github.com/BlinkDL/RWKV-LM/blob/main/RWKV-v5/make_data.py 从 jsonl 准备 binidx 数据,并计算“--my_exit_tokens”和“--magic_prime”。
大数据更快的分词器:https://github.com/cahya-wirawan/json2bin
train.py中的“epoch”是“mini-epoch”(不是真正的epoch。只是为了方便),1个mini-epoch = 40320 * ctx_len tokens。
例如,如果您的 binidx 有 1498226207 个令牌且 ctxlen=4096,请设置“--my_exit_tokens 1498226207”(这将覆盖 epoch_count),它将是 1498226207/(40320 * 4096) = 9.07 个 miniepoch。训练器将在“--my_exit_tokens”令牌后自动退出。将“--magic_prime”设置为小于 datalen/ctxlen-1 (= 1498226207/4096-1 = 365776) 的最大 3n+2 个素数,本例中为“--magic_prime 365759”。
简单:准备 SFT jsonl => 在 make_data.py 中重复 SFT 数据 3 或 4 次。更多的重复会导致过度拟合。
高级:在 jsonl 中重复 SFT 数据 3 或 4 次(注意 make_data.py 将打乱所有 jsonl 项)=> 将一些基础数据(例如 slimpajama)添加到 jsonl => 并且仅在 make_data.py 中重复 1 次。
修复训练尖峰:请参阅本页的“修复 RWKV-6 尖峰”部分。
RWKV-5 的简单推理:https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_v5_demo.py
RWKV-6 的简单推理:https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_v6_demo.py
注意:在 [state = kv + w * state] 中,所有内容都必须是 fp32,因为 w 可以非常接近 1。因此我们可以将 state 和 w 保留在 fp32 中,并将 kv 转换为 fp32。
lm_eval:https://github.com/BlinkDL/ChatRWKV/blob/main/run_lm_eval.py
面向开发人员的聊天演示:https://github.com/BlinkDL/ChatRWKV/blob/main/API_DEMO_CHAT.py
小模型/小数据的提示:当我训练 RWKV 音乐模型时,我使用深和窄(例如 L29-D512)维度,并应用 wd 和 dropout(例如 wd=2 dropout=0.02)。注意 RWKV-LM 压差非常有效 - 使用通常值的 1/4。
对数据使用 .jsonl 格式(有关格式,请参阅 https://huggingface.co/BlinkDL/rwkv-5-world)。
使用 https://github.com/BlinkDL/RWKV-LM/blob/main/RWKV-v5/make_data.py 使用 World tokenizer 将其标记为 binidx,适合微调 World 模型。
将模型文件夹中的基本检查点重命名为 rwkv-init.pth,并将训练命令更改为对 7B 使用 --n_layer 32 --n_embd 4096 --vocab_size 65536 --lr_init 1e-5 --lr_final 1e-5。
0.1B = --n_layer 12 --n_embd 768 // 0.4B = --n_layer 24 --n_embd 1024 // 1.5B = --n_layer 24 --n_embd 2048 // 3B = --n_layer 32 --n_embd 2560 / / 7B = --n_layer 32 --n_embd 4096
目前未优化的实现,采用与完整 SFT 相同的 vram
--train_type "states" --load_partial 1 --lr_init 1 --lr_final 0.01 --warmup_steps 10 (yes, use very high LR)
使用 rwkv 0.8.26+ 自动加载经过训练的“time_state”
当您从头开始训练 RWKV 时,请尝试我的初始化以获得最佳性能。检查 src/model.py 的generate_init_weight():
emb.weight => nn.init.uniform_(a=-1e-4, b=1e-4)
(Note ln0 of block0 is the layernorm for emb.weight)
head.weight => nn.init.orthogonal_(gain=0.5*sqrt(n_vocab / n_embd))
att.receptance.weight => nn.init.orthogonal_(gain=1)
att.key.weight => nn.init.orthogonal_(gain=0.1)
att.value.weight => nn.init.orthogonal_(gain=1)
att.gate.weight => nn.init.orthogonal_(gain=0.1)
att.output.weight => zero
att.ln_x.weight (groupnorm) => ((1 + layer_id) / total_layers) ** 0.7
ffn.key.weight => nn.init.orthogonal_(gain=1)
ffn.value.weight => zero
ffn.receptance.weight => zero
!!!如果您使用位置嵌入,也许最好删除 block.0.ln0 并使用 emb.weight 的默认初始化而不是我的uniform_(a=-1e-4, b=1e-4)!
从头开始训练时,请在“RUN_CUDA_RWKV6(r, k, v, w, u)”之前添加“k = k * torch.clamp(w, max=0).exp()”,并记住也要更改您的推理代码。你会看到更快的收敛。
使用“--adam_eps 1e-18”
如果您看到峰值,则“--beta2 0.95”
在trainer.py中执行“lr = lr *(0.01 + 0.99 * trainer.global_step / w_step)”(最初为0.2 + 0.8)和“--warmup_steps 20”
如果您正在训练大量数据,“--weight_decay 0.1”会带来更好的最终损失。执行此操作时,将 lr_final 设置为 lr_init 的 1/100。
RWKV 是一个具有 Transformer 级别 LLM 性能的 RNN,也可以像 GPT Transformer 一样直接训练(可并行)。而且它是 100% 无需关注的。您只需要位置 t 处的隐藏状态即可计算位置 t+1 处的状态。您可以使用“GPT”模式快速计算“RNN”模式的隐藏状态。
因此,它结合了 RNN 和 Transformer 的优点 -出色的性能、快速推理、节省 VRAM、快速训练、“无限”ctx_len 和自由句子嵌入(使用最终隐藏状态)。
RWKV Runner GUI https://github.com/josStorer/RWKV-Runner 具有一键安装和 API
所有最新的 RWKV 权重: https://huggingface.co/BlinkDL
兼容 HF 的 RWKV 配重: https://huggingface.co/RWKV
RWKV pip 包:https://pypi.org/project/rwkv/
os . environ [ "RWKV_JIT_ON" ] = '1'
os . environ [ "RWKV_CUDA_ON" ] = '0' # if '1' then use CUDA kernel for seq mode (much faster)
from rwkv . model import RWKV # pip install rwkv
model = RWKV ( model = '/fsx/BlinkDL/HF-MODEL/rwkv-4-pile-1b5/RWKV-4-Pile-1B5-20220903-8040' , strategy = 'cuda fp16' )
out , state = model . forward ([ 187 , 510 , 1563 , 310 , 247 ], None ) # use 20B_tokenizer.json
print ( out . detach (). cpu (). numpy ()) # get logits
out , state = model . forward ([ 187 , 510 ], None )
out , state = model . forward ([ 1563 ], state ) # RNN has state (use deepcopy if you want to clone it)
out , state = model . forward ([ 310 , 247 ], state )
print ( out . detach (). cpu (). numpy ()) # same result as above
nanoRWKV :https://github.com/BlinkDL/nanoRWKV(不需要自定义 CUDA 内核进行训练,适用于任何 GPU/CPU)
推特:https://twitter.com/BlinkDL_AI
主页:https://www.rwkv.com
酷社区 RWKV 项目:
所有(300+)RWKV 项目:https://github.com/search?o=desc&q=rwkv&s=updated&type=Repositories
https://github.com/OpenGVLab/Vision-RWKV 愿景 RWKV
https://github.com/feizc/Diffusion-RWKV 扩散 RWKV
https://github.com/cgisky1980/ai00_rwkv_server 最快的 WebGPU 推理 (nVidia/AMD/Intel)
https://github.com/cryscan/web-rwkv ai00_rwkv_server 后端
https://github.com/saharNooby/rwkv.cpp 快速 CPU/cuBLAS/CLBlast 推理:int4/int8/fp16/fp32
https://github.com/JL-er/RWKV-PEFT lora/pissa/Qlora/Qpissa/state 调整
https://github.com/RWKV/RWKV-infctx-trainer Infctx 训练器
https://github.com/daquexian/faster-rwkv
MLC-ai/MLC-llm#1275
https://github.com/TheRamU/Fay/blob/main/README_EN.md 带 RWKV 的数字助理
https://github.com/harrisonvanderbyl/rwkv-cpp-cuda 使用 cuda/amd/vulkan 进行快速 GPU 推理
RWKV v6 250 行(也带有分词器):https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_v6_demo.py
RWKV v5 250 行(也带有分词器):https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_v5_demo.py
RWKV v4 150 行(模型、推理、文本生成):https://github.com/BlinkDL/ChatRWKV/blob/main/RWKV_in_150_lines.py
RWKV v4 预印本https://arxiv.org/abs/2305.13048
RWKV v4介绍,以及100行numpy :https://johanwind.github.io/2023/03/23/rwkv_overview.html https://johanwind.github.io/2023/03/23/rwkv_details.html
RWKV v6 图解:
使用 RWKV 的一篇很酷的论文(Spiking Neural Network):https://github.com/ridgerchu/SpikeGPT
欢迎您加入 RWKV 不和谐 https://discord.gg/bDSBUMeFpc 并以此为基础。我们现在拥有大量潜在的计算(A100 40G)(感谢 Stability 和 EleutherAI),所以如果您有有趣的想法,我可以运行它们。
Pile 中 10000 个 ctx4k+ 文档的 RWKV [损失与代币位置]。 RWKV 1B5-4k在ctx1500之后大部分是平坦的,但是3B-4k和7B-4k和14B-4k有一些斜坡,并且正在变得更好。这推翻了 RNN 无法对长 ctxlens 进行建模的旧观点。我们可以预测 RWKV 100B 会很棒,而 RWKV 1T 可能就是您所需要的:)
与 RWKV 14B ctx8192 聊天RWKV:
我相信 RNN 是基本模型的更好候选者,因为:(1)它对 ASIC 更友好(没有 kv 缓存)。 (2)对于RL更加友好。 (3)当我们写作时,我们的大脑更类似于RNN。 (4) 宇宙也像一个 RNN(因为局部性)。变压器是非本地模型。
A40 (tf32) 上的 RWKV-3 1.5B = 始终为 0.015 秒/令牌,使用简单的 pytorch 代码(无 CUDA)进行测试,GPU 利用率 45%,VRAM 7823M
A40 (tf32) 上的 GPT2-XL 1.3B = 0.032 秒/令牌(对于 ctxlen 1000),使用 HF 进行测试,GPU 利用率也是 45%(有趣),VRAM 9655M
训练速度:(新训练代码)RWKV-4 14B BF16 ctxlen4096 = 8x8 A100 80G (ZERO2+CP) 上 114K 令牌/秒。 (旧训练代码)RWKV-4 1.5B BF16 ctxlen1024 = 8xA100 40G 上的 106K 令牌/秒。
我也在做图像实验(例如:https://huggingface.co/BlinkDL/clip-guided-binary-autoencoder)并且RWKV将能够进行txt2img扩散:)我的想法:256x256 rgb图像 - > 32x32x13位潜在 - > 应用 RWKV 计算每个 32x32 网格的转移概率 -> 假设网格是独立的并且使用这些概率“扩散”。
平稳训练 - 无损失峰值! (lr & bsz 变化约 15G 代币)
所有经过训练的模型都将开源。即使在 CPU 上,推理速度也非常快(仅矩阵向量乘法,没有矩阵矩阵乘法),因此您甚至可以在手机上运行 LLM。
工作原理:RWKV 将信息收集到多个通道,当您移动到下一个标记时,这些通道也会以不同的速度衰减。一旦你理解了它就非常简单了。
RWKV 是可并行化的,因为每个通道的时间衰减是数据无关的(且可训练) 。例如,在通常的 RNN 中,您可以将通道的时间衰减从 0.8 调整到 0.5(这些称为“门”),而在 RWKV 中,您只需将信息从 W-0.8 通道移动到 W-0.5 -channel 达到同样的效果。此外,如果您想要额外的性能,您可以将 RWKV 微调为不可并行的 RNN(然后您可以使用前一个标记的后面层的输出)。
这是我的一些待办事项。让我们一起努力:)
HuggingFace 集成(检查 Huggingface/transformers#17230 ),以及优化的 CPU & iOS & Android & WASM & WebGL 推理。 RWKV 是一种 RNN,对于边缘设备非常友好。让我们可以在您的手机上运行法学硕士。
在双向和传销任务以及图像、音频和视频令牌上对其进行测试。我认为 RWKV 可以通过以下方式支持编码器-解码器:对于每个解码器令牌,使用[解码器先前隐藏状态]和[编码器最终隐藏状态]的学习混合。因此,所有解码器令牌都可以访问编码器输出。
现在用一个微小的额外注意力(与 RWKV-4 相比仅增加几行)来训练 RWKV-4a,以进一步改进较小模型的一些困难的零样本任务(例如 LAMBADA)。请参阅https://github.com/BlinkDL/RWKV-LM/commit/a268cd2e40351ee31c30c5f8a5d1266d35b41829
用户反馈:
到目前为止,我已经在相对较小的预训练数据集(大约 10GB 文本)上尝试过基于字符的模型,结果非常好 - 与需要更长的训练时间的模型类似。
亲爱的上帝,rwkv 速度很快。在从头开始训练它后,我切换到另一个选项卡,当我返回时,它发出看似合理的英语和毛利语单词,我离开去微波炉加热一些咖啡,当我回来时,它正在生成完全语法正确的句子。
Sepp Hochreiter 的推文(谢谢!):https://twitter.com/HochreiterSepp/status/1524270961314484227
您也可以在 EleutherAI Discord 中找到我(BlinkDL):https://www.eleuther.ai/get-involved/
重要提示:使用 deepspeed==0.7.0 pytorch-lightning==1.9.5 torch==1.13.1+cu117 和 cuda 11.7.1 或 11.7 (注意 torch2 + deepspeed 有奇怪的错误并损害模型性能)
使用https://github.com/BlinkDL/RWKV-LM/tree/main/RWKV-v4neo(最新代码,兼容v4)。
这是测试法学硕士问答的一个很好的提示。适用于任何模型:(通过最小化 RWKV 1.5B 的 ChatGPT ppls 发现)
prompt = f' n Q & A n n Question: n { qq } n n Detailed Expert Answer: n ' # let the model generate after this
运行 RWKV-4 桩模型:从 https://huggingface.co/BlinkDL 下载模型。在 run.py 中设置 TOKEN_MODE = 'pile' 并运行它。即使在 CPU 上(默认模式),它也很快。
RWKV-4 桩 1.5B 的 Colab :https://colab.research.google.com/drive/1F7tZoPZaWJf1fsCmZ5tjw6sYHiFOYVWM
在浏览器(和 onnx 版本)中运行 RWKV-4 桩模型:请参阅此问题 #7
RWKV-4 Web 演示:https://josephrocca.github.io/rwkv-v4-web/demo/(注意:目前仅贪婪采样)
对于旧的 RWKV-2:请参阅此处的版本,了解 enwik8 上具有 0.72 BPC(dev) 的 27M 参数模型。在 https://github.com/BlinkDL/RWKV-LM/tree/main/RWKV-v2-RNN 中运行 run.py。您甚至可以在浏览器中运行它: https://github.com/BlinkDL/AI-Writer/tree/main/docs/eng https://blinkdl.github.io/AI-Writer/eng/ (这是使用tf.js WASM 单线程模式)。
pip install deepspeed==0.7.0 // pip install pytorch-lightning==1.9.5 // 火炬 1.13.1+cu117
注意:在少量数据上进行训练时,添加权重衰减(0.1 或 0.01)和 dropout(0.1 或 0.01)。尝试 x=x+dropout(att(x)) x=x+dropout(ffn(x)) x=dropout(x+att(x)) x=dropout(x+ffn(x)) 等。
从头开始训练 RWKV-4:运行 train.py,默认情况下使用 enwik8 数据集(解压 https://data.deepai.org/enwik8.zip)。
您将训练“GPT”版本,因为它是可并行的并且训练速度更快。 RWKV-4 可以进行推断,因此使用 ctxLen 1024 进行训练可以适用于 2500+ 的 ctxLen。您可以使用更长的 ctxLen 对模型进行微调,它可以快速适应更长的 ctxLens。
微调 RWKV-4 桩模型:使用 https://github.com/BlinkDL/RWKV-v2-RNN-Pile/tree/main/RWKV-v3 中的“prepare-data.py”将 .txt 标记化为训练。 npy 数据。然后使用 https://github.com/BlinkDL/RWKV-LM/blob/main/RWKV-v4neo/train.py 来训练它。
阅读 src/model.py 中的推理代码,并尝试使用最终的隐藏状态(.xx .aa .bb)作为其他任务的忠实句子嵌入。也许您应该以 .xx 和 .aa/.bb 开头(.aa 除以 .bb)。
用于微调 RWKV-4 桩模型的 Colab:https://colab.research.google.com/github/resloved/RWKV-notebooks/blob/master/RWKV_v4_RNN_Pile_Fine_Tuning.ipynb
大语料库:使用https://github.com/Abel2076/json2binidx_tool将.jsonl转换为.bin和.idx
jsonl 格式示例(每个文档一行):
{"text": "This is the first document."}
{"text": "HellonWorld"}
{"text": "1+1=2n1+2=3n2+2=4"}
由这样的代码生成:
ss = json.dumps({"text": text}, ensure_ascii=False)
out.write(ss + "n")
无限 ctxlen 训练(WIP): https://github.com/Blealtan/RWKV-LM-LoRA/tree/dev-infctx
考虑 RWKV 14B。状态有200个向量,即每个块有5个向量:fp16(xx)、fp32(aa)、fp32(bb)、fp32(pp)、fp16(xx)。
不要 avg pool,因为状态中不同的向量(xx aa bb pp xx)具有非常不同的含义和范围。您也许可以删除 pp。
我建议首先收集每个向量的每个通道的平均值+标准偏差统计量,并对它们进行归一化(注意:归一化应该与数据无关并从各种文本中收集)。然后训练线性分类器。
RWKV-5 是多头的,这里显示的是一个头。每个头还有一个 LayerNorm(因此实际上是 GroupNorm)。
动态混合和动态衰减。示例(对 TimeMix 和 ChannelMix 执行此操作):
TIME_MIX_EXTRA_DIM = 32
self.time_mix_k_w1 = nn.Parameter(torch.empty(args.n_embd, TIME_MIX_EXTRA_DIM).uniform_(-0.01, 0.01))
self.time_mix_k_w2 = nn.Parameter(torch.zeros(TIME_MIX_EXTRA_DIM, args.n_embd))
self.time_mix_v_w1 = nn.Parameter(torch.empty(args.n_embd, TIME_MIX_EXTRA_DIM).uniform_(-0.01, 0.01))
self.time_mix_v_w2 = nn.Parameter(torch.zeros(TIME_MIX_EXTRA_DIM, args.n_embd))
self.time_mix_r_w1 = nn.Parameter(torch.empty(args.n_embd, TIME_MIX_EXTRA_DIM).uniform_(-0.01, 0.01))
self.time_mix_r_w2 = nn.Parameter(torch.zeros(TIME_MIX_EXTRA_DIM, args.n_embd))
self.time_mix_g_w1 = nn.Parameter(torch.empty(args.n_embd, TIME_MIX_EXTRA_DIM).uniform_(-0.01, 0.01))
self.time_mix_g_w2 = nn.Parameter(torch.zeros(TIME_MIX_EXTRA_DIM, args.n_embd))
...
time_mix_k = self.time_mix_k.view(1,1,-1) + (x @ self.time_mix_k_w1) @ self.time_mix_k_w2
time_mix_v = self.time_mix_v.view(1,1,-1) + (x @ self.time_mix_v_w1) @ self.time_mix_v_w2
time_mix_r = self.time_mix_r.view(1,1,-1) + (x @ self.time_mix_r_w1) @ self.time_mix_r_w2
time_mix_g = self.time_mix_g.view(1,1,-1) + (x @ self.time_mix_g_w1) @ self.time_mix_g_w2
xx = self.time_shift(x)
xk = x * time_mix_k + xx * (1 - time_mix_k)
xv = x * time_mix_v + xx * (1 - time_mix_v)
xr = x * time_mix_r + xx * (1 - time_mix_r)
xg = x * time_mix_g + xx * (1 - time_mix_g)
使用并行化模式快速生成状态,然后使用微调的完整RNN(令牌n的层可以使用令牌n-1的所有层的输出)进行顺序生成。
现在时间衰减就像 0.999^T (0.999 是可学习的)。将其更改为 (0.999^T + 0.1) 之类的内容,其中 0.1 也是可学习的。 0.1 部分将永远保留。或者,A^T + B^T + C = 快衰减 + 慢衰减 + 常数。甚至可以使用不同的公式(例如,对于衰减分量,使用 K^2 而不是 e^K,或者不进行归一化)。
在某些通道中使用复值衰减(因此,旋转而不是衰减)。
注入一些可训练和可推断的位置编码?
除了 2d 旋转之外,我们还可以尝试其他李群,例如 3d 旋转( SO(3) )。非阿贝尔 RWKV 哈哈。
RWKV 在模拟设备上可能非常有用(搜索模拟矩阵矢量乘法和光子矩阵矢量乘法)。 RNN 模式对硬件非常友好(内存中处理)。也可以是 SNN (https://github.com/ridgerchu/SpikeGPT)。我想知道它是否可以针对量子计算进行优化。
可训练的初始隐藏状态 (xx aa bb pp xx)。
分层(甚至行/列、元素)LR,并测试 Lion 优化器。
self.pos_emb_x = nn.Parameter(torch.zeros((1,args.my_pos_emb,args.n_embd)))
self.pos_emb_y = nn.Parameter(torch.zeros((args.my_pos_emb,1,args.n_embd)))
...
x = x + pos_emb_x + pos_emb_y
也许我们可以通过简单地重复上下文来提高记忆力(我想 2 次就足够了)。示例:参考资料 -> 参考资料(再次) -> 问题 -> 答案
这个想法是确保 vocab 中的每个标记都理解其长度和原始 UTF-8 字节。
让 a = max(len(token)) 表示 vocab 中的所有 token。定义 AA : float[a][d_emb]
对于 vocab 中的所有 token,令 b = max(len_in_utf8_bytes(token)) 。定义 BB : float[b][256][d_emb]
对于 vocab 中的每个标记 X,令 [x0, x1, ..., xn] 为其原始 UTF-8 字节。我们将为其嵌入 EMB(X) 添加一些额外的值:
EMB(X) += AA[len(X)] + BB[0][x0] + BB[1][x1] + ... + BB[n][xn] (注:AA BB 是可学习权重)
我有一个改进标记化的想法。我们可以对一些通道进行硬编码以使其具有含义。例子:
通道 0 =“空间”
通道 1 =“首字母大写”
通道 2 =“所有字母大写”
所以:
嵌入“abc”:[0, 0, 0, x0, x1, x2 , ..]
嵌入“abc”:[1, 0, 0, x0, x1, x2, ..]
“Abc”的嵌入:[1, 1, 0, x0, x1, x2, ..]
嵌入“ABC”:[0, 0, 1, x0, x1, x2, ...]
......
所以他们将共享大部分嵌入。我们可以快速计算“abc”所有变体的输出概率。
注意:上述方法假设 p(" xyz") / p("xyz") 对于任何 "xyz" 都是相同的,这可能是错误的。
更好:将 emb_space emb_capitalize_first emb_capitalize_all 定义为 emb 的函数。
也许最好的方法是:让 'abc' ' abc' 等共享最后 90% 的嵌入。
此时,我们所有的分词器花费了太多的项目来表示“abc”“abc”“Abc”等的所有变体。此外,如果其中一些变体在数据集中很少见,则模型无法发现这些变体实际上是相似的。这里的方法可以改善这一点。我计划在新版本的 RWKV 中对此进行测试。
示例(单轮问答):
生成所有 wiki 文档的最终状态。
对于任何用户Q,找到最好的wiki文档,并使用其最终状态作为初始状态。
训练模型直接生成任意用户 Q 的最优初始状态。
然而,对于多轮问答来说,这可能有点棘手:)
RWKV 的灵感来自 Apple 的 AFT (https://arxiv.org/abs/2105.14103)。
此外,它还使用了我的一些技巧,例如:
SmallInitEmb:https://github.com/BlinkDL/SmallInitEmb(适用于所有变压器),有助于提高嵌入质量,并稳定 Post-LN(这就是我正在使用的)。
Token-shift:https://github.com/BlinkDL/RWKV-LM#token-shift-time-shift-mixing(适用于所有变压器),对于字符级模型特别有帮助。
Head-QK:https://github.com/BlinkDL/RWKV-LM#the-head-qk-trick-learning-to-copy-and-avoid-tokens(适用于所有 Transformer)。注意:这很有帮助,但我在 Pile 模型中禁用了它以保持 100% RNN。
FFN 中的额外 R 门(适用于所有变压器)。我还使用 Primer 中的 reluSquared。
更好的初始化:我将大部分矩阵初始化为零(请参阅 https://github.com/BlinkDL/RWKV-LM/blob/main/RWKV-v2-RNN/src/model.py 中的 RWKV_Init)。
您可以将一些参数从小模型转移到大模型(注意:我也对它们进行排序和平滑),以实现更快更好的收敛(请参阅https://www.reddit.com/r/MachineLearning/comments/umq908/r_rwkvv2rnn_a_parallelizing_rnn_with /)。
我的 CUDA 内核:https://github.com/BlinkDL/RWKV-CUDA 以加速训练。
abcd 因子共同构建时间衰减曲线:[X, 1, W, W^2, W^3, ...]。
写出“token at pos 2”和“token at pos 3”的公式,你就会明白:
kv/k是记忆机制。如果通道中的 W 接近 1,则具有高 k 的令牌可以被记住很长时间。
R 门对于性能很重要。 k = 该令牌的信息强度(将传递给未来的令牌)。 r = 是否将信息应用于此令牌。
对 SA 和 FF 层中的 R / K / V 使用不同的可训练 TimeMix 因子。例子:
xx = self . time_shift ( x )
xk = x * self . time_mix_k + xx * ( 1 - self . time_mix_k )
xv = x * self . time_mix_v + xx * ( 1 - self . time_mix_v )
xr = x * self . time_mix_r + xx * ( 1 - self . time_mix_r )
使用 preLN 代替 postLN (更稳定且收敛更快):
if self . layer_id == 0 :
x = self . ln0 ( x )
x = x + self . att ( self . ln1 ( x ))
x = x + self . ffn ( self . ln2 ( x ))
RWKV-3 GPT 模式的构建块与通常的 preLN GPT 类似。
唯一的区别是嵌入后有一个额外的逻辑节点。请注意,您可以在完成训练后将此 LN 吸收到嵌入中。
x = self . emb ( idx ) # input: idx = token indices
x = self . ln_emb ( x ) # extra LN after embedding
x = x + self . att_0 ( self . ln_att_0 ( x )) # preLN
x = x + self . ffn_0 ( self . ln_ffn_0 ( x ))
...
x = x + self . att_n ( self . ln_att_n ( x ))
x = x + self . ffn_n ( self . ln_ffn_n ( x ))
x = self . ln_head ( x ) # final LN before projection
x = self . head ( x ) # output: x = logits
将 emb 初始化为微小值非常重要,例如 nn.init.uniform_(a=-1e-4, b=1e-4),以利用我的技巧 https://github.com/BlinkDL/SmallInitEmb。
对于 1.5B RWKV-3,我在 8 * A100 40G 上使用 Adam(无 wd、无 dropout)优化器。
batchSz = 32 * 896,ctxLen = 896。我使用的是tf32,所以batchSz有点小。
对于前15B代币,LR固定为3e-4,beta=(0.9,0.99)。
然后我设置 beta=(0.9, 0.999),并对 LR 进行指数衰减,在 332B 令牌处达到 1e-5。
RWKV-3 没有通常意义上的任何关注,但无论如何我们都会将此块称为 ATT。
B , T , C = x . size () # x = (Batch,Time,Channel)
# Mix x with the previous timestep to produce xk, xv, xr
xx = self . time_shift ( x ) # self.time_shift = nn.ZeroPad2d((0,0,1,-1))
xk = x * self . time_mix_k + xx * ( 1 - self . time_mix_k )
xv = x * self . time_mix_v + xx * ( 1 - self . time_mix_v )
xr = x * self . time_mix_r + xx * ( 1 - self . time_mix_r )
# Use xk, xv, xr to produce k, v, r
k = self . key ( xk ). transpose ( - 1 , - 2 )
v = self . value ( xv ). transpose ( - 1 , - 2 )
r = self . receptance ( xr )
k = torch . clamp ( k , max = 60 ) # clamp k to avoid overflow
k = torch . exp ( k )
kv = k * v
# Compute the W-curve = [e^(-n * e^time_decay), e^(-(n-1) * e^time_decay), ..., 1, e^(time_first)]
self . time_w = torch . cat ([ torch . exp ( self . time_decay ) * self . time_curve . to ( x . device ), self . time_first ], dim = - 1 )
w = torch . exp ( self . time_w )
# Use W to mix kv and k respectively. Add K_EPS to wk to avoid divide-by-zero
if RUN_DEVICE == 'cuda' :
wkv = TimeX . apply ( w , kv , B , C , T , 0 )
wk = TimeX . apply ( w , k , B , C , T , K_EPS )
else :
w = w [:, - T :]. unsqueeze ( 1 )
wkv = F . conv1d ( nn . ZeroPad2d (( T - 1 , 0 , 0 , 0 ))( kv ), w , groups = C )
wk = F . conv1d ( nn . ZeroPad2d (( T - 1 , 0 , 0 , 0 ))( k ), w , groups = C ) + K_EPS
# The RWKV formula
rwkv = torch . sigmoid ( r ) * ( wkv / wk ). transpose ( - 1 , - 2 )
rwkv = self . output ( rwkv ) # final output projection
self.key、self.receptance、self.output 矩阵均初始化为零。
time_mix、time_decay、time_first 向量是从较小的训练模型转移而来的(注意:我也对它们进行排序和平滑)。
与通常的GPT相比,FFN块有三个技巧:
我的 time_mix 技巧。
来自 Primer 论文的 sqReLU。
一个额外的接收门(类似于 ATT 块中的接收门)。
# Mix x with the previous timestep to produce xk, xr
xx = self . time_shift ( x )
xk = x * self . time_mix_k + xx * ( 1 - self . time_mix_k )
xr = x * self . time_mix_r + xx * ( 1 - self . time_mix_r )
# The usual FFN operation
k = self . key ( xk )
k = torch . square ( torch . relu ( k )) # from the Primer paper
kv = self . value ( k )
# Apply an extra receptance-gate to kv
rkv = torch . sigmoid ( self . receptance ( xr )) * kv
return rkv
self.value、self.receptance 矩阵均初始化为零。
令 F[t] 为 t 时的系统状态。
令 x[t] 为 t 处的新外部输入。
在 GPT 中,预测 F[t+1] 需要考虑 F[0]、F[1]、.. F[t]。所以生成长度为T的序列需要O(T^2)。
GPT 的简化公式:
它在理论上非常强大,但这并不意味着我们可以通过通常的优化器充分利用它的功能。我怀疑损失情况对于我们目前的方法来说太困难了。
与RWKV的简化公式相比(并行模式,看起来类似于Apple的AFT):
R、K、V 是可训练矩阵,W 是可训练向量(每个通道的时间衰减因子)。
在GPT中,F[i]对F[t+1]的贡献由 加权。
在RWKV-2中,F[i]对F[t+1]的贡献由 加权。
重点来了:我们可以将其重写为 RNN(递归公式)。笔记:
因此验证起来很简单:
其中 A[t] 和 B[t] 分别是上一步的分子和分母。
我相信 RWKV 是高性能的,因为 W 就像重复应用对角矩阵。注意 (P^{-1} DP)^n = P^{-1} D^n P,因此它类似于重复应用一般可对角化矩阵。
此外,可以将其转换为连续 ODE(有点类似于状态空间模型)。我稍后再写。
我有一个使用 LM(变压器、RWKV 等)的 [文本 --> 32x32 RGB 图像] 的想法。很快就会进行测试。
首先是LM损失(而不是L2损失),所以图像不会模糊。
其次,色彩量化。例如,仅允许 R/G/B 8 个级别。那么图像词汇大小为 8x8x8 = 512(对于每个像素),而不是 2^24。因此,一个 32x32 RGB 图像 = 一个 len1024 的 vocab512(图像标记)序列,这是普通 LM 的典型输入。 (稍后我们可以使用扩散模型来上采样并生成 RGB888 图像。我们也许也可以使用 LM 来实现这一点。)
第三,二维位置嵌入易于模型理解。例如,将 one-hot X & Y 坐标添加到前 64(=32+32) 个通道。假设像素位于 x=8、y=20,那么我们将向通道 8 和通道 52 加 1(=32+20)。此外,我们可能可以将浮动 X 和 Y 坐标(标准化为 0~1 范围)添加到另外 2 个通道。和其他定期职位。编码也可能有帮助(将测试)。
最后,在DataLoader中进行颜色量化时进行RandRound。例如,如果浮动级别为 4.578,则有 57.8% 的机会使用 5,并且有 (1-57.8%) 的机会使用 4。我们可以在预测中同时允许 4 和 5,但损失将为如果预测为 4,则更高。
多任务训练也可能有所帮助。我将尝试此数据集格式: [TxtFirst] [Img 的描述(txt 标记)] [Img] [img 标记] 有时 [ImgFirst] [img 标记] [Txt] [Img 的描述(txt 标记)] ... imgs 的顺序应在 DataLoader 中随机化,并且 [TxtFirst] [ImgFirst] [Img] [Txt] 是特殊标记,并对完整数据集进行随机采样。因此有时模型会先看到 img 标记,然后看到相应的 txt 标记,这是一个 [img -> txt] 任务。模型将看到一些部分图像和部分文本。我认为字符级 LM 可能有助于模型在图像上写入正确的文本。
我正在使用一种技巧来确定性但足够随机地对桩进行采样。
假设该堆有 x 个块(一个块 = ctx_len 令牌)。
选择一个小于 x 的质数 p,并确保 p = 2 (mod 3)。
使用 (step * step * step) mod p 对其进行采样。为步骤添加一些偏差以获得额外的随机性。
我们提出了一种新的采样方法,称为 top-px:
它就像 top-p,唯一的区别是你还保留了所有 prob > x 的 token。
首先尝试 x = 0.01。
我提出了一种简单的新方法来找到更好的 LR 调度。该方法对于大型语言模型来说具有成本效益且实用。结论是我们可以对 LR 的损失曲线动态(现象学)进行建模,并且可以使用变分方法直接计算出漂亮的封闭式 LR 曲线。此外,我们可以以合理的精度预测最终损失。
更新:在“结论 1”中,使用最佳拟合机制(忽略我们的近似值崩溃的初始步骤)来拟合参数。
试试这个:固定 lr 1 小时,然后在 12 小时内指数衰减到 0.2 * lr,并选择 t=[1hr, 13hr] 段。
在最后三个图中,黑色 = 新 LR 计划的预测损失曲线,蓝色 = 原始(未优化)实际损失曲线,橙色 = 新 LR 计划。
我们提出了 RWKV 语言模型,具有交替的时间混合层和通道混合层:
R、K、V 由输入的线性变换生成,W 是参数。 RWKV的思想是将注意力分解为R(target) * W(src, target) * K(src)。所以我们可以称R为“receptance”,sigmoid表示它在0~1范围内。
时间混合类似于 AFT (https://arxiv.org/abs/2105.14103)。有两点不同。
(1) 我们改变了归一化(分母)。对于屏蔽语言模型,我们定义:
(更新:我们在 v2 中使用原始的 AFT 标准化)
初始化K和R矩阵(以及输出投影矩阵)为零,以进行快速和稳定的收敛。
(2)我们分解W_ {T,U,C}并介绍多头W(这里H是C的相应负责人):
此外,我们将时间混合层的最终输出乘以γ(t)。 αβγ因子的原因是,当t较小时,上下文大小较小,并且可以使用αβγ因子补偿。
(更新:我们在V2-RNN中删除αβγ因子,并将W限制为简单形式,因此能够将其重写为RNN)
频道 - 混合物类似于Geglu(https://arxiv.org/abs/2002.05202),具有额外的R因子。将R和W矩阵初始化为零,以进行快速和稳定的收敛。
最后,我们如(https://github.com/blinkdl/mingpt-tuned)添加了额外的令牌转移(时变混合)。
令牌移位明确使用(该令牌的通道的一半)和(上述令牌的一半)来生成所有向量(qKV,rwkv,...)。
self.time_shift = nn.ZeroPad2d((0,0,1,-1))
x = torch.cat([self.time_shift(x[:, :, :C//2]), x[:, :, C//2:]], dim = -1)
将频道除以2和Shift-1非常适合char-Level英语和Char-Level中文LM。
但是,对于BPE级英语LM,只有在嵌入足够大的情况下才有效(至少1024-因此通常的小L12-D768型号还不够)。
我关于代币迁移的有效性的理论:
当我们训练GPT时,令牌的隐藏表示必须完成两个不同的对象:
预测接下来的令牌。有时这很容易(显而易见的旁边值)。
收集所有以前的上下文信息,因此以后的令牌可以使用它。这总是很难。
转移的渠道可以集中在(2)上,因此我们有良好的信息传播。就像某种残留连接,或变压器内部的小RNN。
您也可以在通常的QKV自我注意力中使用令牌换档。我看了看权重,发现V确实喜欢移动的频道,因此对于Q而言。我还发现您可能想在更高的层中使用更少的混合。
PS在此存储库中有一个MHA_PRO模型,其性能很强。尝试一下:)
在通常的变压器中,一个小型模型很难在上下文中复制令牌(例如人名)。我们将额外的Q&K添加到最终输出中,以便模型可以在上下文中直接复制(或避免)令牌。之后,如果您查看学习的权重,则模型将自学(命名实体识别)。
q = self.head_q(x)[:,:T,:] # projecting to 256-d
k = self.head_k(x)[:,:T,:] # projecting to 256-d
c = (q @ k.transpose(-2, -1)) * (1.0 / 256)
c = c.masked_fill(self.copy_mask[:T,:T] == 0, 0)
c = c @ F.one_hot(idx, num_classes = self.config.vocab_size).float()
x = self.head(x) + c
注意:当一个令牌在上下文中多次发生时,最好使用max(prob)而不是sum(prob)。
我们还提出了一种称为top-a的新采样方法(如src/utils.py中):
(1)在SoftMax之后找到最大概率P_MAX。
(2)删除所有概率低于0.2 * POW(P_MAX,2)的条目。因此,它是自适应的,因此“ top-a”。
(3)随意调整0.2和2因子。首先调音0.2。
top-a的想法:
probs = F.softmax(logits, dim=-1)
limit = torch.pow(torch.max(probs), 2) * 0.02
logits[probs < limit] = -float('Inf')
字符级损失在简单书中-92数据集https://dldata-public.s3.us-east-2.amazonaws.com/simplebooks.zips.zip
灰色:通常的MHA+旋转+geglu-性能不佳。 17.2m参数。
红色:RWKV(“线性”注意) - VRAM友好 - 当CTX窗口长时间 - 性能良好时。 16.6m参数。
绿色:MHA+旋转+geglu+token_shift。 17.2m参数。
蓝色:MHA_PRO(具有各种调整和RWKV型-FFN的MHA) - 慢 - 需要更多的VRAM-良好的性能。 16.6m参数。
@software{peng_bo_2021_5196578,
author = {PENG Bo},
title = {BlinkDL/RWKV-LM: 0.01},
month = aug,
year = 2021,
publisher = {Zenodo},
version = {0.01},
doi = {10.5281/zenodo.5196577},
url = {https://doi.org/10.5281/zenodo.5196577}
}
我们对RWKV使用仔细的初始化来获得快速收敛 - 正交矩阵具有适当的缩放和特殊的Time_W曲线。检查型号的详细信息。
一些学习的时间_W示例: