Buckets:

mishig's picture
|
download
raw
8.68 kB

Google TPU

وحدات معالجة التينسور (TPUs) هي معجلات التعلم الآلي من Google، وهي متاحة على شكل Cloud TPUs (v6e, v7x). يعمل Diffusers عليها من خلال TorchTPU، وهو واجهة PyTorch الخاصة بـ TPUs، مع تغييرات برمجية طفيفة.

يتوفر ثلاثة أوضاع تنفيذ:

الوضع ثابت كيفية التفعيل ملاحظات
الحماس الصارم (الافتراضي) EagerMode.DEFER_NEVER pipe.to("tpu") عمليات تُنفَّذ واحدة تلو الأخرى، غير متزامنة
الحماسي المُحسَّن EagerMode.DEFER_AND_FUSE TORCH_TPU_DEFER_AND_FUSE=1 عمليات مؤجلة ومدمجة في رسوم بيانية أكبر؛ أسرع من الوضع العاجل الصارم، مع وقت تجميع أطول
تجميع — torch.compile(module, backend="tpu") التجميع المسبق (AOT) باستخدام TpuBackend

اتبع دليل تثبيت TorchTPU. بعد التثبيت، يُحمّل import torch المكتبة تلقائيًا ويسجّل جهاز "tpu"، لذا فإن pipe.to("tpu") هو التغيير الوحيد المطلوب. أضف import torch_tpu فقط إذا كنت قد عطّلت التحميل التلقائي للواجهة الخلفية باستخدام TORCH_DEVICE_BACKEND_AUTOLOAD=0.

الوضع الجشع

لا يتسع نموذج FLUX.1-schnell بالكامل على شريحة v6e واحدة في آنٍ واحد، لذا استخدم enable_model_cpu_offload() لنقل كل نموذج إلى وحدة المعالجة TPU فقط أثناء تشغيله. يقوم هذا الأمر باكتشاف جهاز "tpu" تلقائيًا.

import torch

from diffusers import FluxPipeline

pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-schnell", dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()

image = pipe(
    prompt="a golden retriever surfing a wave, photorealistic",
    height=1024,
    width=1024,
    num_inference_steps=4,
    guidance_scale=0.0,
).images[0]

image.save("output.png")

إذا كان النموذج كبيرًا جدًا ليُحمَّل على شريحة واحدة، أو كان لديك عدة شرائح وتريد تقليل زمن الاستجابة، فقسّم النماذج على الشرائح بدلاً من ذلك. راجع قسم التوازي على مستوى الموترات.

وضع التجميع

يسجّل TorchTPU "tpu" كاسم لخلفية torch.compile (تحت الغطاء TpuBackend)، لذا تُجمَّع المكونات كما تُجمَّع أي أهداف أخرى لـtorch.compile. يكون الاستدعاء الأول (إحماء) بطيئاً لأنه يقوم بالتجميع؛ أما الاستدعاءات اللاحقة ذات الأشكال نفسها فتعيد استخدام الرسم البياني المُجمَّع.

يتطلب TorchTPU أشكالاً ثابتة، لذا مرّر dynamic=False. يُعاد تجميع شكل height أو width جديد مرة واحدة لكل شكل، بينما تُعاد استخدام الأشكال التي شوهدت مسبقاً. تغيير num_inference_steps لا يؤدي إلى إعادة التجميع.

عندما يتسع خط الأنابيب بالكامل على شريحة واحدة، انقله إلى TPU وادمج المحوّل الكامل. يتسع Stable Diffusion 3.5 Medium (حوالي 15GB في bf16) على شريحة v6e واحدة.

import torch

from diffusers import StableDiffusion3Pipeline

pipe = StableDiffusion3Pipeline.from_pretrained("stabilityai/stable-diffusion-3.5-medium", dtype=torch.bfloat16)
pipe.to("tpu")
pipe.transformer.compile(backend="tpu", fullgraph=True, dynamic=False)

# Warmup — triggers static graph compilation.
pipe(prompt="warmup", height=1024, width=1024, num_inference_steps=40, guidance_scale=4.5)

# Later calls with the same shapes reuse the compiled graph.
image = pipe(
    prompt="a golden retriever surfing a wave, photorealistic",
    height=1024,
    width=1024,
    num_inference_steps=40,
    guidance_scale=4.5,
).images[0]

image.save("output.png")

إذا لم يتسع خط المعالجة لشريحة واحدة:

  • عند استخدام عدة شرائح، استخدم التوازي على مستوى المصفوفات بدلاً من ذلك لتقسيم النموذج. تبقى جميع العمليات على وحدة المعالجة TPU، ويعمل pipe.transformer.compile(...) بنفس الطريقة على المحوّل المقسّم.
  • مع enable_model_cpu_offload()، لا يمكن تتبّع خطافات النقل بواسطة torch.compile. قم بتجميع كتل التحوّل المتكررة فقط، باستخدام pipe.transformer.compile_repeated_blocks(backend="tpu", fullgraph=True, dynamic=False).

توازي الموتر

قسّم النماذج التي تتجاوز سعة شريحة واحدة على عدة شرائح. يتجاوز كل من مُشفّر النص (48GB) والمحوّل (64GB) في FLUX.2-dev سعة شريحة واحدة، لذا يقوم المثال أدناه بتقسيم كلاهما:

  • المحوّل مع TensorParallelConfig، المُمرَّر إلى معامل parallel_config في from_pretrained(). يقرأ كل رتبة شريحتها الخاصة فقط من كل وزن مُجزّأ، لذا لا يتم إنشاء النموذج الكامل أبدًا. للتفاصيل العامة حول TP (_tp_plan، colwise/rowwise)، راجع دليل Tensor parallelism.
  • مشفر النص مع توازي المصفوفات الخاص بـ Transformers، مع تمرير DistributedConfig والشبكة نفسها.

على TPU، قم بتهيئة مجموعة العمليات باستخدام backend="tpu_dist" وابنِ الشبكة باستخدام DeviceMesh("tpu", ...).

import torch
import torch.distributed as dist
from torch.distributed.device_mesh import DeviceMesh
from transformers import DistributedConfig, Mistral3ForConditionalGeneration

from diffusers import Flux2Pipeline, Flux2Transformer2DModel, TensorParallelConfig

dist.init_process_group(backend="tpu_dist")
mesh = DeviceMesh("tpu", list(range(dist.get_world_size())))

repo_id = "black-forest-labs/FLUX.2-dev"
text_encoder = Mistral3ForConditionalGeneration.from_pretrained(
    repo_id,
    subfolder="text_encoder",
    dtype=torch.bfloat16,
    distributed_config=DistributedConfig(tp_plan="auto"),
    device_mesh=mesh,
)
transformer = Flux2Transformer2DModel.from_pretrained(
    repo_id, subfolder="transformer", dtype=torch.bfloat16, parallel_config=TensorParallelConfig(mesh=mesh)
)
pipe = Flux2Pipeline.from_pretrained(
    repo_id, text_encoder=text_encoder, transformer=transformer, dtype=torch.bfloat16
)
pipe.vae.to("tpu")

image = pipe(
    prompt="a golden retriever surfing a wave, photorealistic",
    num_inference_steps=28,
    generator=torch.Generator("cpu").manual_seed(0),
).images[0]
if dist.get_rank() == 0:
    image.save("output.png")

شغّل عملية واحدة لكل شريحة. اضبط --nproc_per_node لاستخدام جميع شرائح TPU الموجودة على مضيفك.

eval $(python -m torch_tpu._internal.distributed.launchers.singlehost_wrapper | sed 's/^/export /')
torchrun --nproc_per_node=8 flux2_tp.py

يستخدم أمر الإقلاع أعلاه وحدة داخلية في TorchTPU (torch_tpu._internal)، وليس واجهة برمجة تطبيقات مستقرة، ومن المتوقع أن يتغير في إصدار مستقبلي من TorchTPU. تحقق من مستودع TorchTPU لمعرفة الطريقة الحالية لإطلاق المهام متعددة الرقائق.

Xet Storage Details

Size:
8.68 kB
·
Xet hash:
6354599e2369fdd6ef0c5ad445a41d5ac143dd4111aaee733fed5b53e852061c

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