量化基模外挂LoRA微调
============

#### 简介

Transform结构作为基模完成量化后，可支持基模结构挂载LoRA分支进行特定场景训练。即量化基模+浮点LoRA的结构微调，作用于量化损失修复和下游场景任务续训。

微调准备：

1.  浮点模型：Huggingface开源形式加载即可
    
2.  量化策略文件：基于基模量化，需要新增LoRA config配置
    
3.  量化基模权重：基于基模量化保存的trained.pth
    
4.  微调框架：Transform Trainer库架构，或者用户自定义训练架构
    

微调步骤：

1.  修改基模量化策略文件，增加LoRA相关配置
    
2.  使用插件式接口进行模型改造
    
3.  微调模型
    
4.  保存训练后模型参数
    
5.  导出量化参数
    
6.  导出ONNX模型
    

#### 修改基模配置文件

{
    "layer\_strategy": {
        "time\_embedding.linear\_1": {
            "type": "<class 'torch.nn.modules.linear.Linear'>",
            "quant\_strategy": "XXX",  ### 基模策略
            ### 新增外挂lora，追加以下内容
            "lora\_config": {
                "rank": 32, ### LoRA秩大小，影响模型表达能力
                "alpha": 32, ### LoRA缩放因子，通常设置为与rank相同的值
                "quant\_state": false ### 是否启用量化状态，在LoRA训练中建议设为False
            }
        }
}
}

quant\_state为LoRA结构的量化使能标志，训练时建议使用false，即使用浮点LoRA训练。

#### 插件式接口使用

import os
import torch
from dopt.dopt\_lm.do\_opt import (
    generate\_config\_file,
    optimize\_model,
    set\_trainable\_lora
)
### dopt lora ####
dopt\_config = "dopt\_config\_withlora.json"
model = "your model define"
if not os.path.exists(dopt\_config):
    generate\_config\_file(model, dopt\_config)
    exit()
model = optimize\_model(model, dopt\_config)     ### 基于基模策略文件，已经完成添加lora配置
model.load\_state\_dict(torch.load('xxx.pth'))   ### 基模量化权重trained.pth  strict=False
model = set\_trainable\_lora(model, initia\_method='gaussian')
## 即可获得外挂浮点lora+量化基模的torch模型，且支持lora参数可学习，其余参数冻结，支持lora微调。
## initia\_method：初始化方法可选："kaiming", "gaussian", "pissa" , 或者不传参默认全0构造。

#### 微调模型

简单示例：可根据自己需求设计训练框架。

import torch
from datasets import load\_dataset
from transformers import (
    AutoModelForCausalLM, # 或 AutoModelForSequenceClassification, etc.
    AutoTokenizer,
    TrainingArguments,
    Trainer,
    DataCollatorForLanguageModeling
)
from dopt.dopt\_lm.do\_opt import (
    optimize\_model,
    set\_trainable\_lora
)
# -------------------- 1. 定义模型和分词器 --------------------
# 这是一个用于文本生成的 LLM 示例，您可以替换为任何其他任务的模型
MODEL\_NAME = "facebook/opt-125m" # 替换为您想微调的模型
OUTPUT\_DIR = "./opt\_lora\_finetuned"
MAX\_SEQ\_LENGTH = 128
tokenizer = AutoTokenizer.from\_pretrained(MODEL\_NAME)
# 很多 LLM 没有 pad\_token，需要在 LoRA/PEFT 训练中设置
if tokenizer.pad\_token is None:
    tokenizer.pad\_token = tokenizer.eos\_token
# 加载基座模型
model = AutoModelForCausalLM.from\_pretrained(
    MODEL\_NAME,
    device\_map="auto"
)
# -------------------- 2. LoRA使能 --------------------
## 基于基模策略文件，已经完成添加lora配置
dopt\_config = "dopt\_config.json"
model = optimize\_model(model, dopt\_config)
## 基模量化权重 trained.pth  strict=False
model.load\_state\_dict(torch.load('xxx.pth'), strict=False)
model = set\_trainable\_lora(model, initia\_method='gaussian')
# -------------------- 3. 数据集准备和预处理 --------------------
# 示例：加载一个简单的文本数据集
dataset = load\_dataset("Abirate/english\_quotes", split="train")
def preprocess\_function(examples):
    # 简单的格式化：将 quote 和 author 连接起来
    texts = \[f"Quote: {q}\\nAuthor: {a}" for q, a in zip(examples\["quote"\], examples\["author"\])\]
    # 使用 tokenizer 进行编码
    return tokenizer(texts,
                     padding="max\_length",
                     truncation=True,
                     max\_length=MAX\_SEQ\_LENGTH)
# 应用预处理
tokenized\_dataset = dataset.map(
    preprocess\_function,
    batched=True,
    remove\_columns=\["quote", "author"\]
)
# 分割训练集和验证集 (可选)
tokenized\_dataset = tokenized\_dataset.train\_test\_split(test\_size=0.1)
train\_dataset = tokenized\_dataset\["train"\]
eval\_dataset = tokenized\_dataset\["test"\]
# Data Collator: 对于 LLM 训练，使用 DataCollatorForLanguageModeling
data\_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer,
    mlm=False # Causal LM (GPT-style) 训练设置为 False
)
# -------------------- 4. 训练参数和 Trainer --------------------
training\_args = TrainingArguments(
    output\_dir=OUTPUT\_DIR,
    per\_device\_train\_batch\_size=4,
    gradient\_accumulation\_steps=4, # 模拟更大的 batch size (4 \* 4 = 16)
    warmup\_steps=100,
    max\_steps=500, # 限制训练步数，以加快演示速度
    learning\_rate=2e-4, # LoRA 通常可以使用更高的学习率
    logging\_steps=50,
    save\_strategy="steps",
    save\_steps=500,
    do\_eval=True,
    evaluation\_strategy="steps",
    eval\_steps=500,
    fp16=True, # 启用混合精度训练以提高速度
)
# 初始化 Trainer
trainer = Trainer(
    model=model,
    args=training\_args,
    train\_dataset=train\_dataset,
    eval\_dataset=eval\_dataset,
    tokenizer=tokenizer,
    data\_collator=data\_collator,
)
# -------------------- 5. 开始训练 --------------------
print("\\n" + "="\*20 + " 开始 LoRA 训练 " + "="\*20)
trainer.train()
print("="\*20 + " 训练完成 " + "="\*20)
# -------------------- 6. 保存 LoRA 适配器 --------------------
torch.save(model.state\_dict(), 'trained\_lora.pth')

#### 导出量化参数

参考[量化参数提取导出](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/cannkit-plug-in-quantification#量化参数提取导出)。量化参数导出的作用是输出量化文件和导出onnx所用的fake\_quant\_weight.pth。

#### 导出ONNX模型

示例

import os
import sys
import onnx
import torch
import tempfile
from onnxsim import simplify
sys.path.append('path/to/dopt\_tool')
from dopt.common\_utils.onnx\_helper import OnnxHelper
from dopt.dopt\_lm.do\_opt import (
    optimize\_model,
    set\_quant\_state
)
def aigc\_model\_save(onnx\_model, save\_path):
    model\_size = onnx\_model.ByteSize()
    file\_name = os.path.basename(save\_path)
    if model\_size > 2 \* 1024 \* 1024 \* 1024:
        logging.info(f"Current ONNX model size is over than 2GB")
        onnx.save(onnx\_model, save\_path, save\_as\_external\_data=True,
                        all\_tensors\_to\_one\_file=True, location=f'{file\_name}.data',
                        size\_threshold=1024, convert\_attribute=False
        )
    else:
        from onnx.shape\_inference import infer\_shapes
        onnx\_model = infer\_shapes(onnx\_model)
        onnx.save(onnx\_model, save\_path)
transformer\_model = "your model define"
transformer\_model = optimize\_model(transformer\_model, './dopt\_config.json')
transformer\_model.load\_state\_dict(torch.load('trained\_lora.pth'))
set\_quant\_state(transformer\_model, False, False)
## 根据模型输入，随机生成导出onnx所用的输入。
dummy\_input = ()
transformer\_model(\*dummy\_input) ### 检查模型前向推理
## set you onnx input and output node name
input\_names=\["in0\_name", "in1\_name", "..."\]
output\_names=\["out0\_name", "out1\_name", "..."\]
onnx\_save\_path = './xxx.onnx'
with torch.no\_grad():
    with tempfile.NamedTemporaryFile() as f:
        onnx\_1 = f.name
        torch.onnx.export(
            transformer\_model,
            dummy\_input,
            onnx\_1,
            input\_names=input\_names,
            output\_names=output\_names,
            opset\_version=17,
            do\_constant\_folding=True
        )
        onnx\_model = onnx.load(onnx\_1)
    with tempfile.TemporaryDirectory() as temp\_dir:
        onnx\_2 = temp\_dir + '/tmp.onnx'
        aigc\_model\_save(onnx\_model, onnx\_2)
        onnx\_model = onnx.load(onnx\_2)
        onnx\_rename = OnnxHelper(onnx\_model).onnx\_model
    onnx\_simed,\_ = simplify(
        onnx\_rename,
        skipped\_optimizers=\[
            'fuse\_qkv',
            'fuse\_matmul\_add\_bias\_into\_gemm',
            'eliminate\_duplicate\_initializer'
        \]
    )
    aigc\_model\_save(onnx\_simed, onnx\_save\_path)