Diffusers documentation

الفلسفة

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

and get access to the augmented documentation experience

to get started

الفلسفة

🧨 يوفر Diffusers نماذج انتشار مَسبقة التدريب متطورة عبر عدة أنماط. يهدف إلى العمل كـ صندوق أدوات معياري لكل من الاستدلال والتدريب.

نهدف إلى بناء مكتبة تتحمل اختبار الزمن، ولذلك نولي تصميم واجهة برمجة التطبيقات أهمية بالغة.

بإيجاز، بُني Diffusers ليكون امتدادًا طبيعيًا لـ PyTorch. لذلك، تستند معظم اختياراتنا التصميمية إلى مبادئ تصميم PyTorch. دعونا نستعرض أهمها:

السهولة في الاستخدام على حساب الأداء

  • على الرغم من أن Diffusers يحتوي على العديد من الميزات المدمجة لتعزيز الأداء (انظر الذاكرة والسرعة)، إلا أن النماذج تُحمَّل دائمًا بأعلى دقة وأقل تحسين. لذلك، افتراضيًا، تُنشَّأ خطوط أنابيب الانتشار دائمًا على وحدة المعالجة المركزية (CPU) بدقة float32 ما لم يُعرّف المستخدم خلاف ذلك. وهذا يضمن قابلية الاستخدام عبر منصات ومسرِّعات مختلفة، ويعني أنه لا تُطلب تركيبات معقدة لتشغيل المكتبة.
  • تسعى مكتبة Diffusers إلى أن تكون حزمة خفيفة، ولذلك فهي تعتمد على عدد قليل جداً من التبعيات الإلزامية، بينما تمتلك العديد من التبعيات الاختيارية التي يمكن أن تحسّن الأداء (مثل accelerate، safetensors، onnx، وغيرها…). ونسعى جاهدين إلى إبقاء المكتبة خفيفة الوزن قدر الإمكان بحيث يمكن إضافتها كتبعية للحزم الأخرى دون قلق كبير.
  • يفضّل Diffusers الكود البسيط الذي يفسّر نفسه بنفسه على الكود المُضغوط الذي يعتمد على حيل خفية. وهذا يعني أن صيغ الكود المختصرة مثل دوال lambda، والمُشغِّلات المتقدمة في PyTorch غالبًا ما لا تكون مرغوبة.

بسيط وسهل

كما يوضح PyTorch، الصراحة أفضل من الضمنية والبساطة أفضل من التعقيد. تنعكس هذه الفلسفة التصميمية في عدة أجزاء من المكتبة:

  • نتبع واجهة برمجة التطبيقات الخاصة بـ PyTorch من خلال طرق مثل DiffusionPipeline.to للسماح للمستخدم بإدارة الأجهزة.
  • يُفضَّل رفع رسائل خطأ موجزة بدلاً من تصحيح المدخلات الخاطئة بصمت. يهدف Diffusers إلى تعليم المستخدم، بدلاً من جعل المكتبة أسهل استخدامًا ما أمكن.
  • يتم كشف منطق النموذج المعقّد مقابل المجدول بدلاً من معالجته بشكل سحري في الداخل. تم فصل المجدول/المُعيّنات عن نماذج الانتشار مع اعتمادٍ ضئيل بينها. وهذا يفرض على المستخدم كتابة حلقة إزالة الضوضاء المفكوكة. ومع ذلك، يتيح هذا الفصل تسهيل عملية تصحيح الأخطاء ومنح المستخدم مزيداً من التحكم في تكييف عملية إزالة الضوضاء أو تبديل نماذج الانتشار أو المجدول.
  • المكوّنات المُدرَّبة بشكل منفصل في خط أنابيب الانتشار، مثل مُشفِّر النص، وشبكة unet، والمشفِّر التلقائي التبايني، لكلٍّ منها فئة نموذج خاصة به. وهذا يفرض على المستخدم التعامل مع التفاعل بين مكوّنات النموذج المختلفة، كما أن صيغة التسلسل تُفرّق مكوّنات النموذج في ملفات مختلفة. ومع ذلك، فإن هذا يتيح تسهيل عمليات التصحيح والتخصيص. تدريب DreamBooth أو Textual Inversion بسيط للغاية بفضل قدرة Diffusers على فصل مكوّنات فردية من خط أنابيب الانتشار.

تخصيص قابل للضبط، ميسّر للمساهمين فوق التجريد

في أجزاء كبيرة من المكتبة، تتبنى Diffusers مبدأً تصميمياً مهماً من مكتبة Transformers، وهو تفضيل نسخ ولصق الأكواد على التجريدات المتسرعة. هذا المبدأ التصميمي ذو رأي قوي ويتعارض بوضوح مع مبادئ التصميم الشائعة مثل عدم تكرار نفسك (DRY). باختصار، تماماً كما تفعل Transformers لملفات النمذجة، تفضل Diffusers الحفاظ على مستوى تجريد منخفض للغاية وأكواد ذاتية الاكتفاء إلى حد كبير للأنابيب (pipelines) والمجدولات (schedulers). يمكن نسخ الدوال، والكتل الطويلة من الأكواد، وحتى الفئات عبر ملفات متعددة، مما قد يبدو في البداية كخيار تصميمي سيئ وغير منظم يجعل المكتبة غير قابلة للصيانة. ومع ذلك، أثبت هذا التصميم نجاحه بشكل كبير في Transformers، وله معنى كبير للمكتبات مفتوحة المصدر للتعلم الآلي التي يقودها المجتمع لأن:

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

في Hugging Face، نطلق على هذا التصميم اسم سياسة الملف الواحد، مما يعني أن معظم كود فئة معينة يجب أن يُكتب في ملف واحد مكتفٍ ذاتياً. لقراءة المزيد عن هذه الفلسفة، يمكنك الاطلاع على هذا المنشور في المدونة.

في Diffusers، نتبع هذه الفلسفة فيما يتعلق بخطوط الأنابيب ومجدولات التدرج والنماذج على حد سواء. بعض النماذج الأقدم تسبق هذا الاتفاق وتُحفظ كما هي؛ بينما تعيش جميع معماريات النماذج الجديدة في ملفات مستقلة بذاتها. راجع قسم النماذج أدناه للتفاصيل.

رائع، الآن يجب أن تكون قد فهمت بشكل عام سبب تصميم 🧨 Diffusers بهذه الطريقة 🤗. نحاول تطبيق مبادئ التصميم هذه بشكل متسق عبر المكتبة. ومع ذلك، هناك بعض الاستثناءات البسيطة للفلسفة أو بعض اختيارات التصميم غير المحظوظة. إذا كان لديك ملاحظات حول التصميم، فسنكون سعداء ❤️ بالاستماع إليها مباشرة على GitHub.

فلسفة التصميم بالتفصيل

والآن لنغوص في التفاصيل الدقيقة لفلسفة التصميم. يمنحك Diffusers طريقتين لتكوين النماذج والمجدولين في سير عمل قابل للتشغيل: خطوط الأنابيب القياسية، وهي أحادية الكتلة بمهمة واحدة لكل فئة خط أنابيب، وModular Diffusers، وهو قابل للتكوين ومبني على الكتل. تغطي الأقسام أدناه خطوط الأنابيب، وخطوط الأنابيب المعيارية، والنماذج، والمجدولين على التوالي.

خطوط الأنابيب

تُصمَّم خطوط الأنابيب، سواء كانت قياسية أو معيارية، للاستدلال فقط. وهي مصممة لتكون سهلة الاستخدام (لذا فهي لا تتبع مبدأ البساطة على السهولة بنسبة 100%): فهي قابلة للقراءة، وتشرح نفسها بنفسها، ويسهل تعديلها، ويُفضَّل النظر إليها كمثال على كيفية استخدام النماذج والمجدولين. وهي لا تتمتع بكامل الميزات. لبناء واجهات مستخدم كاملة الميزات فوق Diffusers، استخدم Modular Diffusers.

تُتّبع مبادئ التصميم التالية:

  • تتبع خطوط الأنابيب سياسة الملف الواحد. يمكن العثور على جميع خطوط الأنابيب في مجلدات فردية تحت src/diffusers/pipelines. يتوافق مجلد خط أنابيب واحد مع ورقة/مشروع/إصدار واحد للتوليد الانتشاري. يمكن تجميع ملفات خطوط أنابيب متعددة في مجلد خط أنابيب واحد، كما هو الحال في src/diffusers/pipelines/stable-diffusion. إذا كانت خطوط الأنابيب تتشارك في وظائف مشابهة، يمكن الاستفادة من آلية # Copied from.
  • ترث جميع خطوط الأنابيب من DiffusionPipeline.
  • تتكون كل خط أنابيب من مكونات نموذج ومجدول مختلفة، موثقة في ملف model_index.json، ويمكن الوصول إليها كأسماء سمات لخط الأنابيب، ويمكن مشاركتها بين خطوط الأنابيب باستخدام دالة DiffusionPipeline.components.
  • يجب أن يكون كل خط أنابيب قابلًا للتحميل عبر الدالة DiffusionPipeline.from_pretrained.
  • يجب أن يكون لكل خط أنابيب طريقة واحدة فقط لتشغيله عبر طريقة __call__. كما ينبغي أن تكون تسمية معاملات __call__ متسقة عبر جميع خطوط الأنابيب.
  • يجب تسمية خطوط الأنابيب (Pipelines) وفقاً للمهمة التي صُممت لحلها.

المولّدات التوليدية المعيارية

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

تُتّبع مبادئ التصميم التالية:

  • تتبع خطوط الأنابيب المعيارية سياسة الملف الواحد. يوجد كل خط أنابيب في مجلد خاص به تحت src/diffusers/modular_pipelines/، ويقسم المجلد سير العمل إلى ملف واحد لكل مرحلة: encoders.py، before_denoise.py، denoise.py، وdecoders.py. تكمل ملفان إضافيان خط الأنابيب. يجمع modular_blocks_<model>.py المراحل معًا، ويحدد modular_pipeline.py فئة فرعية من ModularPipeline لكل نموذج. لا تستورد خطوط الأنابيب المعيارية بعضها بعضًا.
  • يُعرَّف كل خط أنابيب معياري على أنه مجموعة من ModularPipelineBlocks. توجد الكتل الورقية في ملفات المراحل (encoders.py، before_denoise.py، denoise.py، decoders.py)، بينما يجمع modular_blocks_<model>.py بينها لتكوين سير عمل كامل باستخدام فئات الحاوية مثل SequentialPipelineBlocks وAutoPipelineBlocks. وهذا يفصل بين مفهومين يدمجهما DiffusionPipeline combines. الكتلة هي تعريف خالص؛ فهي تُلزم المدخلات والمخرجات والتبعيات المكوّنة، لكنها لا تحتفظ بالأوزان ولا يمكن تشغيلها. أما ModularPipeline، الذي يُنشأ عبر .init_pipeline(repo_id)، فهو المقابل القابل للتشغيل. إن إبقاء الكتل بلا حالة وبلا أوزان هو ما يجعلها قابلة للتركيب بحرية، وقابلة للاستبدال، وقابلة للمشاركة عبر سير العمل المختلفة.
  • لدعم مهمة جديدة، اكتب الكتل الخاصة بالمهمة، وركّبها مع الكتل الموجودة، وسجّل سير العمل في _workflow_map على مستوى تجميع الكتل العلوي. يمكن لنسخة واحدة من ModularPipeline أن تدعم العديد من سلاسل العمل، مثل النص إلى صورة، والصورة إلى صورة، والتعبئة (inpainting)، بينما يعمل DiffusionPipeline على سلسلة عمل واحدة فقط.

راجع توثيق Modular Diffusers للحصول على دليل التصميم والاستخدام الكامل.

النماذج

تُصمَّم النماذج على أنها صناديق أدوات قابلة للتهيئة، وهي امتدادات طبيعية لفئة Module في PyTorch. ينبغي أن تتبع سياسة الملف الواحد. بعض النماذج الأقدم تسبق هذه الاتفاقية وقد أُبقي عليها كما هي. تعامل معها كاستثناءات قديمة، لا كنماذج يُحتذى بها عند إنشاء نماذج جديدة. على سبيل المثال، استُخدمت فئة UNet2DConditionModel الأصلية لعدة متغيرات من UNet.

تُتّبع مبادئ التصميم التالية:

  • توجد كل بنية نموذج في مجلد خاص بها تحت src/diffusers/models، على سبيل المثال transformers/ أو autoencoders/ أو unets/. ولكل عائلة نماذج ملف خاص بها داخل ذلك المجلد، مثل transformer_flux.py وtransformer_wan.py.
  • تتبع النماذج سياسة الملف الواحد. يجب أن يكون كل ملف نموذج مكتفياً ذاتياً، باستثناء عدد قليل من الوحدات القياسية التي تستخدمها جميع النماذج بشكل متطابق، مثل تضمينات خطوات الزمن وطبقات التطبيع. استورد تلك من embeddings.py و normalization.py.
  • تهدف النماذج إلى كشف التعقيد، تمامًا كما تفعل فئة Module في PyTorch، وتقديم رسائل خطأ واضحة.
  • تورث جميع النماذج من ModelMixin وConfigMixin.
  • يمكن تحسين النماذج من حيث الأداء عندما لا يتطلب ذلك تغييرات كبيرة في الكود، ويحافظ على التوافق مع الإصدارات السابقة، ويحقق مكاسب كبيرة في الذاكرة أو القدرة الحاسوبية.
  • يجب أن تكون النماذج افتراضيًا بأعلى دقة وأدنى إعداد للأداء.
  • لدمج بنية نموذج جديدة تشبه بنية موجودة مسبقًا، انسخ الملف الموجود كنقطة انطلاق ثم عدّله. استخدم تعليقات # Copied from على الطبقات التي تبقى متطابقة حتى يحافظ make fix-copies على مزامنتها.

المجدولون

تتولى مُجدولات المهام (Schedulers) مسؤولية توجيه عملية إزالة الضوضاء أثناء الاستدلال، وكذلك تحديد جدول الضوضاء للتدريب. وقد صُممت كصنفات مستقلة مع ملفات إعداد قابلة للتحميل، وتلتزم بشكل صارم بـسياسة الملف الواحد.

تُتّبع مبادئ التصميم التالية:

  • تُوجد جميع المجدولات في src/diffusers/schedulers.
  • لا يُسمح لـSchedulers بـاستيراد من ملفات الأدوات الكبيرة، ويجب أن تبقى مكتفيةً ذاتياً إلى حد كبير.
  • يتوافق ملف بايثون واحد للمجدول مع خوارزمية مجدولة واحدة (كما قد تُعرَّف في ورقة بحثية).
  • إذا كانت المجدولات (Schedulers) تتشارك في وظائف متشابهة، يمكننا الاستفادة من آلية # Copied from.
  • ترث جميع المجدولات من SchedulerMixin وConfigMixin.
  • يمكن استبدال المجدولات بسهولة باستخدام طريقة ConfigMixin.from_config كما هو موضح بالتفصيل هنا.
  • يجب أن يحتوي كل مُجدول على set_num_inference_steps، ودالة step. يجب استدعاء set_num_inference_steps(...) قبل كل عملية إزالة الضوضاء، أي قبل استدعاء step(...).
  • تُعرِض كل وحدة جدولة خطوات الزمن التي يجب «التكرار عليها» عبر خاصية timesteps، وهي مصفوفة من خطوات الزمن التي سيُطلب من النموذج استدعاؤها.
  • تستقبل الدالة step(...) مخرجات النموذج المتوقعة والعينة “الحالية” (x_t) وتعيد العينة “السابقة” الأكثر إزالةً للضوضاء قليلاً (x_t-1).
  • نظرًا لتعقيد مجدولات الانتشار، لا تُظهر دالة step كل هذا التعقيد، وقد تبدو إلى حد ما “صندوقًا أسود”.
  • في جميع الحالات تقريبًا، يجب تنفيذ المجدولات الجديدة في ملف جدولة جديد.
Update on GitHub