介绍RWKV – 具有Transformer优势的RNN

RWKV是一种结合了Transformer和RNN优势的模型

ChatGPT和聊天机器人应用在自然语言处理(NLP)领域引起了广泛关注。社区不断寻求强大、可靠且开源的模型,用于其应用和用例。这些强大模型的崛起源于基于变压器模型的民主化和广泛采用,该模型最早由Vaswani等人于2017年提出。这些模型在循环神经网络(RNNs)等基于先前SoTA NLP模型的模型上取得了显著的性能优势,而这些模型在那篇论文之后被认为已经过时。通过本博文,我们将介绍一种新架构RWKV的集成,该架构结合了RNNs和变压器的优势,并最近集成到Hugging Face transformers库中。

RWKV项目概述

RWKV项目由Bo Peng发起和领导,他积极贡献并维护该项目。社区通过官方discord频道组织,不断改进项目的各个方面,如性能(RWKV.cpp、量化等)、可扩展性(数据集处理和抓取)和研究(聊天微调、多模态微调等)。RWKV模型的训练所使用的GPU由Stability AI捐赠。

您可以加入官方discord频道参与进来,并在以下两篇博文中了解RWKV背后的一般思想:https://johanwind.github.io/2023/03/23/rwkv_overview.html / https://johanwind.github.io/2023/03/23/rwkv_details.html

变压器架构与RNNs

RNN架构是最早被广泛使用的用于处理数据序列的神经网络架构之一,与处理固定大小输入的经典架构相反。它以当前的“记号”(即数据流的当前数据点)、先前的“状态”为输入,并计算出预测的下一个记号和预测的下一个状态。然后使用新状态来计算下一个记号的预测,依此类推。RNN还可以以不同的“模式”使用,因此可以在不同的场景下应用RNNs,如Andrej Karpathy的博文所示,例如一对一(图像分类)、一对多(图像字幕生成)、多对一(序列分类)、多对多(序列生成)等。

由于RNN在每个步骤使用相同的权重进行预测,它们在长序列的信息记忆方面存在困难,这是由于梯度消失问题所致。为了解决这个限制,已经引入了新的架构,例如LSTM或GRU。然而,变压器架构迄今为止被证明是解决这个问题最有效的方法。

在变压器架构中,输入记号在自注意模块中同时被处理。首先,使用查询、键和值权重将记号线性投影到不同的空间中。然后直接使用生成的矩阵来计算注意力分数(通过softmax函数),然后乘以值隐藏状态以获得最终的隐藏状态。这种设计使得架构能够有效地解决长序列问题,同时相对于RNN模型,推理和训练速度更快。

在训练过程中,与传统的RNN和CNN相比,变压器架构具有几个优势。其中最重要的优势之一是其学习上下文表示的能力。与RNN和CNN一次处理一个单词的输入序列不同,变压器架构将输入序列作为一个整体进行处理。这使得它能够捕捉到序列中单词之间的长距离依赖关系,这对于语言翻译和问题回答等任务特别有用。

在推理过程中,RNN在速度和内存效率方面具有一些优势。这些优势包括简单性,因为只需要进行矩阵-向量操作,并且内存要求在推理过程中不会增长。此外,由于计算只作用于当前记号和状态,因此计算速度在上下文窗口长度上保持不变。

RWKV架构

RWKV受到了Apple的无注意力变压器的启发。该架构经过精心简化和优化,使其可以转换为RNN。此外,还添加了一些技巧,例如TokenShiftSmallInitEmb(技巧列表在官方GitHub存储库的README中列出),以提高其与GPT的性能匹配。如果没有这些技巧,模型的性能将不如此出色。在训练方面,目前已经有一个可以扩展到14B参数的训练基础设施,并且在RWKV-4(最新版本)中已经迭代修复了一些问题,如数值不稳定性。

RWKV作为RNN和transformer的结合体

如何将transformer和RNN的优点结合起来?基于transformer的模型的主要缺点是,在上下文窗口超过一定值时,同时为整个序列计算注意力分数可能变得困难。

RNN本身支持非常长的上下文长度 – 仅受训练中所见的上下文长度限制,但通过仔细编码可以扩展到数百万个标记。目前,已经训练了一个上下文长度为8192(ctx8192)的RWKV模型,它们的速度与ctx1024模型一样快,需要相同数量的内存。

传统RNN模型的主要缺点以及RWKV的不同之处:

  1. 传统RNN模型无法利用非常长的上下文(当作为语言模型时,LSTM只能处理约100个标记)。然而,RWKV可以利用数千个标记甚至更多,如下所示:
  1. 传统RNN模型在训练时无法并行化。RWKV类似于“线性化的GPT”,训练速度比GPT更快。

通过将这两个优点结合到一个单一的架构中,希望RWKV能够成为超越其组成部分总和的东西。

RWKV注意力机制

该模型架构与经典的基于transformer的模型非常相似(即嵌入层、多个相同的层、层归一化和因果语言建模头部以预测下一个标记)。唯一的区别在于注意力层,它与传统的基于transformer的模型完全不同。

为了更全面地理解注意力层,我们建议深入研究Johan Sokrates Wind在博客文章中提供的详细解释。

现有的检查点

纯语言模型:RWKV-4模型

大多数采用的RWKV模型的参数范围从约170M到14B。根据RWKV概述博客文章,在Pile数据集上训练的这些模型在不同的基准测试中与其他SoTA模型进行了评估,并且它们似乎表现相当好,与它们相比具有非常可比的结果。

指令微调/聊天版本:RWKV-4 Raven

Bo还训练了RWKV架构的“聊天”版本,即RWKV-4 Raven模型。它是在ALPACA、CodeAlpaca、Guanaco、GPT4All、ShareGPT等上进行微调的RWKV-4堆(在Pile数据集上预训练的RWKV模型)。该模型有多个版本,包括在不同语言(仅英语、英语+中文+日语、英语+日语等)和不同大小(1.5B参数、7B参数、14B参数)上训练的模型。

所有HF转换的模型都可以在Hugging Face Hub的RWKV组织中找到。

🤗 Transformers集成

该架构已经添加到transformers库中,感谢这个Pull Request。截至撰写时,您可以通过从源代码安装transformers或使用库的main分支来使用它。该架构与库紧密集成,您可以像使用其他架构一样使用它。

让我们通过下面的一些示例来了解。

文本生成示例

要生成给定输入提示的文本,您可以使用pipeline生成文本:

from transformers import pipeline

model_id = "RWKV/rwkv-4-169m-pile"

prompt = "\n在一个令人震惊的发现中,科学家们发现了一群生活在西藏的偏远、以前未被探索过的山谷中的龙。对研究人员来说更令人惊讶的是,这些龙竟然能说一口流利的中文。"

pipe = pipeline("text-generation", model=model_id)
print(pipe(prompt, max_new_tokens=20))
>>> [{'generated_text': '\n在一个令人震惊的发现中,科学家们发现了一群生活在西藏的偏远、以前未被探索过的山谷中的龙。对研究人员来说更令人惊讶的是,这些龙竟然能说一口流利的中文。\n\n研究人员发现这些龙能够相互交流,并且它们能'}]

或者您可以从下面的代码片段中运行和启动:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("RWKV/rwkv-4-169m-pile")
tokenizer = AutoTokenizer.from_pretrained("RWKV/rwkv-4-169m-pile")

prompt = "\n在一个令人震惊的发现中,科学家发现了一群生活在西藏偏远、以前未被探索过的山谷中的龙。更令研究人员惊讶的是,这些龙竟然会说一口流利的中文。"

inputs = tokenizer(prompt, return_tensors="pt")
output = model.generate(inputs["input_ids"], max_new_tokens=20)
print(tokenizer.decode(output[0].tolist()))
>>> 在一个令人震惊的发现中,科学家发现了一群生活在西藏偏远、以前未被探索过的山谷中的龙。更令研究人员惊讶的是,这些龙竟然会说一口流利的中文。\n\n研究人员发现这些龙能够相互交流,并且它们

使用Raven模型(聊天模型)

您可以在alpaca风格下提示聊天模型,以下是一个示例:

from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = "RWKV/rwkv-raven-1b5"

model = AutoModelForCausalLM.from_pretrained(model_id).to(0)
tokenizer = AutoTokenizer.from_pretrained(model_id)

question = "告诉我关于渡鸦的事情"
prompt = f"### 指令: {question}\n### 响应:"

inputs = tokenizer(prompt, return_tensors="pt").to(0)
output = model.generate(inputs["input_ids"], max_new_tokens=100)

print(tokenizer.decode(output[0].tolist(), skip_special_tokens=True))
>>> ### 指令: 告诉我关于渡鸦的事情
### 响应: 渡鸦是一种生活在中东和北非的鸟类。它们以其智慧、适应能力和在各种环境中生存的能力而闻名。渡鸦以其智慧、适应能力和在各种环境中生存的能力而闻名。它们以其智慧、适应能力和在各种环境中生存的能力而闻名。

根据 Bo 的说法,更好的指令技巧在这条 Discord 消息中有详细说明(确保在点击之前加入频道)

| |

模型权重转换

任何用户都可以通过简单运行“transformers”库中提供的转换脚本,将原始的 RWKV 权重转换为 HF 格式。首先将“raw”权重推送到 Hugging Face Hub(假设该仓库为 RAW_HUB_REPO ,原始文件为 RAW_FILE ),然后运行转换脚本:

python convert_rwkv_checkpoint_to_hf.py --repo_id RAW_HUB_REPO --checkpoint_file RAW_FILE --output_dir OUTPUT_DIR

如果您想将转换后的模型推送到 Hub 上(假设在 dummy_user/converted-rwkv 下),在推送模型之前不要忘记使用 huggingface-cli login 登录,然后运行:

python convert_rwkv_checkpoint_to_hf.py --repo_id RAW_HUB_REPO --checkpoint_file RAW_FILE --output_dir OUTPUT_DIR --push_to_hub --model_name dummy_user/converted-rwkv

未来工作

多语言 RWKV

Bo 目前正在开发一个多语言语料库来训练 RWKV 模型。最近发布了一个新的多语言分词器。

面向社区和研究项目

RWKV 社区非常活跃,正在进行几个后续方向的工作,您可以在 Discord 的专用频道中找到一些很棒的项目列表(确保在点击链接之前加入频道)。还有一个专门研究这种架构的频道,欢迎加入并做出贡献!

模型压缩和加速

由于只需要矩阵-向量操作,RWKV是非标准和实验性计算硬件(如光子处理器/加速器)的理想选择。

因此,该架构也可以自然地从经典加速和压缩技术(如ONNX,4位/8位量化等)中受益,并且我们希望这将与架构的transformers集成一起,为开发者和从业者提供民主化的方式。

RWKV还可以从optimum库提出的加速技术中受益。其中一些技术在rwkv.cpp存储库或rwkv-cpp-cuda存储库中得到了突出。

致谢

Hugging Face团队要感谢Bo和RWKV社区的时间,并回答我们有关架构的问题。我们还要感谢他们的帮助和支持,并期待在HF生态系统中看到更多RWKV模型的应用。我们还要感谢Johan Wind在他关于RWKV的博客文章中的工作,这对我们理解架构及其潜力帮助很大。最后,我们要强调并感谢ArEnSc在最初的transformers PR上的工作。同时,也要向Merve Noyan、Maria Khalusova和Pedro Cuenca致以最高的赞誉,因为他们很友好地审查了这篇博客文章,使其变得更好!

引用

如果您在工作中使用了RWKV,请使用以下cff引用。