RKLLM 模型转换 API 介绍
修改履历
| NO | 版本 | 修改内容 | 修改日期 |
|---|---|---|---|
| 1 | Ver1.0 | 新建 | 2026/06/21 |
本文档信息可能会因文档改进而在未事先通知的情况下变更。最新版请参照本公司网站。
未经株式会社日昇科技书面许可,严禁以任何形式复制本文档。
1. RKLLM 初始化
在这一部分,用户需要先初始化 RKLLM 对象,这是整个工作流的第一步。在示例代码中使用 RKLLM()构造函数来初始化 RKLLM 对象。
2. 模型加载
在 RKLLM 初始化完成后,用户需要调用 rkllm.load_huggingface()函数来传入模型的具体路径,RKLLM-Toolkit 即可根据对应路径顺利 加载 Hugging Face 或 GGUF 格式的大语言模型,从而顺利完成后续的转换、量化操作,具体的函数定义如下:
表 1 load_huggingface 函数接口说明
函数名 load_huggingface
描述 用于加载开源的 Hugging Face 格式的大语言模型。 model: LLM 模型的文件路径,用于加载模型进行后续的转换、量化; model_lora: lora 权重的文件路径,转换时 model 必须指向相应的 base model 路径; device: 指定模型转换时使用的设备,支持 cuda 和 cpu 两个选项; 参数 dtype: 权重的数据类型,可选值包括 float32,float16 和 bfloat16;float16 和 bfloat16可以减少显存占用,但会损失 量化精度; custom_config: 自定义模型的配置文件,具体详见自定义模型转换章节; load_weight: 是否加载权重,设置为 False 时不会加载真实权重; 返回值 0 表示模型加载正常;-1 表示模型加载失败; 示例代码如下:
ret = rkllm.load_huggingface(model = ’./huggingface_model_dir’, model_lora = ’./huggingface_lora_model_dir’ )
if ret != 0:print('Load model failed!')表 2 load_gguf 函数接口说明
函数名 load_ggu
用于加载开源的 GGUF 格式的大语言模型,所支持的数值类型为 q4_0 和 fp16 两种,gguf 格式的 lora 模型也可以通过 描述 此接口加载转换为 rkllm 模型。 参数 model: GGUF 模型文件路径;
返回值 0 表示模型加载正常;-1 表示模型加载失败;
示例代码如下:
ret = rkllm.load_gguf(model = './model-Q4_0.gguf')if ret != 0:print('Load model failed!')3. 模型构建
用户在通过rkllm.load_huggingface()函数完成原始模型的加载后,下一步就是通过rkllm.build()函数实现对 RKLLM 模型的构建。构建模 型时,用户可以选择是否进行量化,量化有助于减小模型的大小和提高在 Rockchip NPU 上的推理性能。rkllm.build()函数的具体定义如下:
表 3 build 函数接口说明
函 数 build 名
描
用于构建得到 RKLLM 模型,并在转换过程中定义具体的量化操作。
述
do_quantization: 该参数控制是否对模型进行量化操作,建议设置为 True;
optimization_level: 该参数用于设置是否进行量化精度优化,可选择的设置为{0, 1},0 表示不做任何优化,1 表示进行精度优化,精度优化可
能造成模型推理性能下降;
quantized_dtype: 该参数用于设置量化的具体类型,目前支持的量化类型包
括“w4a16”,“w4a16_g32”,“w4a16_g64”,“w4a16_g128”,“w8a8”,“w8a8_g128”,“w8a8_g256”,“w8a8_g512”,“w4a16”表
示对权重进行 4bit 量化而对激活值不进行量化;“w4a16_g64”表示对权重进行 4bit 分组量化(groupsize=64)而对激活值不进行量
化;“w8a8”表示对权重和激活值均进行 8bit 量化;“w8a8_g128”表示对权重和激活值均进行 8bit 分组量化(group size=128);目前
RK3576 和 RV1126B 平台支持“w4a16”,“w4a16_g32”,“w4a16_g64”,“w4a16_g128”和“w8a8”五种量化类型,RK3588 支
持“w8a8”,“w8a8_g128”,“w8a8_g256”,“w8a8_g512”四种量化类型,RK3562 支
持“w8a8”,“w4a16_g32”,“w4a16_g64”,“w4a16_g128”和“w4a8_g32”量化类型;GGUF模型的 q4_0 对应的量化类型
为“w4a16_g32”;注意 group size 应能被线性层的输出维度整除,否则不支持!
quantized_algorithm: 量化精度优化算法, 可选择的设置包括“normal”、“grq”或“gdq”,所有量化类型均可选择 normal,而 gdq 和
参 grq 算法只支持 w4a16 及 w4a16 分组量化,且 gdq 和 grq 对算力要求高,必须使用 GPU 进行加速运算;grq 相比 gdq 算法速度更快且显
数 存占用更低,4 bit 量化可优先尝试 grq 算法;支持利用 lora 模块进一步提高量化精度,在无其他 lora 模型导入的情况下,可以使
用“normal_r[164]”、“grq_r[164]”或“gdq_r[1~64]”算法,例如“normal_r8”、“grq_r8”或“gdq_r8”,最终将会导出量化模
型与 lora 模型,runtime 加载两个模型执行推理。
num_npu_core: 模型推理需要使用的 npu 核心数,“RK3576”可选项为[1,2],“RK3588”可选项为[1,2,3],“RK3562”可选项为
[1],“RV1126B”可选项为[1];
extra_qparams: 使用 gdq/grq 算法会生成.qparams 后缀的量化权重缓存文件,将此参数设置为*.qparams 路径,可以重新进行模型导出;
dataset: 用于量化校正数据集,格式为 json,内容示例如下,input 为问题,需要加上提示词,target 为回答,多条数据以{}字典形式保存在列表中:[{“input”:“今天天气怎么样?”,“target”:“今天天气晴。”},…] hybrid_rate: 分组和不分组混合量化比率(∈[0,1)),当量化类型为 w4a16/w8a8 时,会按比率分别混合 w4a16 分组/w8a8 分组类型来提高精 度,当量化类型为 w4a16 分组/w8a8 分组类型时,会按比率分别混合 w4a16/w8a8 类型来提高推理性能,当hybrid_rate 值为 0 时,不进行 混合量化; target_platform: 模型运行的硬件平台, 可选择的设置包括“RK3576”、“RK3588”、“RK3562”、“RV1126B”; max_context: 上下文长度的上限值,最大支持到 16384 且必须按 32 对齐; 返 回 0 表示模型转换、量化正常;-1 表示模型转换失败; 值 示例代码如下:
ret = rkllm.build(do_quantization=True, optimization_level=1, quantized_dtype=‘w8a8’, quantized_algorithm=“normal”, num_npu_core=3, extra_qparams=None,
dataset="quant_data.json",hybrid_rate=0, target_platform=‘rk3588’)
if ret != 0:print('Build model failed!')4. 模型导出
用户在通过 rkllm.build()函数构建了 RKLLM 模型后,可以通过 rkllm.export_rkllm()函数将RKNN 模型保存为一个.rkllm 文件,以便后续 模型的部署。rkllm.export_rkllm()函数的具体参数定义如下:
表 4 export_rkllm 函数接口说明
函数名 export_rkllm
描述 用于保存转换、量化后的 RKLLM 模型,用于后续的推理调用。
参数 export_path: 导出 RKLLM 模型文件的保存路径,lora 模型会自动保存为带_lora 后缀的 rkllm 模型;
返回值 0 表示模型成功导出保存;-1 表示模型导出失败; 示例代码如下:
ret = rkllm.export_rkllm(export_path = './model.rkllm')if ret != 0:print('Export model failed!')5. GPTQ 模型转换
用户除了使用上述工具中提供的量化算法进行模型转换,也可以先使用 AutoGPTQ 开源量化工具将浮点模型量化为 4bit/8bit 权重(需保 存为 Hugging Face 格式),再转换为RKLLM 模型。使用 AutoGPTQ 量化浮点模型时,需确保以下参数设置:
bits=4 sym=true group_size=32/64/128 desc_act=false
bits=8 sym=true group_size=128/256/512 desc_act=false
Hugging Face 格式的 GPTQ 模型转换为 rkllm 的示例代码如下:
modelpath = '/path/to/Model-Instruct-GPTQ-Int4'llm = RKLLM()ret = llm.load_huggingface(model=modelpath, model_lora = None,device=‘cuda’)
if ret != 0:print('Load model failed!')exit(ret)# Build modeldataset = Noneqparams = Nonetarget_platform = “RK3576” optimization_level = 1 quantized_dtype = “w4a16_g32” #w4a16_g64 or w4a16_g128 quantized_algorithm = “normal” num_npu_core = 2
ret = llm.build(do_quantization=True,optimization_level=optimization_level, quantized_dtype=quantized_dtype, quantized_algorithm=quantized_algorithm, target_platform=target_platform, num_npu_core=num_npu_core, extra_qparams=qparams, dataset=dataset)
if ret != 0:print('Build model failed!')exit(ret)# Export rkllm modelret =llm.export_rkllm(f”./{os.path.basename(modelpath)}{quantized_dtype}{ target_platform}.rkllm”)
if ret != 0:print('Export model failed!')exit(ret)6. 自定义模型转换
用户如果修改了模型结构或者名称,且修改后的整体架构如下,则可以使用自定义功能转换模型。
TOKEN_EMBD ↓ embd_scale(optional) ↓ ┌─ x │ ↓ │ ATTN_NORM │ ↓ │ attn │ ↓ │ ATTN_POST_NORM(optional) │ ↓ │ hidden_state_scale(optional) │ ↓ │ cross attn(optional) │ ↓ ┌─ └► + │ │ ↓ │ FFN_NORM │ ↓ │ MLP
│ ↓ │ FFN_POST_NORM(optional) │ ↓ │ hidden_state_scale(optional) │ ↓ └───► + …↓ OUTPUT_NORM ↓ lm_head_scale(optional) ↓ OUTPUT
以 Qwen 模型为例,将 Qwen 模型文件 modeling_qwen.py 中相应的变量名称填入自定义配置文件中,如下所示:
{ “BLOCKNAME”: “QWenBlock”, “TOKEN_EMBD”: “wte”, “ATTN_NORM”: “ln_1”, “ATTN_Q_NORM”: "", “ATTN_K_NORM”: "", “CROSS_ATTN_NORM”: "", “CROSS_ATTN_Q”: "", “ATTN_Q”: "", “ATTN_K”: "", “ATTN_V”: "", “ATTN_QKV”: “attn.c_attn”, “ATTN_KV”: "", “KV_CONTINUOUS”: “true”, “ATTN_OUT”: “attn.c_proj”, “CROSS_ATTN_OUT”: "", “ATTN_POST_NORM”: "", “FFN_NORM”: “ln_2”, “FFN_UP”: “mlp.w1”, “FFN_GATE”: “mlp.w2”, “ACT_TYPE”: “silu”, “FFN_DOWN”: “mlp.c_proj”, “FFN_POST_NORM”: "", “OUTPUT_NORM”: “ln_f”, “OUTPUT”: “lm_head” }
其中,ACT_TYPE 可选项为[“silu”, “gelu”, “relu”, “fatrelu”, “squarerelu”, “swiglu”]共六种,ATTN_NORM 和 FFN_NORM 只支持 RMSNorm; 如果使用了 ATTN_QKV 或者 ATTN_KV,则必须确认权重是否可以拆分为连续的 K|V,如果连续则 KV_CONTINUOUS 设置为 true,例如 Qwen 模型的 c_attn 权重是连续存储,它可以按Q,K,V 大小进行顺序切分,而 InternLM2 模型的 wqkv 权重是不连续存储,它的 Q,K,V 是按 head_dim 交错排布。 Qwen 1.8B 模型的 modeling_qwen.py 文件定义如下:
class QWenLMHeadModel(QWenPreTrainedModel): def init(self, config): super().init(config) self.transformer = QWenModel(config) self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
class QWenModel(QWenPreTrainedModel): _keys_to_ignore_on_load_missing = [“attn.masked_bias”]
def init(self, config): super().init(config) self.wte = nn.Embedding(self.vocab_size, self.embed_dim) self.ln_f = RMSNorm( self.embed_dim, eps=config.layer_norm_epsilon, ) class QWenBlock(nn.Module): def init(self, config): super().init() hidden_size = config.hidden_size self.bf16 = config.bf16
self.ln_1 = RMSNorm( hidden_size, eps=config.layer_norm_epsilon, ) self.attn = QWenAttention(config)
self.ln_2 = RMSNorm( hidden_size, eps=config.layer_norm_epsilon, )
self.mlp = QWenMLP(config) class QWenAttention(nn.Module): def init(self, config): super().init() self.c_attn = nn.Linear(config.hidden_size, 3 * self.projection_size) self.c_proj = nn.Linear( config.hidden_size, self.projection_size, bias=not config.no_bias ) class QWenMLP(nn.Module): def init(self, config): super().init() self.w1 = nn.Linear( config.hidden_size, config.intermediate_size // 2, bias=not config.no_bias) self.w2 = nn.Linear( config.hidden_size, config.intermediate_size // 2, bias=not config.no_bias) ff_dim_in = config.intermediate_size // 2 self.c_proj = nn.Linear(ff_dim_in, config.hidden_size, bias=not config.no_bias)
自定义模型的转换,包括支持 cross attention 的模型,我们提供了一个 huggingface 模型结构供参考,自定义的配置文件如下:
{ “BLOCKNAME”: “CustomDecoderLayer”, “TOKEN_EMBD”: “embed_tokens”, “ATTN_NORM”: “input_layernorm”, “ATTN_Q_NORM”: "", “ATTN_K_NORM”: "", “CROSS_ATTN_NORM”: “cross_layernorm”, “CROSS_ATTN_Q”: “cross_attn.cross_q_proj”, “ATTN_Q”: "", “ATTN_K”: "", “ATTN_V”: "", “ATTN_QKV”: “self_attn.qkv_proj”, “ATTN_KV”: "", “KV_CONTINUOUS”: “true”, “ATTN_OUT”: “self_attn.o_proj”, “CROSS_ATTN_OUT”: “cross_attn.cross_o_proj”, “ATTN_POST_NORM”: "", “FFN_NORM”: “post_attention_layernorm”, “FFN_UP”: “mlp.up_proj”, “FFN_GATE”: “mlp.gate_proj”, “ACT_TYPE”: “silu”, “FFN_DOWN”: “mlp.down_proj”, “FFN_POST_NORM”: "", “OUTPUT_NORM”: “norm”, “OUTPUT”: “lm_head”
7. 旧版本模型更新
由于 1.0.2 版本与 1.1 及之后版本差异较大,因此提供了 rkllm.update_rkllm()函数将 1.0.2 版本模型更新为最新版本,更新模型时无需执 行上述模型加载和构建步骤,直接调用此接口进行更新,更新后模型量化类型等参数均未改变。rkllm.update_rkllm()函数的具体参数定义如 下:
表 5 update_rkllm 函数接口说明
函数名 update_rkllm
描述 将 1.0.2 版本模型更新为最新版本
参数 model: 1.0.2 版本的 rkllm 模型路径
返回值 0 表示模型更新成功;-1 表示模型更新失败;
示例代码如下:
ret = llm.update_rkllm(model = "./model_1.0.2version.rkllm")if ret != 0:print('Load model failed!')exit(ret)8. 仿真精度评估
用户在通过 rkllm.build()函数构建了 RKLLM 模型后,可以通过 rkllm.get_logits()函数在 PC端进行仿真精度评估,rkllm.get_logits()函数 的具体参数定义如下:
表 6 get_logits 函数接口说明
函数名 get_logits
描述 用于 PC 端仿真精度评估。
inputs: 仿真输入格式与 huggingface 模型推理一样,示例如下:
参数
{“input_ids”:"", “top_k”:1, …}
返回值 返回模型推理出的 logits 值;
使用此函数进行 wikitext 数据集 ppl 测试示例代码如下:
def eval_wikitext(llm): seqlen = 512 tokenizer = AutoTokenizer.from_pretrained(
modelpath,trust_remote_code=True ) #Dataset download link: #https://huggingface.co/datasets/Salesforce/wikitext/tree/main/wikitext-2-raw-v1 testenc = load_dataset(“parquet”, data_files=’./wikitext/wikitext-2-raw-1/test-00000-of-00001.parquet’, split=‘train’) testenc = tokenizer( “\n\n”.join(testenc[‘text’]), return_tensors=“pt”).input_ids nsamples = testenc.numel() // seqlen nlls = [] for i in tqdm(range(nsamples), desc=“eval_wikitext: ”): batch = testenc[:, (i * seqlen): ((i + 1) * seqlen)] inputs = {“input_ids”: batch} lm_logits = llm.get_logits(inputs)
if lm_logits is None:print("get logits failed!")return shift_logits = lm_logits[:, :-1, :] shift_labels = batch[:, 1:].to(lm_logits.device) loss_fct = nn.CrossEntropyLoss().to(lm_logits.device) loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) neg_log_likelihood = loss.float() * seqlen nlls.append(neg_log_likelihood) ppl = torch.exp(torch.stack(nlls).sum() / (nsamples * seqlen))
print(f'wikitext-2-raw-1-test ppl: {round(ppl.item(), 2)}')9. 仿真模型推理
用户在通过 rkllm.build()函数构建了 RKLLM 模型后,可以通过 rkllm.chat_model()函数在 PC端进行仿真推理,rkllm.chat_model()函数 的具体参数定义如下:
表 7 chat_model 函数接口说明
函数名 chat_model
描述 用于 PC 端仿真模型推理。
messages: 文本输入,需要加上相应提示词参数 args: 推理配置参数,比如 topk 等采样策略参数 返回值 返回模型推理结果; 示例代码如下:
args ={ “max_length”:128, “top_k”:1, “temperature”:0.8, “do_sample”:True,
“repetition_penalty”:1.1 } mesg = “Human: 今天天气怎么样?\nAssistant:”
print(llm.chat_model(mesg, args))以上的这些操作涵盖了 RKLLM-Toolkit 模型转换、量化的全部步骤,根据不同的需求和应用场景,用户可以选择不同的配置选项和量化方 式进行自定义设置,方便后续进行部署。