Diffusion-DPO

repository·main·Indexed 20 days ago

https://github.com/salesforceairesearch/diffusiondpo

A training framework for aligning diffusion models using Direct Preference Optimization (DPO). It enables fine-tuning of models such as Stable Diffusion 1.5 and SDXL to better match human preferences or specific scoring models. The repository includes scripts for training via train.py, support for Supervised Fine-Tuning (SFT), and utilities for evaluating generations using PickScore.

Tokens
2.1K
Snippets
6
Records
8
Agent score
22%

What's inside Diffusion-DPO

  1. Run Diffusion-DPO training for Stable Diffusion 1.5

    main

    To train a Stable Diffusion 1.5 model using Direct Preference Optimization (DPO), use the accelerate launch command pointing to train.py.

    Note on Batch Size: The effective batch size is calculated as (N_GPU * train_batch_size * gradient_accumulation_steps). The original paper used an effective batch size of 2048.

    Example Launch Script:

    export MODEL_NAME="runwayml/stable-diffusion-v1-5"
    export DATASET_NAME="yuvalkirstain/pickapic_v2"
    
    accelerate launch --mixed_precision="fp16"  train.py \
      --pretrained_model_name_or_path=$MODEL_NAME \
      --dataset_name=$DATASET_NAME \
      --train_batch_size=1 \
      --dataloader_num_workers=16 \
      --gradient_accumulation_steps=1 \
      --max_train_steps=2000 \
      --lr_scheduler="constant_with_warmup" --lr_warmup_steps=500 \
      --learning_rate=1e-8 --scale_lr \
      --cache_dir="/path/to/your/cache/" \
      --checkpointing_steps 500 \
      --beta_dpo 5000 \
       --output_dir="tmp-sd15"
    export MODEL_NAME="runwayml/stable-diffusion-v1-5"
    export DATASET_NAME="yuvalkirstain/pickapic_v2"
    
    accelerate launch --mixed_precision="fp16"  train.py \
      --pretrained_model_name_or_path=$MODEL_NAME \
      --dataset_name=$DATASET_NAME \
      --train_batch_size=1 \
      --dataloader_num_workers=16 \
      --gradient_accumulation_steps=1 \
      --max_train_steps=2000 \
      --lr_scheduler="constant_with_warmup" --lr_warmup_steps=500 \
      --learning_rate=1e-8 --scale_lr \
      --cache_dir="/export/share/datasets/vision_language/pick_a_pic_v2/" \
      --checkpointing_steps 500 \
      --beta_dpo 5000 \
       --output_dir="tmp-sd15"
  2. Use pretrained Diffusion-DPO checkpoints

    main

    Pretrained models are available on Hugging Face. You can use these to compare generations or perform evaluations.

    • StableDiffusion 1.5: mhdang/dpo-sd1.5-text2image-v1
    • StableDiffusion XL 1.0: mhdang/dpo-sdxl-text2image-v1

    You can use the provided quick_samples.ipynb notebook to visualize generations and perform quantitative evaluation using PickScore.

  3. Configure training arguments for train.py

    main

    The train.py script accepts several arguments to control the training process.

    General Arguments

    • --pretrained_model_name_or_path: The model to initialize from.
    • --output_dir: Directory to save logs and checkpoints.
    • --seed: Training seed.
    • --sdxl: Flag to enable Stable Diffusion XL training.
    • --sft: Flag to run Supervised Fine-Tuning (SFT) instead of DPO.

    DPO Arguments

    • --beta_dpo: The KL-divergence parameter beta for DPO.
    • --choice_model: The model used for AI feedback (options include Aesthetics, CLIP, PickScore, or HPS).

    Optimizer and Learning Rate Arguments

    • --max_train_steps: Total number of training steps.
    • --gradient_accumulation_steps: Number of steps for gradient accumulation.
    • --train_batch_size: Batch size per device.
    • --checkpointing_steps: Frequency of saving model checkpoints.
    • --gradient_checkpointing: Automatically enabled for SDXL.
    • --learning_rate: The learning rate.
    • --scale_lr: Scales the learning rate (recommended for stability).
    • --lr_scheduler: Type of scheduler (e.g., linear_warmup_to_constant).
    • --lr_warmup_steps: Number of warmup steps.
    • --use_adafactor: Uses Adafactor instead of Adam (lower memory, default for SDXL).

    Data Arguments

    • --dataset_name: Name of the dataset (e.g., Pick-a-Pic).
    • --cache_dir: Local directory for caching the dataset.
    • --resolution: Image resolution (defaults to 512 for SD1.5, 1024 for SDXL).
    • --random_crop: Enables random cropping data augmentation.
    • --no_hflip: Disables horizontal flipping data augmentation.
    • --dataloader_num_workers: Number of dataloader workers.
  4. Compare Baseline vs DPO generations

    main

    To compare a standard Stable Diffusion model with a DPO-tuned version, you can swap the unet attribute of an existing pipeline. This allows you to use the same pipeline infrastructure (scheduler, text encoder, etc.) while switching between the original and the DPO-tuned weights.

    # Assuming 'pipe' is your loaded pipeline and 'unets' is a list [original_unet, dpo_unet]
    unets = [pipe.unet, dpo_unet]
    names = ["Orig. SDXL", "DPO SDXL"]
    
    def gen(prompt, seed=0, run_baseline=True):
        ims = []
        generator = torch.Generator(device='cuda')
        # Loop through original and DPO unets if run_baseline is True
        for unet_i in ([0, 1] if run_baseline else [1]):
            print(f"Prompt: {prompt}\nSeed: {seed}\n{names[unet_i]}")
            pipe.unet = unets[unet_i]
            generator = generator.manual_seed(seed)
            
            im = pipe(prompt=prompt, generator=generator, guidance_scale=7.5).images[0]
            ims.append(im)
        return ims
  5. Initialize Stable Diffusion pipelines

    main

    Depending on whether you are using Stable Diffusion v1.5 or SDXL, use StableDiffusionPipeline or StableDiffusionXLPipeline. For SDXL, it is recommended to use variant="fp16" and use_safetensors=True.

    Note: You may want to set pipe.safety_checker = None to prevent the safety checker from aggressively filtering generated images.

    from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline
    import torch
    
    pretrained_model_name = "stabilityai/stable-diffusion-xl-base-1.0"
    
    if 'stable-diffusion-xl' in pretrained_model_name:
        pipe = StableDiffusionXLPipeline.from_pretrained(
            pretrained_model_name, 
            torch_dtype=torch.float16,
            variant="fp16", 
            use_safetensors=True
        ).to("cuda")
    else:
        pipe = StableDiffusionPipeline.from_pretrained(
            pretrained_model_name, 
            torch_dtype=torch.float16
        ).to("cuda")
    
    pipe.safety_checker = None
  6. Load DPO-tuned UNet weights

    main

    To use a Diffusion DPO model, load the fine-tuned UNet weights using UNet2DConditionModel.from_pretrained. You can specify a Hugging Face model ID (e.g., 'mhdang/dpo-sdxl-text2image-v1') or a local checkpoint directory (e.g., */checkpoint-n/). Ensure you specify the subfolder='unet' and use torch.float16 for efficiency on GPU.

    from diffusers import UNet2DConditionModel
    import torch
    
    dpo_unet = UNet2DConditionModel.from_pretrained(
        'mhdang/dpo-sdxl-text2image-v1',
        subfolder='unet',
        torch_dtype=torch.float16
    ).to('cuda')
  7. Score generations using PickScore

    main

    You can automatically score generated images against their prompts using the Selector class from utils.pickscore_utils. This allows for automated evaluation of image quality and prompt adherence.

    from utils.pickscore_utils import Selector
    
    # Initialize the selector on GPU
    ps_selector = Selector('cuda')
    
    # Score a list of images against a prompt
    scores = ps_selector.score(ims, p)
    print(scores)