LoRA ile Belirli Bir Stili Stable Diffusion’a Öğretme

Stable Diffusion ile çalışırken bir noktada fark ediyorsunuz: genel modeller harika sonuçlar üretiyor ama siz özel bir şey istiyorsunuz. Belki şirketinizin marka kimliğine uygun illüstrasyonlar, belki belirli bir sanatçının tarzı, belki de tamamen özgün bir görsel dil. İşte tam burada LoRA devreye giriyor. LoRA (Low-Rank Adaptation), base modeli bozmadan üzerine ince bir adaptasyon katmanı eklemenizi sağlayan, hem hafif hem de güçlü bir fine-tuning yöntemi. Bu yazıda sıfırdan bir LoRA modeli eğitmeyi, doğru veri setini hazırlamayı ve sonuçları production ortamında kullanmayı ele alacağız.

LoRA Nedir ve Neden Bu Kadar Popüler

Klasik fine-tuning yöntemlerinde tüm model ağırlıklarını güncellersiniz. Bu işlem hem hesaplama açısından pahalı hem de riskli. Yanlış ayarlarla base modeli kalıcı olarak bozabilirsiniz. LoRA ise farklı çalışıyor: orijinal ağırlıkları dondurarak sadece düşük boyutlu adaptasyon matrislerini eğitiyor.

Pratik anlamda ne demek bu? 4GB VRAM’li bir ekran kartıyla bile makul sonuçlar alabiliyorsunuz. Eğitim süresi saatlerden dakikalara iniyor. Ve en önemlisi, oluşturduğunuz LoRA dosyası genellikle 50-200MB arasında oluyor, tüm modeli değil.

Sysadmin perspektifinden bakıldığında da mükemmel: LoRA dosyalarını version control’de tutabilir, farklı projelere kolayca dağıtabilir, hatta birden fazla LoRA’yı aynı anda kullanabilirsiniz.

Ortam Hazırlığı

Donanım Gereksinimleri

Gerçekçi olalım. LoRA eğitimi için minimum gereksinimler şöyle:

  • GPU: En az 6GB VRAM (8GB ve üzeri önerilir)
  • RAM: 16GB minimum, 32GB ideal
  • Disk: Eğitim veri seti ve checkpoint’ler için 50GB boş alan
  • İşletim Sistemi: Ubuntu 22.04 LTS veya Windows 11 (WSL2 üzerinde de çalışır)

Ben bu yazıda Ubuntu 22.04 üzerinde çalışıyorum. Windows kullananlar için WSL2 kurulumu ayrı bir yazı konusu ama temel adımlar aynı.

Python Ortamı Kurulumu

Conda ile izole bir ortam oluşturalım. Sistem Python’unu kirletmemek için bu adım kritik:

# Miniconda kurulumu (zaten kuruluysa atlayın)
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda3
echo 'export PATH="$HOME/miniconda3/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# LoRA eğitimi için yeni ortam
conda create -n lora-training python=3.10 -y
conda activate lora-training

# PyTorch CUDA ile kurulum
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

# CUDA versiyonunuzu kontrol edin
nvidia-smi
python -c "import torch; print(torch.cuda.is_available()); print(torch.version.cuda)"

Kohya_ss Kurulumu

LoRA eğitimi için en yaygın kullanılan araç kohya_ss. GUI’si var, script’leri var, her iki taraf için de kullanışlı:

# Repo'yu klonlayın
git clone https://github.com/kohya-ss/sd-scripts.git
cd sd-scripts

# Bağımlılıkları yükleyin
pip install -r requirements.txt

# xformers kurulumu (VRAM optimizasyonu için önemli)
pip install xformers==0.0.23.post1

# Accelerate yapılandırması
accelerate config
# Sorgulara şu şekilde cevap verin:
# - This machine: No distributed training
# - GPU type: cuda
# - FP16: yes

Veri Seti Hazırlığı

Bu adım eğitimin en kritik kısmı. Kötü veri seti, ne kadar iyi parametre kullansanız kullanın kötü sonuç verir.

Görsel Toplama ve Düzenleme

Diyelim ki bir şirkette çalışıyorsunuz ve şirketin flat design illüstrasyon tarzını öğretmek istiyorsunuz. Pazarlama ekibinin yıllardır ürettiği görseller var ama dağınık durumda.

# Görselleri toplamak ve düzenlemek için basit bir script
mkdir -p ~/lora-dataset/{raw,processed,captions}

# Farklı formatlardaki görselleri bulun
find /media/shared-drive/marketing -type f ( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" ) 
  -newer /tmp/last_sync 
  -exec cp {} ~/lora-dataset/raw/ ;

# Görsellerin çözünürlüklerini kontrol edin
cd ~/lora-dataset/raw
for f in *.{jpg,png,jpeg}; do
    identify "$f" 2>/dev/null | awk '{print $1, $3}'
done | sort -k2 -n

Görsel Boyutlandırma ve Kalite Kontrolü

Stable Diffusion 512×512 veya 768×768 üzerine eğitilmiş. Eğitim görsellerinizin de tutarlı boyutlarda olması gerekiyor. Python ile otomatik işleme yapalım:

#!/usr/bin/env python3
# prepare_dataset.py

from PIL import Image
import os
import shutil
from pathlib import Path

def resize_and_validate(input_dir, output_dir, target_size=512, min_size=512):
    """
    Görselleri eğitime hazırlar:
    - Minimum boyut kontrolü
    - Aspect ratio koruyarak kırpma
    - Kalite filtresi
    """
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)
    
    stats = {"processed": 0, "skipped": 0, "errors": 0}
    
    for img_file in input_path.glob("*.{jpg,jpeg,png,webp}"):
        try:
            with Image.open(img_file) as img:
                # Çok küçük görselleri atla
                if img.width < min_size or img.height < min_size:
                    print(f"SKIP (too small): {img_file.name} - {img.size}")
                    stats["skipped"] += 1
                    continue
                
                # Center crop ile kare yap
                size = min(img.width, img.height)
                left = (img.width - size) // 2
                top = (img.height - size) // 2
                img_cropped = img.crop((left, top, left + size, top + size))
                
                # Hedef boyuta resize
                img_resized = img_cropped.resize(
                    (target_size, target_size), 
                    Image.LANCZOS
                )
                
                # RGB'ye çevir (RGBA varsa)
                if img_resized.mode != 'RGB':
                    img_resized = img_resized.convert('RGB')
                
                output_file = output_path / f"{img_file.stem}.png"
                img_resized.save(output_file, "PNG", quality=95)
                stats["processed"] += 1
                
        except Exception as e:
            print(f"ERROR: {img_file.name} - {e}")
            stats["errors"] += 1
    
    print(f"nSonuç: {stats}")

if __name__ == "__main__":
    resize_and_validate(
        "~/lora-dataset/raw",
        "~/lora-dataset/processed",
        target_size=512
    )
python prepare_dataset.py

Caption Dosyaları Oluşturma

Her görsel için bir .txt caption dosyası gerekiyor. Bu caption’lar modelin öğrendiği konseptleri tanımlamalı. Önemli bir detay: eğitmek istediğiniz stili tanımlayan bir trigger word kullanın. Ben bu örnekte flatstyle_v1 kullanacağım.

# Basit caption oluşturma scripti
cd ~/lora-dataset/processed

for img in *.png; do
    basename="${img%.png}"
    caption_file="${basename}.txt"
    
    # Temel caption şablonu
    echo "flatstyle_v1 illustration, flat design, minimalist, clean lines, solid colors, no gradients, geometric shapes" > "$caption_file"
    
    echo "Caption oluşturuldu: $caption_file"
done

Ama otomatik caption çok genel kalıyor. BLIP veya WD14 tagger kullanarak daha detaylı caption’lar üretebilirsiniz:

# WD14 tagger ile otomatik caption (kohya_ss içinde mevcut)
python sd-scripts/finetune/tag_images_by_wd14_tagger.py 
    ~/lora-dataset/processed 
    --batch_size 4 
    --model_dir "~/.cache/huggingface/hub" 
    --thresh 0.35 
    --caption_extension ".txt" 
    --character_threshold 0.85 
    --prepend_tags "flatstyle_v1"

LoRA Eğitim Parametreleri

Klasör Yapısını Ayarlama

Kohya_ss belirli bir klasör yapısı bekliyor. Klasör adı {tekrar_sayisi}_{konsept_adi} formatında olmalı:

# Eğitim klasör yapısı
mkdir -p ~/lora-training/{
    training_images/10_flatstyle_v1,
    reg_images/1_illustration,
    output,
    logs
}

# İşlenmiş görselleri doğru konuma kopyalayın
cp ~/lora-dataset/processed/*.png ~/lora-training/training_images/10_flatstyle_v1/
cp ~/lora-dataset/processed/*.txt ~/lora-training/training_images/10_flatstyle_v1/

# Dosya sayısını doğrulayın
ls ~/lora-training/training_images/10_flatstyle_v1/ | wc -l

Klasör adındaki 10 tekrar sayısı anlamına geliyor. 20 görseliniz varsa ve epoch başına 200 iterasyon istiyorsanız, tekrar sayısını 10 yaparsınız (20 x 10 = 200).

Eğitim Script’i

Artık en kritik kısma geldik. Parametreleri doğru ayarlamak sonucu doğrudan etkiliyor:

#!/bin/bash
# train_lora.sh

# Temel değişkenler
BASE_MODEL="~/models/stable-diffusion-v1-5/v1-5-pruned-emaonly.safetensors"
OUTPUT_DIR="~/lora-training/output"
LOGGING_DIR="~/lora-training/logs"
TRAIN_DIR="~/lora-training/training_images"
REG_DIR="~/lora-training/reg_images"

accelerate launch --num_cpu_threads_per_process 8 
    sd-scripts/train_network.py 
    --pretrained_model_name_or_path="$BASE_MODEL" 
    --train_data_dir="$TRAIN_DIR" 
    --reg_data_dir="$REG_DIR" 
    --output_dir="$OUTPUT_DIR" 
    --logging_dir="$LOGGING_DIR" 
    --network_module="networks.lora" 
    --output_name="flatstyle_v1" 
    --save_model_as="safetensors" 
    --save_every_n_epochs=2 
    --resolution="512,512" 
    --enable_bucket 
    --min_bucket_reso=256 
    --max_bucket_reso=1024 
    --train_batch_size=2 
    --learning_rate=1e-4 
    --unet_lr=1e-4 
    --text_encoder_lr=5e-5 
    --lr_scheduler="cosine_with_restarts" 
    --lr_warmup_steps=100 
    --lr_scheduler_num_cycles=3 
    --network_dim=32 
    --network_alpha=16 
    --max_train_epochs=20 
    --mixed_precision="fp16" 
    --xformers 
    --gradient_checkpointing 
    --persistent_data_loader_workers 
    --clip_skip=2 
    --seed=42 
    --optimizer_type="AdamW8bit" 
    --caption_extension=".txt" 
    --shuffle_caption 
    --keep_tokens=1 
    --noise_offset=0.05 
    --adaptive_noise_scale=0.00357 
    2>&1 | tee ~/lora-training/logs/training_$(date +%Y%m%d_%H%M%S).log

echo "Eğitim tamamlandı!"

Kritik parametreleri açıklayalım:

  • –network_dim=32: LoRA rankı. Düşük değer (4-16) daha az bellek, daha az ifade gücü. Yüksek değer (64-128) daha fazla detay ama overfit riski.
  • –network_alpha=16: Genellikle dim’in yarısı olarak ayarlanır. Learning rate’i normalize eder.
  • –learning_rate=1e-4: Çok yüksek ayarlarsanız model bozulur, çok düşük ayarlarsanız öğrenme olmaz.
  • –clip_skip=2: SD 1.5 modelleri için 2, SDXL için 1 kullanın.
  • –gradient_checkpointing: Daha az VRAM kullanımı, biraz daha yavaş eğitim.
chmod +x train_lora.sh
./train_lora.sh

Eğitimi İzleme ve Sorun Giderme

Eğitim başladıktan sonra TensorBoard ile ilerlemeyi izleyebilirsiniz:

# Ayrı bir terminal'de
conda activate lora-training
tensorboard --logdir ~/lora-training/logs --port 6006

# Uzak sunucudaysan SSH tünel
ssh -L 6006:localhost:6006 user@training-server
# Tarayıcıda http://localhost:6006 adresine gidin

Eğitim sırasında sık karşılaşılan problemler ve çözümleri:

  • CUDA out of memory: --train_batch_size değerini 1’e düşürün veya --gradient_accumulation_steps=4 ekleyin.
  • Loss NaN oluyor: Learning rate çok yüksek, 1e-4 yerine 5e-5 deneyin.
  • Görseller bulanık çıkıyor: Veri seti kalitesiz veya yetersiz. En az 15-20 yüksek kaliteli görsel gerekiyor.
  • Trigger word çalışmıyor: Caption dosyalarını kontrol edin, trigger word başta olmalı.

Sonuçları Test Etme

Eğitim bittikten sonra output klasöründe .safetensors dosyaları göreceksiniz. Bunları Automatic1111 veya ComfyUI ile test edebilirsiniz:

# LoRA'yı Automatic1111'in klasörüne kopyalayın
cp ~/lora-training/output/flatstyle_v1-*.safetensors 
    ~/stable-diffusion-webui/models/Lora/

# Webui'yi yeniden başlatın (gerekiyorsa)
cd ~/stable-diffusion-webui
./webui.sh --xformers --medvram

ComfyUI ile script üzerinden test etmek isterseniz:

#!/usr/bin/env python3
# test_lora.py - ComfyUI API ile toplu test

import requests
import json
import base64
from pathlib import Path

def test_lora_batch(prompts, lora_name, output_dir="~/lora-test-results"):
    """LoRA'yı farklı prompt'larla test eder"""
    
    output_path = Path(output_dir).expanduser()
    output_path.mkdir(parents=True, exist_ok=True)
    
    for i, prompt in enumerate(prompts):
        # ComfyUI API payload
        workflow = {
            "prompt": {
                "3": {
                    "class_type": "KSampler",
                    "inputs": {
                        "seed": 42 + i,
                        "steps": 25,
                        "cfg": 7.5,
                        "sampler_name": "euler_a",
                        "scheduler": "karras",
                        "denoise": 1.0
                    }
                },
                "6": {
                    "class_type": "CLIPTextEncode",
                    "inputs": {
                        "text": f"flatstyle_v1 <lora:{lora_name}:0.8> {prompt}"
                    }
                }
            }
        }
        
        # API isteği gönder
        response = requests.post(
            "http://localhost:8188/prompt",
            json=workflow,
            timeout=120
        )
        
        if response.status_code == 200:
            print(f"Test {i+1}/{len(prompts)} başlatıldı: {prompt[:50]}...")
        else:
            print(f"HATA: {response.status_code} - {response.text}")

test_prompts = [
    "a person working at a desk, office scene",
    "mountain landscape with trees",
    "smartphone with app icons",
    "team meeting with people around a table",
    "dashboard with charts and graphs"
]

test_lora_batch(test_prompts, "flatstyle_v1")

LoRA Ağırlığı ve Birden Fazla LoRA Kullanımı

Prompt içinde LoRA’nın etkisini ayarlayabilirsiniz:

  • : Daha hafif etki, base model özellikleri daha belirgin
  • : Dengeli kullanım, çoğu durumda en iyi nokta
  • : Tam güç, bazen aşırı uygulama yapabilir

Birden fazla LoRA birleştirme:

flatstyle_v1 <lora:flatstyle_v1:0.7> <lora:add_detail:0.3>, a cityscape illustration

Dikkat etmeniz gereken nokta: iki LoRA’nın ağırlık toplamı 1.0’ı aşarsa beklenmedik sonuçlar çıkabilir.

Production’a Taşıma

Şirkette veya ekipte kullanılacaksa dağıtımı organize etmek gerekiyor:

#!/bin/bash
# deploy_lora.sh - LoRA versiyonlama ve dağıtım scripti

LORA_VERSION="1.0.0"
LORA_NAME="flatstyle_v1"
SOURCE_FILE="~/lora-training/output/${LORA_NAME}-000020.safetensors"
DEPLOY_BASE="/opt/stable-diffusion/models/Lora"
REGISTRY_FILE="/opt/stable-diffusion/lora-registry.json"

# Dosyayı versiyonla birlikte kopyala
cp "$SOURCE_FILE" "${DEPLOY_BASE}/${LORA_NAME}_v${LORA_VERSION}.safetensors"

# MD5 checksum kaydet
md5sum "${DEPLOY_BASE}/${LORA_NAME}_v${LORA_VERSION}.safetensors" > 
    "${DEPLOY_BASE}/${LORA_NAME}_v${LORA_VERSION}.md5"

# Registry'yi güncelle
python3 -c "
import json, datetime, sys

registry_file = '$REGISTRY_FILE'
try:
    with open(registry_file) as f:
        registry = json.load(f)
except FileNotFoundError:
    registry = {'loras': []}

registry['loras'].append({
    'name': '$LORA_NAME',
    'version': '$LORA_VERSION',
    'deployed_at': datetime.datetime.now().isoformat(),
    'file': '${LORA_NAME}_v${LORA_VERSION}.safetensors',
    'trigger_word': '$LORA_NAME',
    'recommended_weight': 0.8
})

with open(registry_file, 'w') as f:
    json.dump(registry, f, indent=2)

print('Registry güncellendi.')
"

echo "LoRA v${LORA_VERSION} başarıyla deploy edildi."

Sonuç

LoRA eğitimi ilk başta karmaşık görünüyor ama sistematik yaklaşıldığında gayet yönetilebilir bir süreç. En çok zaman harcadığınız yer veri seti hazırlığı olacak ve bu tamamen normal. Kaliteli 20-30 görsel, düzgün caption’larla hazırlanmış bir veri seti, kötü hazırlanmış 200 görselin önüne geçiyor.

Parametre ayarlarında başlangıç için şu değerlere sadık kalın: network_dim 32, alpha 16, learning rate 1e-4, epoch sayısı 15-20. Sonuçlar tatmin edici değilse tek tek değiştirin, aynı anda birden fazla parametreyi değiştirirseniz neyin etki ettiğini bilemezsiniz.

Trigger word seçimi de küçük ama önemli bir detay. Mevcut modelin eğitim datasında olmayan, özgün bir kelime seçin. flatstyle_v1, brandart_company, concept_xyz gibi kombinasyonlar iyi çalışıyor. art, style, drawing gibi genel kelimeler kullanmayın, base model bu kelimelere zaten güçlü bağlantılar kurmuş.

Son olarak: her epoch’u kaydedin ve farklı epoch’ları test edin. Çoğu zaman en iyi sonuç son epoch’tan değil, ortalardan bir yerden geliyor. Eğitim süreci doğrusal değil, bir noktadan sonra overfit başlıyor ve model sadece eğitim görsellerini taklit etmeye başlıyor.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir