瑞芯微(EASY EAI)RV1126B AI模型部署

1. AI模型部署

DeepSeek-R1,是幻方量化旗下AI公司深度求索(DeepSeek)研发的推理模型 。DeepSeek-R1采用强化学习进行后训练,旨在提升推理能力,尤其擅长数学、代码和自然语言推理等复杂任务。作为国产AI大数据模型的代表,凭借其卓越的推理能力和高效的文本生成技术,在全球人工智能领域引发广泛关注。

本文主要说明DeepSeek-R1如何离线运行在EASY-EAI-Nano-TB(RV1126B)硬件上, RV1126B具有优异的端侧AI能效比与极高的性价比,是AI落地的不二之选。

v2-5fe00f05814180dbe7e35dc2be8f6d89_720w.webp

注意,要求使用有2GB以上内存的EAI1126B-Core-T方可以正常运行。

图1 EAI1126B-Core-T正面

2. 快速上手

2.1 准备工作

2.1.1 硬件准备

需准备EASY EAI Nano-TB开发板,Type-C数据线、网线。可以基于MobaXterm的ssh远程桌面登录调试。首先使用网线把EASY EAI Nano-TB的千兆以太网接口连着路由LAN口的交换机或者路由器的LAN口连接,如下图所示。

以及串口连接。

2.1.2 开发环境准备

如果您初次阅读此文档,请阅读《入门指南/开发环境准备/Easy-Eai编译环境准备与更新》,并按照其相关的操作,进行编译环境的部署

在PC端Ubuntu系统中执行run脚本,进入EASY-EAI编译环境,具体如下所示。

cd ~/develop_environment ./run.sh

v2-e1127efd76bcca3331922be6d17e546f_720w.webp

2.2 源码下载以及例程编译

本节提供转换成功的大模型文deepseek_r1_rv1126b_w4a16.rkllm及对应的C/C++程序部署代码。

v2-ec48eecad3123b2ab2493ccfe7e2445c_720w.webp

下载链接:https://pan.baidu.com/s/1ELdwCoQYHYtupecOkOhvTw?pwd=1234(提取码: 1234)。

下载程序包移至ubuntu环境后,执行以下指令解压:

tar -xvf deepseek-demo.tar.bz2

下载解压后如下图所示:

v2-b0e1de8a631816c144004ccb75465eb2_720w.webp

在EASY-EAI 编译环境下,进入到对应的例程目录执行编译操作,具体命令如下所示:

cd /opt/nfsroot/rknn-toolkit2/deepseek-demo ./build.sh

v2-53e721073460f4a5f078a29d63e30f9c_720w.webp

同时,把可执行程序目录deepseek-demo_release/复制到开发板/userdata目录上:

cp deepseek-demo_release/ /mnt/userdata/ -rf

而且把librkllmrt.so也同步到板子/usr/lib环境里面:

cp lib/librkllmrt.so /mnt/usr/lib

v2-8dab3e4a9540e315b34b50bd47a3937d_720w.webp

2.3 开发板运行大模型

通过串口调试或ssh调试,进入板卡后台,定位到例程部署的位置,如下所示:

cd /userdata/deepseek-demo_release/

v2-4fd99bc7a9b361b31adb339821b964f7_720w.webp

运行例程命令如下所示:

ulimit -HSn 102400 sudo ./deepseek-demo deepseek_r1_rv1126b_w4a16.rkllm 256 512

v2-5bc9e192f1c917ff9b3604db0dc2067d_720w.webp

至此可以进行对话测试了,试着输入“0”测试预设的问题。回答如下所示:

v2-e410219c1f9014f445722c0102f284a6_720w.webp

3. RKLLM算法例程

例程目录为deepseek-demo/src/llm_demo.cpp,操作流程如下。

v2-f572a83002e3561d8d3009adf646877c_720w.webp

具体代码如下所示:

// Copyright (c) 2025 by Rockchip Electronics Co., Ltd. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include "rkllm.h" #include #include #include #include using namespace std; LLMHandle llmHandle = nullptr; void exit_handler(int signal) { if (llmHandle != nullptr) { { cout << "程序即将退出" << endl; LLMHandle _tmp = llmHandle; llmHandle = nullptr; rkllm_destroy(_tmp); } } exit(signal); } int callback(RKLLMResult *result, void *userdata, LLMCallState state) { if (state == RKLLM_RUN_FINISH) { printf("\n"); } else if (state == RKLLM_RUN_ERROR) { printf("\\run error\n"); } else if (state == RKLLM_RUN_NORMAL) { /* ================================================================================================================ 若使用GET_LAST_HIDDEN_LAYER功能,callback接口会回传内存指针:last_hidden_layer,token数量:num_tokens与隐藏层大小:embd_size 通过这三个参数可以取得last_hidden_layer中的数据 注:需要在当前callback中获取,若未及时获取,下一次callback会将该指针释放 ===============================================================================================================*/ if (result->last_hidden_layer.embd_size != 0 && result->last_hidden_layer.num_tokens != 0) { int data_size = result->last_hidden_layer.embd_size * result->last_hidden_layer.num_tokens * sizeof(float); printf("\ndata_size:%d",data_size); std::ofstream outFile("last_hidden_layer.bin", std::ios::binary); if (outFile.is_open()) { outFile.write(reinterpret_cast(result->last_hidden_layer.hidden_states), data_size); outFile.close(); std::cout << "Data saved to output.bin successfully!" << std::endl; } else { std::cerr << "Failed to open the file for writing!" << std::endl; } } printf("%s", result->text); } return 0; } int main(int argc, char **argv) { if (argc < 4) { std::cerr << "Usage: " << argv[0] << " model_path max_new_tokens max_context_len\n"; return 1; } signal(SIGINT, exit_handler); printf("rkllm init start\n"); //设置参数及初始化 RKLLMParam param = rkllm_createDefaultParam(); param.model_path = argv[1]; //设置采样参数 param.top_k = 1; param.top_p = 0.95; param.temperature = 0.8; param.repeat_penalty = 1.1; param.frequency_penalty = 0.0; param.presence_penalty = 0.0; param.max_new_tokens = std::atoi(argv[2]); param.max_context_len = std::atoi(argv[3]); param.skip_special_token = true; param.extend_param.base_domain_id = 0; param.extend_param.embed_flash = 1; int ret = rkllm_init(&llmHandle, ¶m, callback); if (ret == 0){ printf("rkllm init success\n"); } else { printf("rkllm init failed\n"); exit_handler(-1); } vector pre_input; pre_input.push_back("现有一笼子,里面有鸡和兔子若干只,数一数,共有头14个,腿38条,求鸡和兔子各有多少只?"); pre_input.push_back("有28位小朋友排成一行,从左边开始数第10位是学豆,从右边开始数他是第几位?"); cout << "\n**********************可输入以下问题对应序号获取回答/或自定义输入********************\n" << endl; for (int i = 0; i < (int)pre_input.size(); i++) { cout << "[" << i << "] " <", "<|Assistant|>"); while (true) { std::string input_str; printf("\n"); printf("user: "); std::getline(std::cin, input_str); if (input_str == "exit") { break; } if (input_str == "clear") { ret = rkllm_clear_kv_cache(llmHandle, 1, nullptr, nullptr); if (ret != 0) { printf("clear kv cache failed!\n"); } continue; } for (int i = 0; i < (int)pre_input.size(); i++) { if (input_str == to_string(i)) { input_str = pre_input[i]; cout << input_str << endl; } } rkllm_input.input_type = RKLLM_INPUT_PROMPT; rkllm_input.role = "user"; rkllm_input.prompt_input = (char *)input_str.c_str(); printf("robot: "); // 若要使用普通推理功能,则配置rkllm_infer_mode为RKLLM_INFER_GENERATE或不配置参数 rkllm_run(llmHandle, &rkllm_input, &rkllm_infer_params, NULL); } rkllm_destroy(llmHandle); return 0; }

为您推荐

当前非电脑浏览器正常宽度,请使用移动设备访问本站!