MLC-LLM 部署RWKV World系列模型实战(3B模型Mac M2解码可达26tokens/s)

2023-11-15

0x0. 前言

我的 ChatRWKV 学习笔记和使用指南 这篇文章是学习RWKV的第一步,然后学习了一下之后决定自己应该做一些什么。所以就在RWKV社区看到了这个将RWKV World系列模型通过MLC-LLM部署在各种硬件平台的需求,然后我就开始了解MLC-LLM的编译部署流程和RWKV World模型相比于MLC-LLM已经支持的Raven系列模型的特殊之处。

MLC-LLM的编译部署流程在MLC-LLM的官方文档已经比较详细了,但这部分有一些隐藏的坑点需要你去发现,比如现在要支持的RWKV-World模型它的Tokenizer是自定义的,并不是Huggingface的格式,这就导致我们不能使用MLC-LLM去直接编译这个模型,也不能使用预编译好的MLC-LLM二进制库去运行这个模型了。另外,在编译MLC-LLM仓库之前我们需要先编译Relax仓库而不是原始的TVM仓库,Relax可以认为是TVM的一个fork,在此基础上支持了Relax这个新一代的IR,这部分背景建议读者看一下我这个仓库的相关链接:

https://github.com/BBuf/tvm_mlir_learn

这个仓库已经揽下1.4k star,谢谢读者们支持。

从RWKV社区了解到,RWKV-World系列模型相比于Raven系列,推理代码和模型都是完全一样,不一样的地方主要是tokenizer是自定义的,并且system prompt不同。

在编译Relax的时候需要按需选择自己的编译平台进行编译,编译完之后 MLC-LLM 会通过 TVM_HOME 这个环境变量来感知 Relax 的位置,并且Relax编译时开启的选项要和MLC-LLM编译的选项匹配上,这样才可以在指定平台上进行正确的编译和推理。

在适配 RWKV-World 1.5B时,由于模型比较小对逗号比较敏感,导致第一层就炸了精度,最终挂在sampler里面,这个地方我定位2个晚上,后来mlc-ai官方的冯思远告诉我在 MLC-LLM 里如何逐层打印精度之后,我最终定位到了问题。并且在 RWKV 社区里面了解到了这个现象之前就出现过,那就是1.5B的模型第一层需要用FP32来计算,不然会炸精度,我后续实验了RWKV-4-World 3B/7B,这个现象就没有了。

另外,模型的组织格式也是值得注意的一点,并不是在任意位置编译好模型都可以在运行时被 MLC-LLM 正确发现。我大概花了快一周工作外时间在 MLC-LLM 上来支持 RWKV-World 系列模型,工作内容主要为:

  • 将大缺弦的 https://github.com/daquexian/faster-rwkv 仓库中的 RWKV World模型tokenizer实现挂到 mlc-ai 的 tokenizers.cpp 中,作为一个 3rd 库提供给MLC-LLM。合并的PR为:https://github.com/mlc-ai/tokenizers-cpp/pull/14。
  • 在上面的基础上,在MLC-LLM中支持 RWKV World系列模型的部署,对齐 World 系列模型的 Prompt ,获得良好的对话效果。分别在 Apple M2和A800显卡上进行了部署和测试。PR为:https://github.com/mlc-ai/mlc-llm/pull/848 ,这个pr还wip,如果你现在要使用的话可以直接切到这个pr对应的分支就可以了。
  • debug到1.5B RWKV World小模型会炸精度的bug,相当于踩了个大坑。

我要特别感谢 mlc-ai 官方的冯思远在我部署过程中提供的支持以及帮我Review让代码合并到 mlc-ai 社区,以及感谢大缺弦的 RWKV World Tokenizer c++实现以及在编译第三方库时帮我解决的一个bug。

以下是MLC-LLM 部署RWKV World系列模型教程,尽量提供大家部署最不踩坑的实践。

效果:

在这里插入图片描述

0x1. 将RWKV-4-World-7B部署在A800上

准备工作

  • RWKV-4-World模型地址:https://huggingface.co/StarRing2022/RWKV-4-World-7B
  • 下载这里:https://github.com/BBuf/rwkv-world-tokenizer/releases/tag/v1.0.0 的 tokenizer_model.zip并解压为tokenizer_model文件,这是RWKV World系列模型的Tokenizer文件。
  • 克隆好 https://github.com/mlc-ai/mlc-llm 和 https://github.com/mlc-ai/relax ,注意克隆的时候一定要加上 –recursive 参数,这样才会把它们依赖的第三方库也添加上。

编译Relax

git clone --recursive git@github.com:mlc-ai/relax.git
cd relax
mkdir build
cd build
cp ../cmake/config.cmake ./

然后修改build目录下的config.cmake文件,由于我这里是在A800上面编译,我改了以下设置:

set(USE_CUDA ON)
set(USE_CUTLASS ON)
set(USE_CUBLAS ON)

即启用了CUDA,并开启了2个加速库CUTLASS和CUBLAS。然后在build目录下执行cmake .. && make -j32 即可。

最后可以考虑把Relax添加到PYTHONPATH环境变量里面使得全局可见,在~/.bashrc上输入以下内容:

export TVM_HOME=/bbuf/relax
export PYTHONPATH=$TVM_HOME/python:${PYTHONPATH}

然后source ~/.bashrc即可。

编译和安装MLC-LLM

git clone --recursive git@github.com:mlc-ai/mlc-llm.git
cd mlc-llm/cmake
python3 gen_cmake_config.py

执行python3 gen_cmake_config.py 可以按需选择需要打开的编译选项,比如我这里就选择打开CUDA,CUBLAS,CUTLASS,另外需要注意的是这里的 TVM_HOME 路径需要设置为上面编译的Relax路径。

然后执行下面的操作编译:

cd ..
mkdir build
cp cmake/config.cmake build
cd build
cmake ..
make -j32

这里编译时还需要安装一下rust,按照建议的命令安装即可,编译完成之后即安装上了mlc-llm提供的聊天程序mlc_chat_cli。然后为了做模型转换和量化,我们还需要在mlc-llm目录下执行一下pip install .安装mlc_llm包。

模型转换

模型转换这里基本就是参考这个教程了:https://mlc.ai/mlc-llm/docs/compilation/compile_models.html 。

例如我们执行python3 -m mlc_llm.build --hf-path StarRing2022/RWKV-4-World-7B --target cuda --quantization q4f16_1 就可以将RWKV-4-World-7B模型权重量化为4个bit,然后activation还是以FP16的方式存储。

在这里插入图片描述
target 则指定我们要在什么平台上去运行,这里会将整个模型构成的图编译成一个动态链接库(也就是TVM的IRModule)供后续的mlc_chat_cli程序(这个是在编译mlc-llm时产生的)调用。

这里默认会在当前目录下新建一个dist/models文件夹来存量化后模型和配置文件以及链接库,转换和量化好之后的模型会存储在当前命令所在目录的dist子目录下(会自动创建),你也可以手动克隆huggingface模型到dist/models文件夹下。量化完之后的模型结构如下:

在这里插入图片描述在这里插入图片描述
这里的mlc-chat-config.json指定来模型生成的一些超参数比如top_p,temperature等。

最后在推理之前,我们还需要把最开始准备的tokenizer_model文件拷贝到这个params文件夹中。

执行推理

我们在mlc-llm的上一层文件夹执行下面的命令:

./mlc-llm/build/mlc_chat_cli --model RWKV-4-World-7B-q0f16

RWKV-4-World-7B-q0f16可以换成你量化模型时的名字,加载完并运行system prompt之后你就可以愉快的和RWKV-4-World模型聊天了。

在这里插入图片描述
程序有一些特殊的指令来退出,查看速度等等:在这里插入图片描述

性能测试

硬件 量化方法 速度
A800 q0f16 prefill: 362.7 tok/s, decode: 72.4 tok/s
A800 q4f16_1 prefill: 1104.7 tok/s, decode: 122.6 tok/s

这里给2组性能数据,大家感兴趣的话可以测测其它配置。

逐层debug方法

在适配1.5B模型时出现了推理结果nan的现象,可以用mlc-llm/tests/debug/dump_intermediate.py这个文件来对齐输入和tokenizer的结果之后进行debug,可以精准模拟模型推理并打印每一层的中间值,这样我们就可以方便的看到模型是在哪一层出现了nan。

0x2. 将RWKV-4-World-3B部署在Apple M2上

在mac上部署和cuda上部署并没有太大区别,主要是编译relax和mlc-llm的时候编译选项现在要选Metal而不是cuda了。我建议最好是在一个anconda环境里面处理编译的问题,不要用系统自带的python环境。

在编译relax的时候需要同时打开使用Metal和LLVM选项,如果系统没有LLVM可以先用Homebrew装一下。

在mlc-llm中生成config.cmake时使用下面的选项:

在这里插入图片描述编译完并pip install .之后使用下面的命令量化模型:

python3 -m mlc_llm.build --hf-path StarRing2022/RWKV-4-World-3B --target metal --quantization q4f16_1

量化过程中日志如下:

(base) bbuf@MacBook-Pro RWKV % python3 -m mlc_llm.build --hf-path StarRing2022/RWKV-4-World-3B --target metal --quantization q4f16_1
Weights exist at dist/models/RWKV-4-World-3B, skipping download.
Using path "dist/models/RWKV-4-World-3B" for model "RWKV-4-World-3B"
[09:53:08] /Users/bbuf/工作目录/RWKV/relax/src/runtime/metal/metal_device_api.mm:167: Intializing Metal device 0, name=Apple M2
Host CPU dection:
  Target triple: arm64-apple-darwin22.3.0
  Process triple: arm64-apple-darwin22.3.0
  Host CPU: apple-m1
Target configured: metal -keys=metal,gpu -max_function_args=31 -max_num_threads=256 -max_shared_memory_per_block=32768 -max_threads_per_block=1024 -thread_warp_size=32
Host CPU dection:
  Target triple: arm64-apple-darwin22.3.0
  Process triple: arm64-apple-darwin22.3.0
  Host CPU: apple-m1
Automatically using target for weight quantization: metal -keys=metal,gpu -max_function_args=31 -max_num_threads=256 -max_shared_memory_per_block=32768 -max_threads_per_block=1024 -thread_warp_size=32
Start computing and quantizing weights... This may take a while.
Finish computing and quantizing weights.
Total param size: 1.6060066223144531 GB
Start storing to cache dist/RWKV-4-World-3B-q4f16_1/params
[0808/0808] saving param_807
All finished, 51 total shards committed, record saved to dist/RWKV-4-World-3B-q4f16_1/params/ndarray-cache.json
Finish exporting chat config to dist/RWKV-4-World-3B-q4f16_1/params/mlc-chat-config.json
[09:53:40] /Users/bbuf/工作目录/RWKV/relax/include/tvm/topi/transform.h:1076: Warning: Fast mode segfaults when there are out-of-bounds indices. Make sure input indices are in bound
[09:53:41] /Users/bbuf/工作目录/RWKV/relax/include/tvm/topi/transform.h:1076: Warning: Fast mode segfaults when there are out-of-bounds indices. Make sure input indices are in bound
Save a cached module to dist/RWKV-4-World-3B-q4f16_1/mod_cache_before_build.pkl.
Finish exporting to dist/RWKV-4-World-3B-q4f16_1/RWKV-4-World-3B-q4f16_1-metal.so

同样也需要把tokenizer_model文件拷贝到量化后模型文件夹的params目录下,然后执行下面的命令启动聊天程序:

./mlc-llm/build/mlc_chat_cli --model RWKV-4-World-3B-q0f16

在这里插入图片描述
最后也来一个Mac M2的速度测试:

硬件 量化方法 速度
Apple M2 q0f16 204.9 tok/s, decode: 12.1 tok/s
Apple M2 q4f16_1 prefill: 201.6 tok/s, decode: 26.3 tok/s

建议使用q4f16的配置,这样回复会快一些。

0x3. 总结

这篇文章介绍了一下笔者最近给mlc-llm做适配的工作,欢迎大家体验MLC-LLM和RWKV-World模型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MLC-LLM 部署RWKV World系列模型实战(3B模型Mac M2解码可达26tokens/s) 的相关文章

  • 如何使虚线可移动

    我用下面的代码画了一条虚线 get the current CGContextRef for the view CGContextRef currentContext CGContextRef NSGraphicsContext curre
  • 如何向现有 (OS X) 可执行文件添加节?

    有什么方法可以将部分添加到已链接的可执行文件中吗 我正在尝试基于以下代码对 OS X 可执行文件进行代码签名苹果说明 http developer apple com library mac documentation Security C
  • Cocoa Key Value Bindings:Controller Key的各个选项的解释是什么?

    当我使用 Interface Builder 将控件绑定到 NSArrayController 时 绑定检查器中的 Controller Key 字段下有多种选项 我理解什么是 arrangedObjects 我半理解什么是 选择 但我很想
  • 创建证书以通过 bash 在 Mac OS X 上签署 GDB

    我正在尝试通过以下方式在 Mac OS X 上安装 gdblink1 http www patosai com blog post installing gdb on mac os x yosemite and link2 http ntr
  • AppleScript:如何获取文件夹中没有隐藏文件的文件?

    我其实有两个问题 当我尝试获取文件夹中的文件时 如何排除 DS STORE Icon 等隐藏文件 我试过了 没有隐形人 但似乎不起作用 如果已经存在 如何将我的 var the new folder 设置为现有文件夹 感谢您的回答 My c
  • std::istringstream >> 使奇怪的行为加倍

    下面的代码打印0在 mac osx 上使用 clang 其他地方都会打印5 clang https ideone com mVgpzS gcc https ideone com oZ0hy6 include
  • 为什么 NSToolbarItem 自动被禁用?

    我的 Mac 幻灯片应用程序工具栏中的按钮有点问题 我希望在没有活动幻灯片时禁用这些按钮 在有活动幻灯片时启用这些按钮 为了实现这一点 我设置了按钮isEnabled财产给false在开始时 我已经尝试过 Interface Builder
  • MacOS 每秒唤醒次数错误

    构建 Rails 应用程序 ruby 2 4 0p0 Rails 5 1 4 并使用我的 Macbook Air MacOS High Sierra 10 13 2 进行本地测试 我不断遇到此问题 过去 241 秒内有 45001 次唤醒
  • 如何在 mac os 10.6 上安装brew或homebrew

    我已经尝试过多次了 谁能告诉我具体的详细步骤吗 我的Mac操作系统是10 6 8 它抱怨一些丢失的包裹 使用它在 Mac OSX 10 6 8 上安装 ruby e curl fsSL https raw githubusercontent
  • Xcode:无法检查应用程序包

    我正在运行 Xcode 6 和 iOS 8 GM 每当我运行我的应用程序时 我都会从 Xcode 收到此消息 无法检查应用程序包 这样我就可以运行和构建 我会收到消息 我再次运行并构建 一切都按预期运行 这是我的设备 然后它会冲洗并重复 每
  • 使用 MTL/Boost 库 Mac 终端 C++

    准确地说 我正在尝试运行这个优秀的项目 https github com ppwwyyxx panorama https github com ppwwyyxx panorama 我使用的是现代 Mac 问题是我似乎无法让我的计算机正确包含
  • webview渲染完成后如何截图

    我想在 webview 渲染完成时截图 以下是我的代码 void webView WebView sender didFinishLoadForFrame WebFrame frame if frame sender mainFrame r
  • 如何在 Unix 控制台或 Mac 终端中编译和运行 C/C++ 代码?

    如何在 Unix 控制台或 Mac 终端中编译 运行 C 或 C 代码 如果是一个简单的单源程序 make foo 源文件在哪里foo c foo cpp等等 你甚至不需要 makefile Make 有足够的内置规则将源文件构建为同名的可
  • 是否可以在 Mac OS X 上构建 FreeGLUT?

    我正在做一些关于 OpenGL 的教程 http www arcsynthesis org gltut Basics Tutorial 2001 html那个使用FreeGLUT http freeglut sourceforge net
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 如何使 SFSpeechRecognizer 在 macOS 上可用?

    我正在尝试使用 Apple 的语音框架在 macOS 10 15 1 上进行语音识别 在 macOS 10 15 之前 语音识别仅在 iOS 上可用 但根据文档 https developer apple com documentation
  • QFileSystemModel setRootPath

    我正在尝试创建一个 Qt 应用程序来显示文件夹 Mac OS 中的 Users 文件夹 的内容 这是代码 QFileSystemModel dirModel new QFileSystemModel dirModel gt setRootP
  • 在 Cocoa OS X AVPlayer 中播放 HLS (m3u8) - Swift

    基本上我正在尝试在 Cocoa Swift 中使用 AVPlayer 播放 m3u8 HLS Live Stream 我对这门语言比较陌生 所以基本上掌握了一些示例代码 http qiita com ono matope items 23d
  • 在 OS X 上创建和使用静态库

    好的 我正在尝试创建一个 Cocoa 库 静态 并使用 但我不断收到错误 我创建了一个超基本的静态库 TSXLib 其中仅包含一个额外的类 import
  • 在 MAC OS X 10.9 上安装 NLTK 确实很困难

    我是 Python Mac OS 新手 我正在寻找 NLTK 教科书 但我在安装它时遇到了一些问题 我一直在寻找解决方案 但不幸的是 所有解决方案似乎都不适合我 或者我误解了如何使用它们 我遇到的基本问题是 尽管按照说明进行操作 NLTK

随机推荐

  • STM32 定时器中断

    通用定时器工作过程 时钟选择 计数器时钟可以由下列时钟源提供 内部时钟 CK INT 外部时钟模式1 外部输入脚 TIx 外部时钟模式2 外部触发输入 ETR 内部触发输入 ITRx 使用一个定时器作为另一个定时器的预分频器 如可以配置一个
  • 环形队列原理,全网最通俗易懂

    队列是什么 队列是一种很常见的数据结构 满足先进先出的方式 如果我们设定队列的最大长度 那就意味着进队列和出队列的元素的数量实则满足一种动态平衡 如果我们把首次添加入队列的元素作为一个一维坐标的原点 那么随着队列中元素的添加 坐标原点到队尾
  • 六一儿童节 全网最全的微服务+Outh2套餐,你确定不来试一试?(入门到精通,附源码)满足你的味蕾需要(二)

    咱们废话不多说 直接开干 目录 一 项目目录 二 Token 三 授权服务器oauth 1 pom 2 application 3 OauthApp启动类 4 DiyUserDetails 5 MyUserDetailService 6 K
  • 爬虫项目二十:用Python对58租房信息进行爬取

    文章目录 前言 一 分析url 二 制造url 三 详情url 四 解析页面 总结 前言 用Python爬下58同城租房详情信息 仅供学习使用 已发现弊端 封IP严重 提示 以下是本篇文章正文内容 下面案例可供参考 一 分析url 第一页
  • 数学建模学习笔记——插值与拟合

    数学建模学习笔记 插值与拟合 一 基础知识储备 1 插值 1 1 拉格朗日插值 1 2 牛顿插值 1 3 分段线性插值 1 4 Hermite插值 1 5 三次样条插值 1 6 B样条函数插值 1 7 二维插值 2 曲线拟合的线性最小二乘法
  • 如何设置python路径并在powershell链接,在PowerShell中为Python设置路径?

    I have two Python versions on my machine Windows Vista 2 6 located in C Program files and 2 7 located in C 1 I open Powe
  • AlibabaCloud核心组件服务治理Nacos(一)

    目录 一 什么是注册中心 服务治理 二 为什么要用注册中心 三 主流的注册中心 四 Linux安装nacos 五 nacos的使用 添加nacos依赖 六 服务之间的调用 一 什么是注册中心 服务治理 服务注册 服务提供者provider
  • ElasticSearch实战之千万级TPS写入

    1 如何发现写入瓶颈 2 哪几个因素会造成长尾问题 3 如何消除分布式的长尾问题 1 背景前段时间 为了降低用户使用ElasticSearch的存储成本 我们做了数据的冷热分离 为了保持集群磁盘利用率不变 我们减少了热节点数量 Elasti
  • softmax cross entropy loss 与 sigmoid cross entropy loss的区别

    要了解两者的区别 当然要先知道什么是softmax sigmoid 和 cross entropy 交叉熵 了 1 softmax 图片来源 李宏毅机器学习课程 sotfmax其实很简单 就是输入通过一个函数映射到0 1之间的输出 上图中蓝
  • 工程管理文件Makefile及gcc编译过程

    一 工程管理文件Makefile 1 什么是makefile 用来管理一个工程中的所有关联文件的文件 头文件 源文件 库文件 2 makefile文件在工程中一定要有吗 不一定 一般原则 若编译命令比较复杂时 会写makefile文件 若源
  • 这个屏幕录制太好用了!

    哈喽 大家好 今天给各位小伙伴测试了一屏幕录制的小工具 ApowerREC 它是一款专业同步录制屏幕画面及声音的录屏软件 界面简洁 操作简单 支持实时编辑屏幕录像 创建计划任务 录制摄像头高清视频等功能 废话不多说 我们一起来学习下吧 一
  • flink源码解析

    一 启动流程解析 flink的启动从命令行提交开始 yooh hadoop101 bin pwd home yooh app flink 1 11 1 bin yooh hadoop101 bin cat flink 上边都是获取环境配置相
  • 告别救火式IT运维服务:《阳光雨露IT运维项目管理白皮书》正式发布!

    因为一个系统故障 在短短一天内丢失了20G的核心业务数据 导致服务器停用 客户不满 这样的事故不是个例 随着信息技术的高速发展 企业对IT运维及管理的依赖性日益增加 如何做好IT运维管理工作已成为各企事业单位长期思考的问题 然而 传统的救火
  • Pointpillars for object detection

    博客参考 pointpillars代码阅读 prep pointcloud篇 Little sky jty的博客 CSDN博客Brief这一篇内容主要是对函数prep pointcloud进行debug和记录 这里也是dataloader的
  • Math.random()随机数的三种用法

    1 得到一个两个数之间的随机数 1 得到一个两数之间的随机数 function getRandom min max return Math random max min min 返回的是一个非整数小于两个实参之间的浮点型的随机值 2 得到一
  • 蓝桥杯试题 基础练习 十六进制转八进制

    题目来源 http lx lanqiao cn problem page gpid T51 1 问题描述 给定n个十六进制正整数 输出它们对应的八进制数 输入格式 输入的第一行为一个正整数n 1 lt n lt 10 接下来n行 每行一个由
  • ng-zorro-antd 入门

    2019独角兽企业重金招聘Python工程师标准 gt gt gt ng new tk zorro web skip install style scss cd tk zorro web npm i npm install save ng
  • angularjs使用http服务请求网络数据展示

    div div
  • 实时渲染大赛太卷了,来看提前交卷的优秀参赛作品

    小伙伴们大家好 首届实时渲染3D动画创作大赛 已经如火如荼进行了50天报名参赛人数已达120 大赛奖品总价值已达40万 报名截止至3月10日 还有42天 跃跃欲试的小伙伴们赶紧冲啊 Blender大佬用作品道出CG人心声 首届实时渲染3D动
  • MLC-LLM 部署RWKV World系列模型实战(3B模型Mac M2解码可达26tokens/s)

    0x0 前言 我的 ChatRWKV 学习笔记和使用指南 这篇文章是学习RWKV的第一步 然后学习了一下之后决定自己应该做一些什么 所以就在RWKV社区看到了这个将RWKV World系列模型通过MLC LLM部署在各种硬件平台的需求 然后