Transformers documentation

المصدّرون

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

المصدّرون

صدّر أي PreTrainedModel إلى ONNX أو ExecuTorch أو برنامج PyTorch مستقل، بغض النظر عن وقت التشغيل المستهدف.

exporter = DynamoExporter()  # or OnnxExporter, ExecutorchExporter
config = DynamoConfig(dynamic=True)
exported = exporter.export(model, inputs, config=config)

توجد أدوات التصدير داخل Transformers بدلاً من مكتبة لاحقة، لذا تُدعم تغييرات البنية، وأنماط الانتباه الجديدة، وأنواع ذاكرة التخزين المؤقت المخصصة عند التصدير بمجرد توفرها في كود النمذجة.

المُصدِّرات تجريبية. تعمل العديد من التصحيحات في هذا الوحدة على تجاوز أخطاء محددة في المصادر الأصلية (Torch، ONNX Script، ONNX Runtime، ExecuTorch)، وستُزال بمجرد اعتماد الإصلاح في المصدر الأصلي. حتى تستقر واجهة برمجة التطبيقات، تعامل مع التصحيحات على أنها مرتبطة بالإصدارات المستخدمة في مجموعة الاختبارات. ثبّت تلك الإصدارات في أدوات الإنتاج، وتوقع ظهور تصحيحات جديدة واختفاء القديمة مع اعتماد التغييرات في المصدر الأصلي.

مُصدِّرالمخرجاتوقت التشغيل
DynamoExporterExportedProgramأي وقت تشغيل لـ PyTorch، تجميع مسبق
OnnxExporterONNXProgramأي وقت تشغيل ONNX (ORT، TensorRT، OpenVINO)
ExecutorchExporterExecutorchProgramManagerالأجهزة المحمولة وأجهزة الحافة (ExecuTorch)
OpenVINOExporteropenvino.Modelبيئة تشغيل OpenVINO (معالج CPU/وحدة معالجة رسومية GPU/وحدة معالجة عصبية NPU من Intel)

يختار AutoHfExporter المُصدِّر المناسب من ملف الإعداد، بينما يختار AutoExportConfig فئة الإعداد الصحيحة من قاموس. يتبع كلاهما نفس نمط الفئة التلقائية في Transformers، وهو مفيد عند اختيار الخلفية في وقت التشغيل بدلاً من تثبيتها في موقع الاستدعاء.

from transformers.exporters import AutoExportConfig, AutoHfExporter

export_config_dict = {"export_format": "onnx", "dynamic": True}
config = AutoExportConfig.from_dict(export_config_dict)
exporter = AutoHfExporter.from_config(config)

onnx_program = exporter.export(model, inputs, config=config)

التثبيت

قم بتثبيت التبعيات الخاصة بالخلفية التي تخطط للتصدير إليها.

الإصدارات أدناه هي التي تُثبَّت عليها مجموعة اختبارات المُصدِّر. غالبًا ما تعمل الإصدارات الأحدث أو الأقدم، لكن تصحيحات المُصدِّر تستهدف واجهة برمجة تطبيقات محددة، لذا في أدوات الإنتاج ثبِّت هذه الإصدارات وتوقّع أن يسجّل HfExporter تحذيرًا عند اكتشافه انحرافًا.

Dynamo
ONNX
ExecuTorch XNNPACK
ExecuTorch MLX
OpenVINO
pip install transformers "torch==2.12.0"

تصدير نموذج

تشارك جميع مُصدِّرات البيانات نفس الواجهة. أنشئ مُصدِّر بيانات باستخدام إعداد، ثم استدعِ export().

يمكنك التبديل بين بيئات التشغيل عن طريق استبدال فئة المُصدِّر.

Dynamo
ONNX
ExecuTorch
OpenVINO
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.exporters import DynamoExporter, DynamoConfig

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
inputs = tokenizer("Hello, world!", return_tensors="pt")

exporter = DynamoExporter()
config = DynamoConfig(dynamic=True)
exported = exporter.export(model, inputs, config=config)

# run the exported graph directly
outputs = exported.module()(**inputs)

الأشكال الديناميكية

تعيين dynamic=True يحدد كل بُعد من أبعاد المصفوفة (Tensor) على أنه ديناميكي، مما يتيح للرسم البياني المُصدَّر قبول مدخلات بأي حجم وقت التشغيل دون الحاجة إلى إعادة التتبع.

للحصول على تحكم دقيق في الأبعاد الديناميكية، مرّر dynamic_shapes صراحةً بدلاً من ذلك، حيث يتم تمريرها مباشرة إلى torch.export.export.

Dynamo
ONNX
ExecuTorch
OpenVINO
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.exporters import DynamoExporter, DynamoConfig

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
inputs = tokenizer(["Hello, world!", "Hi"], padding=True, return_tensors="pt")

batch = torch.export.Dim("batch", min=1, max=32)
seq = torch.export.Dim("seq", min=1, max=2048)

exporter = DynamoExporter()
config = DynamoConfig(
    dynamic_shapes={"input_ids": {0: batch, 1: seq}, "attention_mask": {0: batch, 1: seq}},
    # Emit data-dependent shape guards as runtime asserts instead of failing the export when a
    # guard wouldn't hold across the explicit symbolic range. Most LLMs need this under fine-grained
    # ``Dim(min=, max=)`` bounds. Not needed with ``dynamic=True`` / ``Dim.AUTO``, where torch.export
    # infers shape relations instead of verifying them against user-stated bounds.
    prefer_deferred_runtime_asserts_over_guards=True,
)
exported = exporter.export(model, inputs, config=config)

النماذج التوليدية

في التوليد الذاتي التتابعي، يكون لشكل forward الخاص بالنموذج أشكال مختلفة في خطوة التعبئة المسبقة (الموجز الكامل، بدون ذاكرة KV) مقارنةً بخطوة فك الترميز (رمز واحد، ذاكرة KV ممتلئة). تعرض أدوات التصدير ~HfExporter.export_for_generation، والتي تقسم المرحلتين وتصدر كلًا منهما على حدة.

بالنسبة إلى النماذج التوليدية متعددة الوسائط، ينقسم التمهيد (prefill) بشكل إضافي إلى مُشفِّر للصور أو الصوت، ونموذج اللغة، وlm_head. يعتمد اكتشاف المُشفِّر ونموذج اللغة على مُوجِّهَي get_encoder() (مع modality="image" أو "audio") وget_decoder()، بحيث تعمل أي بنية معمارية جديدة تستخدم هذه المُوجِّهات دون أي إعداد مسبق.

يظهر مكوّن المُسقط (projector) فقط عندما يكشف النموذج عن واحد تحت اسم خاصية (multi_modal_projector، connector، embed_vision، embed_audio). في النموذج Qwen2-VL أدناه، يُدمج المُسقط في برج الرؤية، لذا فإن قاموس مكوّناته لا يحتوي على مفتاح multi_modal_projector منفصل. يجب على البنى المعمارية الجديدة محاذاة خاصية المُسقط لديها مع أحد هذه الأسماء بدلاً من توسيع القائمة.

Dynamo
ONNX
ExecuTorch
OpenVINO
from transformers import AutoModelForImageTextToText, AutoProcessor
from transformers.exporters import DynamoExporter, DynamoConfig

model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
messages = [{"role": "user", "content": [{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"}, {"type": "text", "text": "Describe this image."}]}]
text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
inputs = processor(text=text, images=messages[0]["content"][0]["url"], return_tensors="pt").to(model.device)

exporter = DynamoExporter()
config = DynamoConfig(dynamic=True)
components = exporter.export_for_generation(model, inputs, config=config)
# components = {"image_encoder": ExportedProgram, "language_model": ExportedProgram, "lm_head": ExportedProgram, "decode": ExportedProgram}

المكونات المُصدَّرة هي رسوم بيانية مستقلة، وليست خط أنابيب استدلال جاهزًا للتشغيل. يقع على عاتق المستدعي مسؤولية تشغيل كل مشفّر، وإسقاط التضمينات، وتنسيق حلقة التوليد.

كيف يعمل export_for_generation

decompose_for_generation() runs model.generate(**inputs, max_new_tokens=2) once and hooks model.forward to capture the real prefill and decode kwargs (and the per-submodule kwargs via hooks on each encoder/projector/language model if the model is multi-modal). That’s why it works for any architecture, including decoder-only, SSM, encoder-decoder, and multi-modal models, without per-model glue. export_for_generation is a one-liner over it.

تقوم عملية الالتقاط بتشغيل النموذج بشكل فوري على inputs، لذا مرّر قيمًا صغيرة لكنها تمثيلية، مثل موجه قصير، أو صورة صغيرة واحدة، أو بعض الإطارات الصوتية. البرنامج المُصدَّر غير مرتبط بتلك الأحجام (فالأشكال الديناميكية لا تزال تتدفق عبره)، لكن مدخلات الالتقاط الأصغر تجعل decompose_for_generation أرخص وتُبقي الاستدلال على الأشكال الرمزية قابلاً للتنفيذ.

استدعِ decompose_for_generation مباشرةً للتدخل بين التفكيك والتصدير، مثل تنفيذ تمرير عاجل للتحقق، أو تبديل مدخلات وحدة فرعية، أو تجاوز مرحلة معينة.

from transformers.exporters.utils import decompose_for_generation

components = decompose_for_generation(model, inputs)
# {"image_encoder": (submodel, fwd_kwargs), "language_model": (...), ..., "decode": (...)}

exported = {}
for name, (submodel, subinputs) in components.items():
    eager_outputs = submodel(**subinputs)  # sanity-check the eager forward before exporting
    exported[name] = exporter.export(submodel, subinputs, config=config)

فك ترميز متعدد الرموز

بشكل افتراضي، يُنفَّذ مكوّن decode كخطوة رمز واحد — رمز استعلام واحد مقابل ذاكرة KV — لذلك يُخصِّص torch.export محور تسلسل الاستعلام إلى 1. مرِّر multi_token_decode=True لالتقاط decode كخطوة فك ترميز متعددة الرموز بدلاً من ذلك: يدمج decompose_for_generation() خطوتين متتاليتين من فك الترميز (يُلتقطان مع max_new_tokens=3) في تمريرة أمامية واحدة، بحيث يبقى ذلك المحور رمزياً. ثم تخدم مخططة واحدة كل طول للاستعلام — رمز واحد (فك ترميز عادي)، أو عدة رموز دفعة واحدة (استكمال من الماضي، مثل قبول مجموعة من الرموز التخمينية)، أو تعبئة مسبقة عادية عندما تكون الذاكرة المؤقتة فارغة.

Dynamo
ONNX
ExecuTorch
from transformers.exporters import DynamoExporter, DynamoConfig

exporter = DynamoExporter()
config = DynamoConfig(dynamic=True)
components = exporter.export_for_generation(model, inputs, config=config, multi_token_decode=True)
# components["decode"] now accepts a variable number of query tokens

يبقى محور الاستعلام رمزيًا فقط عند التصدير بأشكال ديناميكية (dynamic=True)؛ أما التصدير الثابت فيجمّده عند الطول المُلتقط، مما يمنح رسمًا ثابتًا متعدد الرموز. يتكامل هذا مع ذاكرة KV الثابتة أدناه — حيث تكتب عملية فك الترميز المدمجة رموز كل خطوة في ذاكرة التخزين المؤقت ذات الحجم الثابت في مكانها، وتتعامل الذاكرة داخليًا مع مكان هبوطها.

ذاكرة KV الثابتة

أمثلة ExecuTorch في هذا القسم، بما في ذلك التحديثات بدون نسخ وحلقة فك الترميز، هي خاصة بـ XNNPACK فقط. يرفض مُصدِّر MLX StaticCache؛ استخدم DynamicCache مع MLX.

تُنشئ generate() كاش DynamicCache افتراضيًا، مع إعادة تخصيص الذاكرة كلما امتدّت التسلسلات — وهو هدف متحرك للرسوم المصدَّرة. الكاش الثابت هو مخزن ذاكرة بحجم ثابت، يُخصَّص مرة واحدة ويُكتب فيه في الموقع الحالي في كل خطوة. عند دمجه مع فك ترميز متعدد الرموز ينهار التوليد في رسم مصدَّر واحد: يتلقى رسم decode كاشًا بحجم ثابت وعددًا متغيرًا من رموز الاستعلام، بحيث يخدم رسم واحد كلًا من الموجه (كاش فارغ → تعبئة مسبقة) وكل رمز مولَّد (كاش مملوء → فك ترميز). صدّره عن طريق تمرير GenerationConfig مع cache_implementation="static" (وmax_cache_len) إلى جانب multi_token_decode=True:

Dynamo
ONNX
ExecuTorch XNNPACK
from transformers import GenerationConfig
from transformers.exporters import DynamoExporter, DynamoConfig

exporter = DynamoExporter()
gen_config = GenerationConfig(cache_implementation="static", max_cache_len=2048)
components = exporter.export_for_generation(
    model, inputs, config=DynamoConfig(dynamic=True), generation_config=gen_config, multi_token_decode=True
)

أصبح لدى رسم decode الآن محوران رمزيان — طول الاستعلام (عدد الرموز التي تُدخلها) وطول الكاش (max_cache_len، قابل للتعديل عند التحميل). يُحدد dynamic=True هذه المحاور (وكل المحاور الأخرى) على أنها Dim.AUTO، بحيث يقبل الرسم المُصدَّر أي طول للاستعلام وأي حجم للكاش عند التحميل.

التحديثات في الموقع دون نسخ

يُمرَّر الكاش الثابت ويُعدَّل في مكانه، لذا تحمل وسادة واحدة الحالة عبر خطوات فك الترميز دون نسخ على المضيف — طالما أن وقت التشغيل يربط وسادات المستدعي بدلاً من النسخ عبر ساحة خاصة به. ما يتطلبه ذلك هو الجزء الوحيد المتبقي لكل منصة:

  • Dynamo — يُمثّل البرنامج المُصدَّر كتابةَ الكاش على أنها USER_INPUT_MUTATION، لذا فإن استدعاء components["decode"].module()(...) يُحدِّث مُتجهات الكاش التي تمررها مباشرةً. أعد استخدام نفس المُتجهات في كل خطوة؛ لا حاجة لأي إعداد.

  • ONNX Runtime — يكشف رسم فك الترميز عن ذاكرة التخزين المؤقت كأزواج مطابقة من input.<name> / output.<name>. تربط دالة CudaSession.set_buffer_sharing في ORT (onnxruntime.transformers.io_binding_helper) كل زوج مع مخزن بيانات واحد على الجهاز، بحيث تُقرأ ذاكرة التخزين المؤقت وتُحدَّث في مكانها عبر الحلقة دون أي رحلات ذهاب وإياب إلى المضيف.

  • ExecuTorch (XNNPACK) — عطّل تخصيصات تخطيط الذاكرة في ExecutorchConfig حتى يمكن تنفيذ الكتابة في الموقع داخل المصفوفة الخاصة بالمستدعي (راجع المرجع لمعرفة وظيفة كل علم):

    config = ExecutorchConfig(
        backend="xnnpack",
        dynamic=True,
        alloc_graph_input=False,
        alloc_graph_output=False,
        alloc_mutable_buffers=False,
    )

    يتطلب الكتابة في الموقع دون نسخ أيضًا من المستدعي ربط مخازن الإخراج وقت التشغيل عبر Method::set_output_data_ptr — غير معرّض عبر بيئة التشغيل الخاصة بلغة بايثون (فإن executorch.runtime.Method يعرّض فقط execute/set_inputs/get_outputs). تُهيّئ الأعلام المذكورة أعلاه هذا الإعداد، لكن الكتابة في الموقع هي مسار مخصص لـ C++ فقط (انظر مثال حلقة فك الترميز في ExecuTorch أدناه). من بايثون، اقرأ ذاكرة التخزين المؤقت المحدّثة من مخرجات الطريقة في كل خطوة.

Decode-loop inference examples

تتخذ الحلقة الشكل نفسه على جميع منصات التشغيل — فهي نفس الرسم البياني طوال العملية. ابدأ من ذاكرة مؤقتة ثابتة الحجم فارغة، ثم مرّر الموجه (prompt) كاملاً مرة واحدة (ذاكرة مؤقتة فارغة → مرحلة التعبئة المسبقة prefill)، ثم رمزاً تلو الآخر (ذاكرة مؤقتة ممتلئة → مرحلة فك الترميز decode). تمرّر كل استدعاء input_ids، وقناع انتباه سببي attention_mask، وposition_ids (تُزاد بعدد الرموز الجديدة في كل خطوة)، بالإضافة إلى الذاكرة المؤقتة، وتُعاد منها قيم اللوجيت (logits) لكل موضع استعلام. يتتبع الكاش الثابت (static cache) داخلياً موضع كل رمز في الذاكرة المؤقتة، لذا لا حاجة لإيصال أي شيء إضافي عبر الاستدعاء. يختلف إعداد الذاكرة المؤقتة حسب بيئة التشغيل (كائن StaticCache لـ Dynamo، مخازن أجهزة خام لـ ONNX Runtime، مصفوفات مستدعي في C++ لـ ExecuTorch)، لذا يبني كل تبويب إعداداته أدناه. تحدّث تبويبا Dynamo وONNX Runtime الذاكرة المؤقتة في مكانها؛ أما المسار في المكان نفسه في ExecuTorch فهو بلغة C++ (فبيئة التشغيل الخاصة به بلغة بايثون لا تستطيع ذلك، كما ذُكر أعلاه).

Dynamo
ONNX Runtime
ExecuTorch XNNPACK

torch.export records the static-cache write as a USER_INPUT_MUTATION, so the loaded graph’s module() updates the StaticCache you pass in directly — one cache carries state across the whole loop with nothing to bind or thread back out. register_pytree_node(StaticCache) lets torch.export.load unflatten the StaticCache input. The cache has to be initialized up front (torch.export bakes the allocated K/V into the input spec, so a lazy blank cache won’t match) — but the saved program carries its own example_inputs, so reuse that already-initialized StaticCache template, reset to empty:

import copy
import torch
from transformers import StaticCache
from transformers.exporters.exporter_dynamo import register_pytree_node

register_pytree_node(StaticCache)
exported = torch.export.load("decode.pt2")
decode = exported.module()   # runs on the device its inputs / cache live on (CUDA here)

# the artifact carries an initialized StaticCache template — reuse it (reset to empty)
_, example_kwargs = exported.example_inputs
past_key_values = copy.deepcopy(example_kwargs["past_key_values"])
past_key_values.reset()

def causal_mask(positions, cache_len):   # [1, 1, len(positions), cache_len]
    return (torch.arange(cache_len, device="cuda")[None, :] <= positions[:, None])[None, None]

# prefill: the whole prompt in one call
positions = torch.arange(prompt_len, device="cuda")
logits = decode(input_ids=prompt_ids, attention_mask=causal_mask(positions, max_cache_len),
                position_ids=positions[None], past_key_values=past_key_values).logits
next_token = logits[:, -1:].argmax(-1)

# decode: query=1 buffers reused in place
input_ids = torch.empty((1, 1), dtype=torch.long, device="cuda")
position_ids = torch.empty((1, 1), dtype=torch.long, device="cuda")
attention_mask = torch.empty((1, 1, 1, max_cache_len), dtype=torch.bool, device="cuda")
slots = torch.arange(max_cache_len, device="cuda")
for position in range(prompt_len, max_cache_len):
    input_ids.copy_(next_token)
    position_ids.fill_(position)
    attention_mask[0, 0, 0].copy_(slots <= position)
    logits = decode(input_ids=input_ids, attention_mask=attention_mask,
                    position_ids=position_ids, past_key_values=past_key_values).logits
    next_token = logits[:, -1:].argmax(-1)

التكميم

تتلقى كل إعدادات تصدير quantizer يقوم بتكميم النموذج أثناء التصدير، إما على رسم torch.export FX (PT2E أو NNCF، لكل واجهة خلفية) أو على نموذج ONNX أو OpenVINO المحوّل (ONNX Runtime أو NNCF). راجع تكميم التصديرات للاطلاع على مُكمّيمات التصدير، وواجهاتها الخلفية، والمعايرة، وكيفية إضافة واحدة منها.

القيود والحلول البديلة

لكلٍّ من torch.export وtorch.onnx.export وExecuTorch بعض العيوب الدقيقة المتعلقة بأنماط PyTorch محددة. تعمل أدوات التصدير على تجاوز هذه العيوب من خلال مجموعة صغيرة من التصحيحات القابلة للعكس وإصلاحات على مستوى FX تُطبَّق في نقاط محددة بوضوح ضمن سير عمل التصدير. لا يظهر أيٌّ من ذلك من واجهة export العامة، لكن أكثر الأمور شيوعًا التي ينبغي معرفتها هي:

  • لا يمكن تصدير FlashAttention وFlexAttention على أي منصة خلفية. يُعد sdpa الإعداد المفضل، ويعمل eager أيضاً (ببطء أكبر). اضبط أحدهما على النموذج قبل استدعاء export إذا كان يستخدم إعداداً آخر.
  • يتتبع grouped_mm بسلاسة عبر DynamoExporter ويُترجم تلقائيًا من أجل OnnxExporter. أما في حالة استخدام ExecutorchExporter مع XNNPACK أو MLX، فيقوم المُصدِّر باستبدال خبراء MoE بـ batched_mm قبل التصدير.

الخطوات التالية

Update on GitHub