本文主要介绍如何在Jetson设备上使用纯C/C++实现LLaMA模型的推理,而无需安装Python等其他外部依赖。通过本文你将了解如何借助 llama.cpp 项目在NVIDIA的Jetson系列设备上部署大模型,以及如何使用Qwen-1.8B模型进行通用问答任务。

1. 引言

随着人工智能的快速发展,大规模语言模型已经成为了AI领域中的一个重要分支。其中,阿里云研发的通义千问-1.8B(Qwen-1.8B)无疑是一个典型的代表。这是一个拥有18亿参数的大规模语言模型,基于Transformer架构并在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍、代码等,使得模型在多个中英文下游评测任务上(涵盖常识推理、代码、数学、翻译等)有着卓越的表现。

尤为重要的是,其低成本部署的特点:提供int8和int4量化版本,推理最低仅需不到2GB显存,生成2048 tokens仅需3GB显存占用。这对于边缘计算设备如Jetson系列来说,显得尤为关键。Jetson设备通常具有有限的内存和计算能力,因此需要在资源利用上进行优化。Qwen-1.8B模型提供的int8和int4量化版本,不仅可以降低模型的存储和计算要求,同时也可以保持较高的模型性能。这使得Qwen-1.8B模型能够在Jetson这样的边缘计算设备上进行高效的运行。

本文将介绍如何借助 llama.cpp 项目在NVIDIA的Jetson系列设备上部署大模型,以及如何使用Qwen-1.8B模型进行通用问答任务。

2. 先决条件

本文使用 Jetson AGX Xavier 部署,其拥有 32 TOPS(int8)的算力,运行已非常流畅,其他设备需自行测试,但是理论上来说问题不大,就是推理快慢的差别。关于环境的问题,这里不再详细介绍,需要具备以下几个方面:

  1. 一台PC,已经安装好基础的AI环境和 pip 的 transformers 库以及其依赖
  2. Jetson 设备已经安装操作系统并通过 SDK Manager 安装好 Cuda 等 NVIDIA 的基础 AI 环境

环境

3. 模型准备

模型准备的操作建议在 PC 进行,因为模型转换需要较大的内存和计算资源,而 Jetson 设备的资源有限,因此建议在 PC 上进行模型转换,然后将转换后的模型拷贝到 Jetson 设备上进行推理。这样你无需在 Jeston 设备上处理复杂的 Pyhton 环境,只需要在 Jetson 设备上安装好 llama.cpp 项目即可。

3.1 下载模型

这里我们使用的是 Qwen-1_8B-Chat ,当然你也可以尝试其他的模型。模型可以通过下面两种途径获取:

  • 魔搭 https://huggingface.co/Qwen/Qwen-1_8B-Chat
  • Hugging Face https://huggingface.co/Qwen/Qwen-1_8B-Chat

国内建议使用魔搭社区下载,通过 git 指令即可:

git clone https://www.modelscope.cn/qwen/Qwen-1_8B-Chat.git

3.2 模型转换

模型下载完成后,我们需要将其转换为 llama.cpp 项目支持的格式。这里我们使用的是 qwen.cpp 项目中的 convert.py 脚本,这个脚本可以将 Hugging Face 的模型转换为 llama.cpp 项目支持的格式。这个脚本的使用方法如下:

python convert.py -i <model_name_or_path> -o <output_bin>

这里的 model_name_or_path 可以是本地的模型路径,也可以是 Hugging Face 的模型名称,比如 Qwen/Qwen-1_8B-Chat。output_bin 是转换后的模型输出文件,这里我们将其命名为 qwen-1.8b-chat.bin。

可以使用 -t 参数指定量化,默认值是 q4_0

python qwen_cpp/convert.py -i Qwen/Qwen-1_8B-Chat -o qwen1_8b-ggml.bin

转换

等待转换结束,我们就可以得到一个 qwen1_8b-ggml.bin 文件,这个文件就是我们需要的模型文件。

4. Jetson 设备部署

在 Jetson 设备上部署模型,我们需要借助 llama.cpp 项目,这是一个纯 C++ 实现的大模型推理项目,可以在 Jetson 设备上高效地运行大模型,这里我们使用的是 qwen.cpp

4.1 编译环境准备

在编译前我们需要准备 cmake 工具,直接 apt 安装的版本太低,无法编译 llama.cpp 项目。

如果已经存在 cmake ,也可以先卸载:

sudo apt-get remove cmake

然后,我们直接编译安装 cmake 3.28.0 版本:

wget https://cmake.org/files/v3.28/cmake-3.28.0.tar.gz
tar -zxvf cmake-3.28.0.tar.gz 
cd cmake-3.28.0/

编译前我们需要安装一些依赖:

sudo apt-get install libssl-dev

如果不安装这个依赖,编译时会报错 Could NoT find Openssl

Openssl

然后开始编译:

sudo ./configure 
sudo make -j8 
sudo make install

编译完成后,我们可以查看 cmake 的版本:

cmake --version

如果没有显示版本号,可以尝试重启一下终端。

4.2 安装 llama.cpp 项目

克隆 qwen.cpp 项目:

git clone --recursive https://github.com/QwenLM/qwen.cpp && cd qwen.cpp

然后开始编译:

cmake -B build
cmake --build build -j --config Release

编译完成后,我们可以看到 build 目录下的 bin 目录生成了一个 main 可执行文件:

main

5. 模型推理

5.1 模型准备

将转换后的模型拷贝到 Jetson 设备上,这里我们将其拷贝到 qwen.cpp 项目的根目录下。

另外找到下载的模型文件夹下的 qwen.tiktoken 文件,将其拷贝到 qwen.cpp 项目的根目录下。

5.2 推理

推理的命令如下:

./build/bin/main -m "qwen1_8-ggml.bin" --tiktoken "qwen.tiktoken" -p 你好
# 你好!有什么我可以帮助你的吗?

整体的推理速度还是非常快的,CPU 占用大概 50% 左右,内存占用大概 3.5G 左右。

推理

当然你也可以使用 -i 进入交互模式:

./build/bin/main -m "qwen1_8-ggml.bin" --tiktoken "qwen.tiktoken" -i

交互

当然,其还有很多使用方式,你可以自行前往 llama.cpp 开源项目了解更多使用信息。

5.3 推理速度

这边编译并没有启用 GPU,但是 CPU 的推理速度也是非常可观的,达到了 135ms/token 的速度,这个速度已经可以满足大部分的端侧应用场景了。

使用 -v 参数即可查看推理速度信息,这里我们以写一篇 800 字的作文为例:

qwen.cpp/build/bin/main -m models/qwen1_8-ggml.bin --tiktoken models/qwen.tiktoken -v -p 写一篇800字的作文:冬天的北京

推理结果:

system info: | AVX = 0 | AVX2 = 0 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 0 | VSX = 0 |
inference config: | max_length = 2048 | max_context_length = 512 | top_k = 0 | top_p = 0.5 | temperature = 0.95 | num_threads = 0 |
loaded qwen model from models/qwen1_8-ggml.bin within: 150.005 ms

标题:冬天的北京
···略···

prompt time: 3255.28 ms / 31 tokens (105.009 ms/token)
output time: 69472.2 ms / 511 tokens (135.953 ms/token)
total time: 72727.4 ms

5.4 启用 GPU

如果需要启用 GPU 支持,我们在编译时需要添加 -DGGML_CUBLAS=ON 参数:

cmake -B build -DGGML_CUBLAS=ON
cmake --build build -j --config Release

这时就可以使用 GPU 进行推理了,推理速度也会有所提升,相应的编译过程也会变长。

GPU配置

GPU 的推理速度我们用同样的方式测试一下:

ggml_init_cublas: found 1 CUDA devices:
  Device 0: Xavier, compute capability 7.2
system info: | AVX = 0 | AVX2 = 0 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 |
inference config: | max_length = 2048 | max_context_length = 512 | top_k = 0 | top_p = 0.5 | temperature = 0.95 | num_threads = 0 |
loaded qwen model from models/qwen/chat1_8B/qwen1_8-ggml.bin within: 23820.7 ms

标题:冬天的北京
···略···

prompt time: 706.89 ms / 31 tokens (22.802 ms/token)
output time: 7275.73 ms / 395 tokens (18.419 ms/token)
total time: 7982.62 ms

我们可以看到,这里总时间不如 CPU,但是单个 token 的推理速度已经达到了 18ms,这个速度是非常快的了,是 CPU 的 8 倍左右。主要的耗时是在模型的加载上,用了23s,CPU则是 150ms。当然加载只有一次,后续的推理速度还是非常快的。

5.5 最低配置测试

这里我们进行了 Jetson 设备的最低配置测试,即 Jetson Nano Developer Kit ,拥有 4GB 内存,GPU 128 核心,CPU 四核心,性能非常有限。这个是最早期的设备,仅支持 SD 卡启动,并且在支持上也有一些限制,官方已经很久没有更新了 SD 卡镜像了,最新的 JetPack 只到 4.6.1,而且只支持到 CUDA 10.2。而编译用到的 ggml 要求 Cuda 最低 11.0,因此这里只测试了 CPU 的推理速度。

Jetson Nano

如上图所示,我们可以看到,Jetson Nano 的 CPU 推理速度为 257.319 ms/token,这个速度也是非常惊人的。

prompt time: 8166.8 ms / 46 tokens (177.539 ms/token)
output time: 107817 ms / 419 tokens (257.319 ms/token)
total time: 115984 ms

6. 总结

本文主要介绍了如何在 Jetson 设备上使用纯C/C++实现LLaMA模型的推理,而无需安装Python等其他外部依赖。通过本文你将了解如何借助 llama.cpp 项目在NVIDIA的Jetson系列设备上部署大模型,以及如何使用Qwen-1.8B模型进行通用问答任务。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐