Diffusers documentation
Custom Diffusion
Custom Diffusion
Custom Diffusion هي تقنية تدريب لتخصيص نماذج توليد الصور. وكما هو الحال مع Textual Inversion وDreamBooth وLoRA، لا تتطلب Custom Diffusion سوى عدد قليل (~4-5) من الصور الممثّلة. تعمل هذه التقنية من خلال تدريب الأوزان في طبقات الانتباه المتقاطع (cross-attention) فقط، وتستخدم كلمة خاصة لتمثيل المفهوم الجديد المُتعلَّم. وتتميّز Custom Diffusion بقدرتها على تعلّم عدة مفاهيم في الوقت نفسه.
إذا كنت تدرب على وحدة معالجة رسومية (GPU) ذاكرتها المخصصة (vRAM) محدودة، فيجب عليك محاولة تفعيل xFormers باستخدام --enable_xformers_memory_efficient_attention للحصول على تدريب أسرع مع متطلبات أقل لـ vRAM (16 جيجابايت). لحفظ المزيد من الذاكرة، أضف --set_grads_to_none في حجة التدريب لتعيين التدرجات إلى None بدلاً من الصفر (قد يسبب هذا الخيار بعض المشكلات، لذا إذا واجهت أي منها، حاول إزالة هذا المعامل).
ستستكشف هذه الدليل سكربت train_custom_diffusion.py لمساعدتك على الاطلاع عليه بشكل أعمق، وكيفية تكييفه ليناسب حالتك الخاصة.
قبل تشغيل السكربت، تأكد من تثبيت المكتبة من المصدر:
git clone https://github.com/huggingface/diffusers
cd diffusers
pip install .انتقل إلى مجلد المثال الذي يحتوي على سكربت التدريب وقم بتثبيت الاعتماديات المطلوبة:
cd examples/custom_diffusion
pip install -r requirements.txt
pip install clip-retrieval🤗 Accelerate هي مكتبة تساعدك على التدريب على عدة وحدات معالجة رسومية (GPU) أو وحدات معالجة مخصصة (TPU) أو باستخدام دقة مختلطة. ستقوم تلقائيًا بإعداد بيئة التدريب الخاصة بك بناءً على عتادك وبيئتك. اطّلع على جولة سريعة في 🤗 Accelerate لمعرفة المزيد.
قم بتهيئة بيئة 🤗 Accelerate:
accelerate config
لإعداد بيئة 🤗 Accelerate افتراضية دون اختيار أي تكوينات:
accelerate config default
أو إذا لم يدعم بيئتك shell تفاعليًا، كما هو الحال في notebook، يمكنك استخدام:
from accelerate.utils import write_basic_config
write_basic_config()أخيرًا، إذا كنت ترغب في تدريب نموذج على مجموعة بياناتك الخاصة، فاطّلع على دليل إنشاء مجموعة بيانات للتدريب لمعرفة كيفية إنشاء مجموعة بيانات تعمل مع سكربت التدريب.
تسلّط الأقسام التالية الضوء على أجزاء من سكربت التدريب التي تُعدّ مهمة لفهم كيفية تعديله، لكنها لا تغطي كل جانب من جوانب السكربت بالتفصيل. إذا كنت مهتمًا بالتعلّم أكثر، فلا تتردد في الاطلاع على السكربت وإعلامنا بأي أسئلة أو مخاوف لديك.
معاملات السكربت
تحتوي سكربت التدريب على جميع المعاملات لمساعدتك على تخصيص عملية التدريب الخاصة بك. وتُوجد هذه المعاملات في الدالة parse_args(). تأتي الدالة بقيم افتراضية، لكن يمكنك أيضًا تعيين قيمك الخاصة في أمر التدريب إذا رغبت في ذلك.
على سبيل المثال، لتغيير دقة الصورة المدخلة:
accelerate launch train_custom_diffusion.py \ --resolution=256
يُوصف العديد من المعلمات الأساسية في دليل تدريب DreamBooth، لذا يركّز هذا الدليل على المعلمات الفريدة لـ Custom Diffusion:
--freeze_model: يجمّد معاملات المفتاح والقيمة في طبقة الانتباه المتقاطع؛ القيمة الافتراضية هيcrossattn_kv، لكن يمكنك ضبطها علىcrossattnلتدريب جميع المعاملات في طبقة الانتباه المتقاطع--concepts_list: لتعلم عدة مفاهيم، قم بتوفير مسار إلى ملف JSON يحتوي على المفاهيم--modifier_token: كلمة خاصة تُستخدم لتمثيل المفهوم المُتعلَّم--initializer_token: كلمة خاصة تُستخدم لتبطينmodifier_token
خسارة الحفاظ على المسبق
خسارة الحفاظ على المسبق هي طريقة تستخدم العينات التي يولدها النموذج نفسه لمساعدته على تعلّم كيفية توليد صور أكثر تنوعًا. وبما أن صور العينات المولّدة تنتمي إلى نفس الفئة التي تنتمي إليها الصور التي قدمتها، فإنها تساعد النموذج على الاحتفاظ بما تعلّمه عن الفئة وكيفية استخدام ما يعرفه مسبقًا عنها لإنشاء تركيبات جديدة.
يُوصف العديد من المعلمات الخاصة بخسارة الحفاظ على المسبق في دليل تدريب DreamBooth.
التنظيم
يتضمن التخصيص الانتشاري تدريب الصور المستهدفة باستخدام مجموعة صغيرة من الصور الحقيقية لمنع الإفراط في التكيّف. وكما يمكنك أن تتخيل، يمكن أن يكون هذا الأمر سهلاً عندما تكون تتدرب على عدد قليل من الصور فقط! حمّل 200 صورة حقيقية باستخدام clip_retrieval. يجب أن يكون class_prompt في نفس الفئة التي تنتمي إليها الصور المستهدفة. تُخزَّن هذه الصور في class_data_dir.
python retrieve.py --class_prompt cat --class_data_dir real_reg/samples_cat --num_class_images 200لتفعيل التنظيم، أضف المعاملات التالية:
--with_prior_preservation: ما إذا كان سيتم استخدام خسارة الحفاظ على المسبق--prior_loss_weight: يتحكم في تأثير خسارة الحفاظ على المسبق على النموذج--real_prior: ما إذا كان سيتم استخدام مجموعة صغيرة من الصور الحقيقية لمنع الإفراط في التخصيص
accelerate launch train_custom_diffusion.py \
--with_prior_preservation \
--prior_loss_weight=1.0 \
--class_data_dir="./real_reg/samples_cat" \
--class_prompt="cat" \
--real_prior=True \سكربت التدريب
يُشبه جزء كبير من الكود في سكربت تدريب Custom Diffusion سكربت DreamBooth. يركّز هذا الدليل بدلاً من ذلك على الكود ذي الصلة بـ Custom Diffusion.
يحتوي سكربت تدريب Custom Diffusion على صفحتي بيانات:
CustomDiffusionDataset: يعالج الصور المسبقة، وصور الفئات، والأوامر النصية للتدريبPromptDataset: يجهّز الأوامر التوجيهية لتوليد صور الفئات
في الخطوة التالية، يُضاف modifier_token إلى المُرمِّز، ثم يُحوَّل إلى معرِّفات رموز، وتُعاد ضبط أحجام تضمينات الرموز لاستيعاب modifier_token الجديد. بعد ذلك، تُهيَّأ تضمينات modifier_token باستخدام تضمينات initializer_token. وتُجمَّد جميع المعاملات في مُرمِّز النص، باستثناء تضمينات الرموز، لأن هذا هو ما يحاول النموذج تعلُّم ربطه بالمفاهيم.
params_to_freeze = itertools.chain(
text_encoder.text_model.encoder.parameters(),
text_encoder.text_model.final_layer_norm.parameters(),
text_encoder.text_model.embeddings.position_embedding.parameters(),
)
freeze_params(params_to_freeze)الآن ستحتاج إلى إضافة Custom Diffusion weights إلى طبقات الانتباه. هذه خطوة بالغة الأهمية للحصول على الشكل والحجم الصحيحين لأوزان الانتباه، ولضبط العدد المناسب لمعالجات الانتباه في كل كتلة من UNet.
st = unet.state_dict()
for name, _ in unet.attn_processors.items():
cross_attention_dim = None if name.endswith("attn1.processor") else unet.config.cross_attention_dim
if name.startswith("mid_block"):
hidden_size = unet.config.block_out_channels[-1]
elif name.startswith("up_blocks"):
block_id = int(name[len("up_blocks.")])
hidden_size = list(reversed(unet.config.block_out_channels))[block_id]
elif name.startswith("down_blocks"):
block_id = int(name[len("down_blocks.")])
hidden_size = unet.config.block_out_channels[block_id]
layer_name = name.split(".processor")[0]
weights = {
"to_k_custom_diffusion.weight": st[layer_name + ".to_k.weight"],
"to_v_custom_diffusion.weight": st[layer_name + ".to_v.weight"],
}
if train_q_out:
weights["to_q_custom_diffusion.weight"] = st[layer_name + ".to_q.weight"]
weights["to_out_custom_diffusion.0.weight"] = st[layer_name + ".to_out.0.weight"]
weights["to_out_custom_diffusion.0.bias"] = st[layer_name + ".to_out.0.bias"]
if cross_attention_dim is not None:
custom_diffusion_attn_procs[name] = attention_class(
train_kv=train_kv,
train_q_out=train_q_out,
hidden_size=hidden_size,
cross_attention_dim=cross_attention_dim,
).to(unet.device)
custom_diffusion_attn_procs[name].load_state_dict(weights)
else:
custom_diffusion_attn_procs[name] = attention_class(
train_kv=False,
train_q_out=False,
hidden_size=hidden_size,
cross_attention_dim=cross_attention_dim,
)
del st
unet.set_attn_processor(custom_diffusion_attn_procs)
custom_diffusion_layers = AttnProcsLayers(unet.attn_processors)يتم تهيئة optimizer لتحديث معاملات طبقة الانتباه المتقاطع:
optimizer = optimizer_class(
itertools.chain(text_encoder.get_input_embeddings().parameters(), custom_diffusion_layers.parameters())
if args.modifier_token is not None
else custom_diffusion_layers.parameters(),
lr=args.learning_rate,
betas=(args.adam_beta1, args.adam_beta2),
weight_decay=args.adam_weight_decay,
eps=args.adam_epsilon,
)في حلقة التدريب، من المهم تحديث التضمينات (embeddings) للمفهوم الذي تحاول تعلمه فقط. وهذا يعني تعيين تدرجات تضمينات الرموز (tokens) الأخرى جميعها إلى الصفر:
if args.modifier_token is not None:
if accelerator.num_processes > 1:
grads_text_encoder = text_encoder.module.get_input_embeddings().weight.grad
else:
grads_text_encoder = text_encoder.get_input_embeddings().weight.grad
index_grads_to_zero = torch.arange(len(tokenizer)) != modifier_token_id[0]
for i in range(len(modifier_token_id[1:])):
index_grads_to_zero = index_grads_to_zero & (
torch.arange(len(tokenizer)) != modifier_token_id[i]
)
grads_text_encoder.data[index_grads_to_zero, :] = grads_text_encoder.data[
index_grads_to_zero, :
].fill_(0)تشغيل السكربت
بمجرد أن تُجري جميع تعديلاتك أو تكون راضياً عن الإعداد الافتراضي، تكون مستعداً لإطلاق سكربت التدريب! 🚀
في هذا الدليل، ستقوم بتنزيل واستخدام هذه صور القطط كمثال. يمكنك أيضًا إنشاء واستخدام مجموعة بياناتك الخاصة إذا أردت (راجع دليل إنشاء مجموعة بيانات للتدريب).
اضبط متغير البيئة MODEL_NAME على معرّف نموذج في Hub أو مسار لنموذج محلي، وINSTANCE_DIR على المسار الذي حمّلت إليه صور القطط للتو، وOUTPUT_DIR على المكان الذي تريد حفظ النموذج فيه. ستستخدم <new1> ككلمة خاصة لربط التضمينات الجديدة المكتسبة. ينشئ السكربت نقاط فحص للنموذج ويحفظها مع ملف pytorch_custom_diffusion_weights.bin في مستودعك.
لمراقبة تقدم التدريب باستخدام Weights and Biases، أضف معامل --report_to=wandb إلى أمر التدريب وحدد موجه تحقق باستخدام --validation_prompt. وهذا مفيد لتصحيح الأخطاء وحفظ النتائج الوسيطة.
إذا كنتَ تُدرّب على وجوه بشرية، فقد وجد فريق Custom Diffusion أن المعايير التالية تعمل بشكل جيد:
--learning_rate=5e-6- يمكن أن يكون
--max_train_stepsفي أي مكان بين 1000 و2000--freeze_model=crossattn- استخدم ما لا يقل عن 15-20 صورة للتدريب
export MODEL_NAME="CompVis/stable-diffusion-v1-4"
export OUTPUT_DIR="path-to-save-model"
export INSTANCE_DIR="./data/cat"
accelerate launch train_custom_diffusion.py \
--pretrained_model_name_or_path=$MODEL_NAME \
--instance_data_dir=$INSTANCE_DIR \
--output_dir=$OUTPUT_DIR \
--class_data_dir=./real_reg/samples_cat/ \
--with_prior_preservation \
--real_prior \
--prior_loss_weight=1.0 \
--class_prompt="cat" \
--num_class_images=200 \
--instance_prompt="photo of a <new1> cat" \
--resolution=512 \
--train_batch_size=2 \
--learning_rate=1e-5 \
--lr_warmup_steps=0 \
--max_train_steps=250 \
--scale_lr \
--hflip \
--modifier_token "<new1>" \
--validation_prompt="<new1> cat sitting in a bucket" \
--report_to="wandb" \
--push_to_hubيمكن لـ Custom Diffusion أيضًا تعلُّم مفاهيم متعددة إذا قمت بتوفير ملف JSON يحتوي على بعض التفاصيل حول كل مفهوم يجب أن يتعلمه.
شغّل clip-retrieval لجمع بعض الصور الحقيقية لاستخدامها في التنظيم:
pip install clip-retrieval
python retrieve.py --class_prompt {} --class_data_dir {} --num_class_images 200ثم يمكنك تشغيل السكربت:
export MODEL_NAME="CompVis/stable-diffusion-v1-4"
export OUTPUT_DIR="path-to-save-model"
accelerate launch train_custom_diffusion.py \
--pretrained_model_name_or_path=$MODEL_NAME \
--output_dir=$OUTPUT_DIR \
--concepts_list=./concept_list.json \
--with_prior_preservation \
--real_prior \
--prior_loss_weight=1.0 \
--resolution=512 \
--train_batch_size=2 \
--learning_rate=1e-5 \
--lr_warmup_steps=0 \
--max_train_steps=500 \
--num_class_images=200 \
--scale_lr \
--hflip \
--modifier_token "<new1>+<new2>" \
--push_to_hubبمجرد اكتمال التدريب، يمكنك استخدام نموذج Custom Diffusion الجديد لديك للاستدلال.
import torch
from diffusers import DiffusionPipeline
pipeline = DiffusionPipeline.from_pretrained(
"CompVis/stable-diffusion-v1-4", dtype=torch.float16,
).to("cuda") # or "mps", "xpu", "cpu"
pipeline.unet.load_attn_procs("path-to-save-model", weight_name="pytorch_custom_diffusion_weights.bin")
pipeline.load_textual_inversion("path-to-save-model", weight_name="<new1>.bin")
image = pipeline(
"<new1> cat sitting in a bucket",
num_inference_steps=100,
guidance_scale=6.0,
eta=1.0,
).images[0]
image.save("cat.png")import torch
from huggingface_hub.repocard import RepoCard
from diffusers import DiffusionPipeline
pipeline = DiffusionPipeline.from_pretrained(
"CompVis/stable-diffusion-v1-4", dtype=torch.float16,
).to("cuda") # or "mps", "xpu", "cpu"
model_id = "sayakpaul/custom-diffusion-cat-wooden-pot"
pipeline.unet.load_attn_procs(model_id, weight_name="pytorch_custom_diffusion_weights.bin")
pipeline.load_textual_inversion(model_id, weight_name="<new1>.bin")
pipeline.load_textual_inversion(model_id, weight_name="<new2>.bin")
image = pipeline(
"the <new1> cat sculpture in the style of a <new2> wooden pot",
num_inference_steps=100,
guidance_scale=6.0,
eta=1.0,
).images[0]
image.save("multi-subject.png")الخطوات التالية
تهانينا على تدريب نموذج باستخدام Custom Diffusion! 🎉 للتعرف على المزيد:
- Read the Multi-Concept Customization of Text-to-Image Diffusion blog post to learn more details about the experimental results from the Custom Diffusion team.