Buckets:

mishig's picture
|
download
raw
22.6 kB

تسريع الاستدلال

تكون نماذج الانتشار بطيئة عند الاستدلال لأن التوليد عملية تكرارية يتم فيها تحسين الضوضاء تدريجياً لتتحول إلى صورة أو فيديو عبر عدد معين من "الخطوات". لتسريع هذه العملية، يمكنك تجربة تجارب مع مجدولات مختلفة، أو تقليل دقة أوزان النموذج لحسابات أسرع، أو استخدام آليات انتباه أكثر كفاءة في استخدام الذاكرة، وغير ذلك.

اجمع بين هذه التقنيات واستخدمها معًا لجعل الاستدلال أسرع مما لو استخدمت أي تقنية على حدة.

ستتناول هذه الدليل كيفية تسريع الاستدلال.

نوع بيانات النموذج

تؤثر دقة أوزان النموذج ونوع البيانات على سرعة الاستدلال، لأن الدقة الأعلى تتطلب ذاكرة أكبر للتحميل ووقتًا أطول لتنفيذ العمليات الحسابية. يقوم PyTorch بتحميل أوزان النموذج بنوع float32 أو الدقة الكاملة افتراضيًا، لذا فإن تغيير نوع البيانات هو طريقة بسيطة للحصول على استدلال أسرع بسرعة.

bfloat16 يشبه float16 لكنه أكثر مقاومة للأخطاء العددية. يختلف دعم الأجهزة لـ bfloat16، لكن معظم وحدات معالجة الرسومات الحديثة قادرة على دعم bfloat16.

import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]

float16 مشابه لـ bfloat16 لكنه قد يكون أكثر عرضة للأخطاء العددية.

import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]

تُدعم وضع TensorFloat-32 (tf32) على وحدات معالجة الرسوميات NVIDIA Ampere، حيث يقوم بحساب عمليات الالتفاف وضرب المصفوفات في tf32. وتبقى التخزين والعمليات الأخرى في float32. وهذا يتيح حسابات أسرع بشكل كبير عند دمجه مع bfloat16 أو float16.

PyTorch يُفعّل وضع tf32 للعمليات التجميعية (convolutions) افتراضياً فقط، وستحتاج إلى تفعيله صراحةً لعمليات ضرب المصفوفات.

import torch
from diffusers import StableDiffusionXLPipeline

torch.backends.cuda.matmul.allow_tf32 = True

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]

راجع مستندات التدريب بدقة مختلطة لمزيد من التفاصيل.

انتباه منتج نقطي مُصعّد

تحسّن الانتباه الموفّر للذاكرة سرعة الاستدلال و استهلاك الذاكرة!

انتباه حاصل الضرب النقطي المُقَيَّم (SDPA) ينفّذ عدة واجهات خلفية للانتباه، وهي FlashAttention وxFormers وتنفيذ أصلي بلغة C++. يقوم تلقائيًا باختيار الواجهة الخلفية الأكثر ملاءمة لمعداتك.

يتم تفعيل SDPA افتراضيًا إذا كنت تستخدم PyTorch >= 2.0 ولا يلزم إجراء أي تغييرات إضافية على الكود الخاص بك. ومع ذلك، يمكنك تجربة تجارب مع واجهات خلفية انتباه أخرى إذا كنت ترغب في اختيار واجهتك الخاصة. يستخدم المثال أدناه مدير السياق torch.nn.attention.sdpa_kernel لتفعيل الانتباه الفعال.

from torch.nn.attention import SDPBackend, sdpa_kernel
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"

with sdpa_kernel(SDPBackend.EFFICIENT_ATTENTION):
  image = pipeline(prompt, num_inference_steps=30).images[0]

torch.compile

يسرّع torch.compile الاستدلال من خلال ترميز كود PyTorch وعملياته إلى نوى مُحسّنة. يقوم Diffusers عادةً بترميز النماذج الأكثر كثافة في الحسابات مثل UNet أو transformer أو VAE.

فعّل إعدادات المُجمِّع التالية للحصول على أقصى سرعة (راجع القائمة الكاملة لمعرفة المزيد من الخيارات).

import torch
from diffusers import StableDiffusionXLPipeline

torch._inductor.config.conv_1x1_as_mm = True
torch._inductor.config.coordinate_descent_tuning = True
torch._inductor.config.epilogue_fusion = False
torch._inductor.config.coordinate_descent_check_all_directions = True

حمّل UNet وVAE وجمعهما. هناك عدة أوضاع مختلفة يمكنك الاختيار من بينها، لكن "max-autotune" يُحسّن لأقصى سرعة عن طريق التجميع إلى CUDA graph. تُقلّل رسوم CUDA بشكل فعال من العبء التشغيلي من خلال إطلاق عمليات GPU متعددة عبر عملية CPU واحدة.

With PyTorch 2.3.1, you can control the caching behavior of torch.compile. This is particularly beneficial for compilation modes like "max-autotune" which performs a grid-search over several compilation flags to find the optimal configuration. Learn more in the Compile Time Caching in torch.compile tutorial.

يُحسّن تغيير تخطيط الذاكرة إلى channels_last من كفاءة الذاكرة وسرعة الاستدلال.

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet.to(memory_format=torch.channels_last)
pipeline.vae.to(memory_format=torch.channels_last)
pipeline.unet = torch.compile(
    pipeline.unet, mode="max-autotune", fullgraph=True
)
pipeline.vae.decode = torch.compile(
    pipeline.vae.decode,
    mode="max-autotune",
    fullgraph=True
)

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]

تكون عملية التجميع بطيئة في المرة الأولى، لكن بمجرد اكتمالها، تصبح أسرع بشكل ملحوظ. حاول استخدام خط الأنابيب المُجمَّع فقط على نفس نوع عمليات الاستدلال. استدعاء خط الأنابيب المُجمَّع على حجم صورة مختلف يعيد تشغيل عملية التجميع، وهي عملية بطيئة وغير فعّالة.

تجميع الأشكال الديناميكية

تأكد دائمًا من استخدام الإصدار اليومي (nightly) من PyTorch للحصول على دعم أفضل.

يحافظ torch.compile على تتبع أشكال المدخلات والشروط، وإذا كانت هذه مختلفة، يعيد تجميع النموذج. على سبيل المثال، إذا تم تجميع نموذج على صورة بدقة 1024x1024 واستُخدم على صورة بدقة مختلفة، فإن ذلك يستدعي إعادة التجميع.

لتجنب إعادة التجميع، أضف dynamic=True لمحاولة توليد نواة (kernel) أكثر ديناميكية لتجنب إعادة التجميع عند تغيّر الشروط.

+ torch.fx.experimental._config.use_duck_shape = False
+ pipeline.unet = torch.compile(
    pipeline.unet, fullgraph=True, dynamic=True
)

يُوجِّه تحديد use_duck_shape=False المُجمِّع (Compiler) بشأن ما إذا كان ينبغي له استخدام المتغير الرمزي نفسه لتمثيل أحجام المدخلات المتطابقة. لمزيد من التفاصيل، راجع هذا تعليق.

قد لا تستفيد جميع النماذج من التجميع الديناميكي بشكل مباشر وقد تتطلب تعديلات. راجع هذا PR الذي حسّن تنفيذ AuraFlowPipeline للاستفادة من التجميع الديناميكي.

لا تتردد في فتح مشكلة إذا لم يعمل التجميع الديناميكي كما هو متوقع لنموذج Diffusers.

التجميع الإقليمي

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

استخدم طريقة compile_repeated_blocks()، وهي أداة مساعدة تغلف torch.compile، على أي مكوّن مثل نموذج الترانسفورمر كما هو موضح أدناه.

# pip install -U diffusers
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"

# compile only the repeated transformer layers inside the UNet
pipeline.unet.compile_repeated_blocks(fullgraph=True)

لتفعيل التجميع الإقليمي لنموذج جديد، أضف سمة _repeated_blocks إلى فئة النموذج تحتوي على أسماء الفئات (كسلاسل نصية) للكتل التي تريد تجميعها.

class MyUNet(ModelMixin):
    _repeated_blocks = ("Transformer2DModel",)  # ← compiled by default

لمزيد من أمثلة التجميع الإقليمية، راجع PR المرجعي.

يوجد أيضًا طريقة compile_regions في Accelerate تختار تلقائيًا الكتل المرشحة داخل النموذج لتجميعها. يتم تجميع بقية الرسم البياني بشكل منفصل. هذا مفيد للتجارب السريعة لأنه لا توجد خيارات كثيرة لتحديد الكتل المراد تجميعها أو تعديل أعلام التجميع.

# pip install -U accelerate
import torch
from diffusers import StableDiffusionXLPipeline
from accelerate.utils import compile_regions

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet = compile_regions(pipeline.unet, mode="reduce-overhead", fullgraph=True)

compile_repeated_blocks() صريحةٌ عمدًا. اذكر الكتل التي تريد تكرارها في _repeated_blocks ولن يُجمّع المُساعد سوى تلك الكتل. فهي توفر سلوكًا متوقعًا وسهولةً في الاستدلال حول إعادة استخدام ذاكرة التخزين المؤقت في سطرٍ واحد من الكود.

انقطاعات الرسم البياني

من المهم تحديد fullgraph=True في torch.compile للتأكد من عدم وجود انقطاعات في الرسم البياني للنموذج الأساسي. وهذا يتيح لك الاستفادة من torch.compile دون أي تدهور في الأداء. بالنسبة إلى UNet وVAE، يغيّر هذا الطريقة التي تصل بها إلى متغيرات الإرجاع.

- latents = unet(
-   latents, timestep=timestep, encoder_hidden_states=prompt_embeds
-).sample

+ latents = unet(
+   latents, timestep=timestep, encoder_hidden_states=prompt_embeds, return_dict=False
+)[0]

مزامنة وحدة معالجة الرسوميات

تُستدعى الدالة step() على المجدول بعد كل تنبؤ يصدره مُزيل الضوضاء، ويُستخدم فهرسة متغير sigmas. عند وضعه على وحدة معالجة الرسوميات، يُدخل تأخيراً بسبب مزامنة الاتصال بين وحدة المعالجة المركزية ووحدة معالجة الرسوميات. ويصبح هذا التأخير أكثر وضوحاً عندما يكون مُزيل الضوضاء مُجمَّعاً بالفعل.

بشكل عام، يجب أن تبقى على وحدة المعالجة المركزية (CPU) sigmas لتجنب مزامنة الاتصال وزمن الاستجابة.

راجع منشور المدونة torch.compile و Diffusers: دليل عملي لتحقيق الأداء الأقصى لتعظيم الأداء باستخدام torch.compile لنماذج الانتشار.

المعايير

راجع مجموعة بيانات diffusers/benchmarks للاطلاع على بيانات زمن الاستدلال واستهلاك الذاكرة للخطوط الأنابيب المُجمّعة.

تحتوي مستودعة diffusers-torchao أيضًا على نتائج قياس الأداء للإصدارات المُجمَّعة من Flux وCogVideoX.

النوى

Kernels هو مكتبة لبناء وتوزيع وتحميل نوى الحساب المُحسَّنة على Hub. يدعم مكتبة attention النوى المخصصة لنوى CUDA للعمليات مثل RMSNorm وGEGLU وRoPE وAdaLN.

يُبيّن دليل تكامل خط أنابيب Diffusers كيفية دمج نواة مع مهارة إضافة cuda-kernels. تُمكّن هذه المهارة وكيلًا، مثل Claude أو Codex، من كتابة نوى مخصصة موجهة نحو نموذج محدد وأجهزتك.

قم بتثبيت مهارة إضافة cuda-kernels لتعليم الوكيل كيفية كتابة نواة. يغطي منشور المدونة النوى المخصصة للجميع من Codex وClaude هذا الموضوع بتفصيل أكبر.

على سبيل المثال، نواة RMSNorm مخصصة (مولّدة بواسطة مهارة add cuda-kernels) مع torch.compile تسرّع توليد LTX-Video بمقدار 1.43x على H100.

Xet Storage Details

Size:
22.6 kB
·
Xet hash:
0b01671a8ac09101aa528fe6842db8d2fbded97d28ad09e9c55cce9f02c2fcd2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.