生成並執行帶 LoRA 介面卡的微調模型

瞭解如何生成適合使用 ONNX Runtime 執行的模型和介面卡。

LoRA 是 Low Rank Adaptation 的縮寫。它是一種流行的微調方法,凍結圖中的某些層,並透過一個名為介面卡的工件提供可變層的權重值。

多 LoRA 在執行時使用多個介面卡來運行同一模型的不同微調。介面卡可以是按場景、按租戶/客戶或按使用者劃分的,即介面卡數量可以從幾個到數百或數千個。

Olive 以 ONNX 格式生成模型和介面卡。這些模型和介面卡隨後可以透過 ONNX Runtime 執行。

設定

  1. 安裝 Olive

    這會從 main 安裝 Olive。當 0.8.0 版本釋出時請替換。

    pip install git+https://github.com/microsoft/olive
    
  2. 安裝 ONNX Runtime generate()

    pip install onnxruntime-genai
    
  3. 安裝其他依賴項

    pip install optimum peft
    
  4. 降級 torch 和 transformers

    待辦:torch 2.5.0 存在匯出錯誤,並且與 transformers>=4.45.0 不相容

    pip uninstall torch
    pip install torch==2.4
    pip uninstall transformers
    pip install transformers==4.44
    
  5. 選擇一個模型

    您可以使用 HuggingFace 上的模型,或您自己的模型。該模型必須是 PyTorch 模型。

  6. 決定是微調您的模型,還是使用預先存在的介面卡

    HuggingFace 上有許多預先存在的介面卡。如果您使用多個不同的介面卡,這些介面卡必須都使用原始模型的相同微調層。

以 ONNX 格式生成模型和介面卡

  1. 如果進行微調,執行 Olive 來微調您的模型

    注意:此操作需要一個配備 NVIDIA GPU 並安裝 CUDA 的系統

    使用 olive fine-tune 命令:https://microsoft.github.io/Olive/how-to/cli/cli-finetune.html

    以下是該命令的使用示例

    olive finetune --method qlora -m meta-llama/Meta-Llama-3-8B -d nampdn-ai/tiny-codes --train_split "train[:4096]" --eval_split "train[4096:4224]" --text_template "### Language: {programming_language} \n### Question: {prompt} \n### Answer: {response}" --per_device_train_batch_size 16 --per_device_eval_batch_size 16 --max_steps 150 --logging_steps 50 -o adapters\tiny-codes
    
  2. (可選)量化您的模型

    使用 olive quantize 命令:https://microsoft.github.io/Olive/how-to/cli/cli-quantize.html

  3. 使用量化模型生成 ONNX 模型和介面卡

    此步驟使用 olive auto-opt 命令:https://microsoft.github.io/Olive/how-to/cli/cli-auto-opt.html

    --adapter path 可以是 HuggingFace 介面卡引用,也可以是您上面微調的介面卡路徑。

    --provider 引數可以是 ONNX Runtime 執行提供者。

    olive auto-opt -m <path to your model folder> --adapter_path <path to your adapter> -o <output model folder> --device cpu\|gpu --provider <provider> 
    
  4. 將介面卡轉換為 .onnx_adapter 格式

    為您生成的每個介面卡執行此步驟一次。

    olive convert-adapters --adapter_path <path to your fine-tuned adapter --output_path <path to .onnx_adapter location --dtype float32
    

編寫您的應用程式

此示例以 Python 顯示,但您也可以使用 C/C++ API、C# API 和 Java API(即將推出!

import onnxruntime_genai as og
import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Application to load and switch ONNX LoRA adapters')
parser.add_argument('-m', '--model', type=str, help='The ONNX base model')
parser.add_argument('-a', '--adapters', nargs='+', type=str, help='List of adapters in .onnx_adapters format')
parser.add_argument('-t', '--template', type=str, help='The template with which to format the prompt')
parser.add_argument('-s', '--system', type=str, help='The system prompt to pass to the model')
parser.add_argument('-p', '--prompt', type=str, help='The user prompt to pass to the model')
args = parser.parse_args()

model = og.Model(args.model)
if args.adapters:
    adapters = og.Adapters(model)
    for adapter in args.adapters:
        adapters.load(adapter, adapter)

tokenizer = og.Tokenizer(model)
tokenizer_stream = tokenizer.create_stream()

prompt = args.template.format(system=args.system, input=args.prompt)

params = og.GeneratorParams(model)
params.set_search_options(max_length=2048, past_present_share_buffer=False)
# This input is generated for transformers versions > 4.45
#params.set_model_input("onnx::Neg_67", np.array(0, dtype=np.int64))
params.input_ids = tokenizer.encode(prompt)

generator = og.Generator(model, params)

if args.adapters:
   for adapter in args.adapters:
      print(f"[{adapter}]: {prompt}")
      generator.set_active_adapter(adapters, adapter)

      while not generator.is_done():
        generator.compute_logits()
        generator.generate_next_token()

        new_token = generator.get_next_tokens()[0]
        print(tokenizer_stream.decode(new_token), end='', flush=True)
else:
    print(f"[Base]: {prompt}")

    while not generator.is_done():
       generator.compute_logits()
       generator.generate_next_token()

呼叫應用程式

python app.py -m <model folder> -a <.onnx_adapter files> -t <prompt template> -s <systemm prompt> -p <prompt>

參考資料