Feinabgestimmte Modelle mit LoRA-Adaptern generieren und ausführen
Erfahren Sie, wie Sie Modelle und Adapter in Formaten generieren, die für die Ausführung mit ONNX Runtime geeignet sind.
LoRA steht für Low Rank Adaptation. Es ist eine beliebte Methode zur Feinabstimmung, bei der einige Schichten in einem Graphen eingefroren und die Werte der Gewichte der variablen Schichten in einem Artefakt namens Adapter bereitgestellt werden.
Multi LoRA verwendet zur Laufzeit mehrere Adapter, um verschiedene Feinabstimmungen desselben Modells auszuführen. Der Adapter kann pro Szenario, pro Mandant/Kunde oder pro Benutzer sein, d. h. es kann nur wenige Adapter bis zu vielen Hunderten oder Tausenden geben.
Olive generiert Modelle und Adapter im ONNX-Format. Diese Modelle und Adapter können dann mit ONNX Runtime ausgeführt werden.
Setup
-
Olive installieren
Dies installiert Olive aus dem Hauptzweig. Ersetzen Sie dies durch Version 0.8.0, wenn diese veröffentlicht wird.
pip install git+https://github.com/microsoft/olive -
ONNX Runtime generate() installieren
pip install onnxruntime-genai -
Andere Abhängigkeiten installieren
pip install optimum peft -
torch und transformers downgraden
TODO: Es gibt einen Exportfehler mit torch 2.5.0 und eine Inkompatibilität mit transformers>=4.45.0
pip uninstall torch pip install torch==2.4 pip uninstall transformers pip install transformers==4.44 -
Ein Modell auswählen
Sie können ein Modell von HuggingFace oder Ihr eigenes Modell verwenden. Das Modell muss ein PyTorch-Modell sein.
-
Entscheiden Sie, ob Sie Ihr Modell feinabstimmen oder einen bereits vorhandenen Adapter verwenden
Es gibt viele bereits vorhandene Adapter auf HuggingFace. Wenn Sie mehrere verschiedene Adapter verwenden, müssen diese alle dieselben feinabgestimmten Schichten des Originalmodells verwenden.
Modell und Adapter im ONNX-Format generieren
-
Wenn Sie feinabstimmen, führen Sie Olive aus, um Ihr Modell feinabzustimmen
Hinweis: Diese Operation erfordert ein System mit einer NVIDIA-GPU mit installiertem CUDA
Verwenden Sie den Befehl
olive fine-tune: https://msdocs.de/Olive/how-to/cli/cli-finetune.htmlHier ist ein Beispiel für die Verwendung des Befehls
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 -
Optional Ihr Modell quantisieren
Verwenden Sie den Befehl
olive quantize: https://msdocs.de/Olive/how-to/cli/cli-quantize.html -
Das ONNX-Modell und den Adapter mit dem quantisierten Modell generieren
Verwenden Sie für diesen Schritt den Befehl
olive auto-opt: https://msdocs.de/Olive/how-to/cli/cli-auto-opt.htmlDer Parameter
--adapter pathkann entweder eine HuggingFace-Adapterreferenz oder ein Pfad zu dem von Ihnen oben feinabgestimmten Adapter sein.Das Argument
--providerkann ein ONNX Runtime Execution Provider sein.olive auto-opt -m <path to your model folder> --adapter_path <path to your adapter> -o <output model folder> --device cpu\|gpu --provider <provider> -
Adapter in das Format
.onnx_adapterkonvertierenFühren Sie diesen Schritt einmal für jeden von Ihnen generierten Adapter aus.
olive convert-adapters --adapter_path <path to your fine-tuned adapter --output_path <path to .onnx_adapter location --dtype float32
Ihre Anwendung schreiben
Dieses Beispiel wird in Python gezeigt, aber Sie können auch die C/C++-API, die C#-API und die Java-API (bald verfügbar!) verwenden.
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()
Die Anwendung aufrufen
python app.py -m <model folder> -a <.onnx_adapter files> -t <prompt template> -s <systemm prompt> -p <prompt>