# Özel Difüzyon

[Custom Diffusion](https://huggingface.co/papers/2212.04488), görüntü üretim modellerini kişiselleştirmek için kullanılan bir eğitim tekniğidir. Textual Inversion, DreamBooth ve LoRA gibi Custom Diffusion da yalnızca birkaç (~4-5) örnek görüntü gerektirir. Bu teknik, yalnızca cross-attention katmanlarındaki ağırlıkları eğiterek çalışır ve yeni öğrenilen kavramı temsil etmek için özel bir kelime kullanır. Custom Diffusion'ın benzersiz yanı, aynı anda birden fazla kavramı da öğrenebilmesidir.

Sınırlı vRAM'a sahip bir GPU üzerinde eğitim yapıyorsanız, daha düşük vRAM gereksinimi (16GB) ile daha hızlı eğitim için xFormers'ı `--enable_xformers_memory_efficient_attention` ile etkinleştirmeyi denemelisiniz. Daha fazla bellek tasarrufu sağlamak için, eğitimin argümanlarına `--set_grads_to_none` ekleyerek gradyanları sıfır yerine `None` olarak ayarlayın (bu seçenek bazı sorunlara neden olabilir, bu nedenle herhangi bir sorun yaşarsanız bu parametreyi kaldırmayı deneyin).

Bu kılavuz, [train_custom_diffusion.py](https://github.com/huggingface/diffusers/blob/main/examples/custom_diffusion/train_custom_diffusion.py) betiğini inceleyerek onu daha yakından tanımanıza ve kendi kullanım senaryonuza nasıl uyarlayabileceğinizi gösterir.

Betik çalıştırmadan önce, kütüphanenin kaynak kodundan yüklendiğinden emin olun:

```bash
git clone https://github.com/huggingface/diffusers
cd diffusers
pip install .
```

Eğitim betiği bulunan örnek klasörüne gidin ve gerekli bağımlılıkları yükleyin:

```bash
cd examples/custom_diffusion
pip install -r requirements.txt
pip install clip-retrieval
```

> [!TIP]
> 🤗 Accelerate, birden fazla GPU/TPU ile veya karma hassasiyetle eğitim yapmanıza yardımcı olmak için tasarlanmış bir kütüphanedir. Donanımınıza ve ortamınıza göre eğitim kurulumunuzu otomatik olarak yapılandırır. Daha fazla bilgi edinmek için 🤗 Accelerate [Hızlı tur](https://huggingface.co/docs/accelerate/quicktour) sayfasına göz atın.

Bir 🤗 Accelerate ortamı başlatın:

```bash
accelerate config
```

Herhangi bir yapılandırma seçmeden varsayılan bir 🤗 Accelerate ortamı kurmak için:

```bash
accelerate config default
```

Ya da ortamınız, bir notebook gibi, etkileşimli bir kabuğu desteklemiyorsa, şunu kullanabilirsiniz:

```py
from accelerate.utils import write_basic_config

write_basic_config()
```

Son olarak, kendi veri setiniz üzerinde bir model eğitmek istiyorsanız, eğitim scriptiyle uyumlu bir veri seti oluşturma yöntemini öğrenmek için [Eğitim için veri seti oluşturma](create_dataset) kılavuzuna göz atın.

> [!TIP]
> Aşağıdaki bölümler, betiğin nasıl değiştirileceğini anlamak için önemli olan eğitim betiğinin kısımlarını vurgular, ancak betiğin her yönünü ayrıntılı olarak kapsamaz. Daha fazla bilgi edinmek isterseniz, [betiği](https://github.com/huggingface/diffusers/blob/main/examples/custom_diffusion/train_custom_diffusion.py) okumaktan çekinmeyin ve herhangi bir sorunuz veya endişeniz varsa bize bildirin.

## Betik parametreleri

Eğitim betiği, eğitim çalışmanızı özelleştirmenize yardımcı olmak için tüm parametreleri içerir. Bunlar [`parse_args()`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/custom_diffusion/train_custom_diffusion.py#L319) fonksiyonunda bulunur. Fonksiyon varsayılan değerlerle birlikte gelir, ancak isterseniz kendi değerlerinizi eğitim komutunda da ayarlayabilirsiniz.

Örneğin, giriş görüntüsünün çözünürlüğünü değiştirmek için:

```bash
accelerate launch train_custom_diffusion.py \
  --resolution=256
```

Temel parametrelerin çoğu [DreamBooth](dreambooth#script-parameters) eğitim kılavuzunda anlatıldığından, bu kılavuz Custom Diffusion'a özgü parametrelere odaklanmaktadır:

- `--freeze_model`: çapraz dikkat katmanındaki anahtar ve değer parametrelerini dondurur; varsayılan değer `crossattn_kv`'dir ancak çapraz dikkat katmanındaki tüm parametreleri eğitmek için `crossattn` olarak ayarlayabilirsiniz
- `--concepts_list`: birden fazla kavram öğrenmek için, kavramları içeren bir JSON dosyasının yolunu belirtin
- `--modifier_token`: öğrenilen kavramı temsil etmek için kullanılan özel bir kelime
- `--initializer_token`: `modifier_token` gömmelemelerini başlatmak için kullanılan özel bir kelime

### Önceden var olan bilgi kaybı

Öncül koruma kaybı, bir modelin kendi ürettiği örnekleri kullanarak daha çeşitli görseller üretmeyi öğrenmesine yardımcı olan bir yöntemdir. Bu üretilmiş örnek görsellerler, sağladığınız görsellerle aynı sınıfa ait olduğu için, modelin sınıfa dair öğrendiklerini korumasına ve sınıfa zaten bildiklerini kullanarak yeni kompozisyonlar oluşturmasına yardımcı olurlar.

Önceki koruma kaybı için parametrelerin çoğu [DreamBooth](dreambooth#prior-preservation-loss) eğitim kılavuzunda açıklanmıştır.

### Düzenleme

Custom Diffusion, aşırı öğrenmeyi önlemek için hedef görselleri küçük bir gerçek görsel setiyle eğitir. Sadece birkaç görselle eğitim yaptığınızı düşündüğünüzde bunun ne kadar kolay yapılabileceğini hayal edebilirsiniz. `clip_retrieval` ile 200 gerçek görsel indirin. `class_prompt`, hedef görsellerle aynı kategori olmalıdır. Bu görseller `class_data_dir` içinde saklanır.

```bash
python retrieve.py --class_prompt cat --class_data_dir real_reg/samples_cat --num_class_images 200
```

Düzenlemeyi etkinleştirmek için aşağıdaki parametreleri ekleyin:

- `--with_prior_preservation`: prior preservation loss kullanılıp kullanılmayacağı
- `--prior_loss_weight`: model üzerindeki öncül koruma kaybının etkisini kontrol eder
- `--real_prior`: aşırı öğrenmeyi önlemek için küçük bir gerçek görsel kümesi kullanılıp kullanılmayacağı

```bash
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 \
```

## Eğitim betiği

> [!TIP]
> Custom Diffusion eğitim betiğindeki kodun büyük bir kısmı [DreamBooth](dreambooth#training-script) betiğine benzer. Bu kılavuz bunun yerine Custom Diffusion ile ilgili koda odaklanır.

Custom Diffusion eğitim betiğinin iki veri seti sınıfı vardır:

- [`CustomDiffusionDataset`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/custom_diffusion/train_custom_diffusion.py#L165): eğitim için görüntüleri, sınıf görüntülerini ve istemleri ön işler
- [`PromptDataset`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/custom_diffusion/train_custom_diffusion.py#L148): sınıf görselleri üretmek için istemleri hazırlar

Ardından, `modifier_token` [tokenizatora eklenir](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/custom_diffusion/train_custom_diffusion.py#L811), token kimliklerine dönüştürülür ve yeni `modifier_token` için token gömme boyutları yeniden ayarlanır. Daha sonra `modifier_token` gömmeleri, `initializer_token` gömmeleriyle başlatılır. Metin kodlayıcıdaki tüm parametreler, modelin kavramlarla ilişkilendirmeyi öğrenmeye çalıştığı şey olan token gömmeleri hariç olmak üzere dondurulur.

```py
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)
```

Şimdi dikkat katmanlarına [Custom Diffusion ağırlıklarını](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/custom_diffusion/train_custom_diffusion.py#L911C3-L911C3) eklemeniz gerekecek. Dikkat ağırlıklarının şeklinin ve boyutunun doğru olması ve her UNet bloğunda uygun sayıda dikkat işleyicisinin ayarlanması için bu gerçekten önemli bir adımdır.

```py
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](https://github.com/huggingface/diffusers/blob/84cd9e8d01adb47f046b1ee449fc76a0c32dc4e2/examples/custom_diffusion/train_custom_diffusion.py#L982), çapraz dikkat katmanı parametrelerini güncellemek üzere başlatılır:

```py
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,
)
```

[eğitim döngüsünde](https://github.com/huggingface/diffusers/blob/84cd9e8d01adb47f046b1ee449fc76a0c32dc4e2/examples/custom_diffusion/train_custom_diffusion.py#L1048), öğrenmeye çalıştığınız kavram için yalnızca gömme değerlerini güncellemek önemlidir. Bu, diğer tüm token gömme değerlerinin gradyanlarını sıfıra ayarlamak anlamına gelir:

```py
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)
```

## Betik başlat

Tüm değişikliklerinizi yaptıysanız veya varsayılan yapılandırmayla sorununuz yoksa, eğitim betiğini başlatmaya hazırsınız! 🚀

Bu kılavuzda, bu örnek [kedi görsellerini](https://www.cs.cmu.edu/~custom-diffusion/assets/data.zip) indirip kullanacaksınız. İsterseniz kendi veri setinizi oluşturup kullanabilirsiniz ([Eğitim için veri seti oluşturma](create_dataset) kılavuzuna bakın).

Ortam değişkenini `MODEL_NAME` olarak Hub'daki bir model kimliğine veya yerel bir modele giden yola, `INSTANCE_DIR` olarak az önce kedi görsellerini indirdiğiniz yola ve `OUTPUT_DIR` olarak modeli kaydetmek istediğiniz yola ayarlayın. Yeni öğrenilen gömme (embedding)leri bağlamak için özel kelime olarak `<new1>` kullanacaksınız. Betik, model denetim noktalarını ve pytorch_custom_diffusion_weights.bin dosyasını oluşturup deponuza kaydeder.

Eğitim ilerlemesini Weights and Biases ile izlemek için eğitim komutuna `--report_to=wandb` parametresini ekleyin ve `--validation_prompt` ile bir doğrulama istemci belirleyin. Bu, hata ayıklama ve ara sonuçları kaydetmek için kullanışlıdır.

> [!TIP]
> İnsan yüzleri üzerinde eğitim yapıyorsanız, Custom Diffusion ekibi aşağıdaki parametrelerin iyi çalıştığını bulmuştur:
>
> - `--learning_rate=5e-6` - `--max_train_steps` 1000 ile 2000 arasında herhangi bir değer olabilir - `--freeze_model=crossattn` - eğitim için en az 15-20 görsel kullanın

```bash
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, öğrenmesi gereken her kavramla ilgili bazı ayrıntıları içeren bir [JSON](https://github.com/adobe-research/custom-diffusion/blob/main/assets/concept_list.json) dosyası sağlarsanız birden fazla kavramı da öğrenebilir.

Düzenleme için kullanılacak bazı gerçek görüntüleri toplamak için clip-retrieval'i çalıştırın:

```bash
pip install clip-retrieval
python retrieve.py --class_prompt {} --class_data_dir {} --num_class_images 200
```

Ardından betiği başlatabilirsiniz:

```bash
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
```

Eğitim tamamlandıktan sonra, yeni Custom Diffusion modelinizi çıkarım için kullanabilirsiniz.

```py
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")
```

```py
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")
```

## Sonraki adımlar

Custom Diffusion ile bir model eğittiğiniz için tebrikler! 🎉 Daha fazla bilgi edinmek için:

- Custom Diffusion ekibinin deneysel sonuçlarına ilişkin daha fazla ayrıntı için [Multi-Concept Customization of Text-to-Image Diffusion](https://www.cs.cmu.edu/~custom-diffusion/) blog yazısını okuyun.

