Skip to content

Commit 8933686

Browse files
Z image lora training (#13056)
* initial commit * initial commit * initial commit * initial commit * initial commit * initial commit * initial commit * fix vae * fix prompts * Apply style fixes * fix license --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent baaa8d0 commit 8933686

File tree

2 files changed

+2259
-0
lines changed

2 files changed

+2259
-0
lines changed
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
# DreamBooth training example for Z-Image
2+
3+
[DreamBooth](https://huggingface.co/papers/2208.12242) is a method to personalize image generation models given just a few (3~5) images of a subject/concept.
4+
[LoRA](https://huggingface.co/docs/peft/conceptual_guides/adapter#low-rank-adaptation-lora) is a popular parameter-efficient fine-tuning technique that allows you to achieve full-finetuning like performance but with a fraction of learnable parameters.
5+
6+
The `train_dreambooth_lora_z_image.py` script shows how to implement the training procedure for [LoRAs](https://huggingface.co/blog/lora) and adapt it for [Z-Image](https://huggingface.co/Tongyi-MAI/Z-Image).
7+
8+
> [!NOTE]
9+
> **About Z-Image**
10+
>
11+
> Z-Image is a high-quality text-to-image generation model from Alibaba's Tongyi Lab. It uses a DiT (Diffusion Transformer) architecture with Qwen3 as the text encoder. The model excels at generating images with accurate text rendering, especially for Chinese characters.
12+
13+
> [!NOTE]
14+
> **Memory consumption**
15+
>
16+
> Z-Image is relatively memory efficient compared to other large-scale diffusion models. Below we provide some tips and tricks to further reduce memory consumption during training.
17+
18+
## Running locally with PyTorch
19+
20+
### Installing the dependencies
21+
22+
Before running the scripts, make sure to install the library's training dependencies:
23+
24+
**Important**
25+
26+
To make sure you can successfully run the latest versions of the example scripts, we highly recommend **installing from source** and keeping the install up to date as we update the example scripts frequently and install some example-specific requirements. To do this, execute the following steps in a new virtual environment:
27+
28+
```bash
29+
git clone https://github.com/huggingface/diffusers
30+
cd diffusers
31+
pip install -e .
32+
```
33+
34+
Then cd in the `examples/dreambooth` folder and run
35+
```bash
36+
pip install -r requirements_z_image.txt
37+
```
38+
39+
And initialize an [🤗Accelerate](https://github.com/huggingface/accelerate/) environment with:
40+
41+
```bash
42+
accelerate config
43+
```
44+
45+
Or for a default accelerate configuration without answering questions about your environment
46+
47+
```bash
48+
accelerate config default
49+
```
50+
51+
Or if your environment doesn't support an interactive shell (e.g., a notebook)
52+
53+
```python
54+
from accelerate.utils import write_basic_config
55+
write_basic_config()
56+
```
57+
58+
When running `accelerate config`, if we specify torch compile mode to True there can be dramatic speedups.
59+
Note also that we use PEFT library as backend for LoRA training, make sure to have `peft>=0.6.0` installed in your environment.
60+
61+
62+
### Dog toy example
63+
64+
Now let's get our dataset. For this example we will use some dog images: https://huggingface.co/datasets/diffusers/dog-example.
65+
66+
Let's first download it locally:
67+
68+
```python
69+
from huggingface_hub import snapshot_download
70+
71+
local_dir = "./dog"
72+
snapshot_download(
73+
"diffusers/dog-example",
74+
local_dir=local_dir, repo_type="dataset",
75+
ignore_patterns=".gitattributes",
76+
)
77+
```
78+
79+
This will also allow us to push the trained LoRA parameters to the Hugging Face Hub platform.
80+
81+
## Memory Optimizations
82+
83+
> [!NOTE]
84+
> Many of these techniques complement each other and can be used together to further reduce memory consumption. However some techniques may be mutually exclusive so be sure to check before launching a training run.
85+
86+
### CPU Offloading
87+
To offload parts of the model to CPU memory, you can use `--offload` flag. This will offload the VAE and text encoder to CPU memory and only move them to GPU when needed.
88+
89+
### Latent Caching
90+
Pre-encode the training images with the VAE, and then delete it to free up some memory. To enable `latent_caching` simply pass `--cache_latents`.
91+
92+
### QLoRA: Low Precision Training with Quantization
93+
Perform low precision training using 8-bit or 4-bit quantization to reduce memory usage. You can use the following flags:
94+
95+
- **FP8 training** with `torchao`:
96+
Enable FP8 training by passing `--do_fp8_training`.
97+
> [!IMPORTANT]
98+
> Since we are utilizing FP8 tensor cores we need CUDA GPUs with compute capability at least 8.9 or greater. If you're looking for memory-efficient training on relatively older cards, we encourage you to check out other trainers.
99+
100+
- **NF4 training** with `bitsandbytes`:
101+
Alternatively, you can use 8-bit or 4-bit quantization with `bitsandbytes` by passing `--bnb_quantization_config_path` to enable 4-bit NF4 quantization.
102+
103+
### Gradient Checkpointing and Accumulation
104+
* `--gradient_accumulation` refers to the number of updates steps to accumulate before performing a backward/update pass. By passing a value > 1 you can reduce the amount of backward/update passes and hence also memory requirements.
105+
* With `--gradient_checkpointing` we can save memory by not storing all intermediate activations during the forward pass. Instead, only a subset of these activations (the checkpoints) are stored and the rest is recomputed as needed during the backward pass. Note that this comes at the expense of a slower backward pass.
106+
107+
### 8-bit-Adam Optimizer
108+
When training with `AdamW` (doesn't apply to `prodigy`) you can pass `--use_8bit_adam` to reduce the memory requirements of training. Make sure to install `bitsandbytes` if you want to do so.
109+
110+
### Image Resolution
111+
An easy way to mitigate some of the memory requirements is through `--resolution`. `--resolution` refers to the resolution for input images, all the images in the train/validation dataset are resized to this.
112+
Note that by default, images are resized to resolution of 1024, but it's good to keep in mind in case you're training on higher resolutions.
113+
114+
### Precision of saved LoRA layers
115+
By default, trained transformer layers are saved in the precision dtype in which training was performed. E.g. when training in mixed precision is enabled with `--mixed_precision="bf16"`, final finetuned layers will be saved in `torch.bfloat16` as well.
116+
This reduces memory requirements significantly without a significant quality loss. Note that if you do wish to save the final layers in float32 at the expense of more memory usage, you can do so by passing `--upcast_before_saving`.
117+
118+
## Training Examples
119+
120+
### Z-Image Training
121+
122+
To perform DreamBooth with LoRA on Z-Image, run:
123+
124+
```bash
125+
export MODEL_NAME="Tongyi-MAI/Z-Image"
126+
export INSTANCE_DIR="dog"
127+
export OUTPUT_DIR="trained-z-image-lora"
128+
129+
accelerate launch train_dreambooth_lora_z_image.py \
130+
--pretrained_model_name_or_path=$MODEL_NAME \
131+
--instance_data_dir=$INSTANCE_DIR \
132+
--output_dir=$OUTPUT_DIR \
133+
--mixed_precision="bf16" \
134+
--gradient_checkpointing \
135+
--cache_latents \
136+
--instance_prompt="a photo of sks dog" \
137+
--resolution=1024 \
138+
--train_batch_size=1 \
139+
--guidance_scale=5.0 \
140+
--use_8bit_adam \
141+
--gradient_accumulation_steps=4 \
142+
--optimizer="adamW" \
143+
--learning_rate=1e-4 \
144+
--report_to="wandb" \
145+
--lr_scheduler="constant" \
146+
--lr_warmup_steps=100 \
147+
--max_train_steps=500 \
148+
--validation_prompt="A photo of sks dog in a bucket" \
149+
--validation_epochs=25 \
150+
--seed="0" \
151+
--push_to_hub
152+
```
153+
154+
To better track our training experiments, we're using the following flags in the command above:
155+
156+
* `report_to="wandb"` will ensure the training runs are tracked on [Weights and Biases](https://wandb.ai/site). To use it, be sure to install `wandb` with `pip install wandb`. Don't forget to call `wandb login <your_api_key>` before training if you haven't done it before.
157+
* `validation_prompt` and `validation_epochs` to allow the script to do a few validation inference runs. This allows us to qualitatively check if the training is progressing as expected.
158+
159+
> [!NOTE]
160+
> If you want to train using long prompts, you can use `--max_sequence_length` to set the token limit. The default is 512. Note that this will use more resources and may slow down the training in some cases.
161+
162+
### Training with FP8 Quantization
163+
164+
For reduced memory usage with FP8 training:
165+
166+
```bash
167+
export MODEL_NAME="Tongyi-MAI/Z-Image"
168+
export INSTANCE_DIR="dog"
169+
export OUTPUT_DIR="trained-z-image-lora-fp8"
170+
171+
accelerate launch train_dreambooth_lora_z_image.py \
172+
--pretrained_model_name_or_path=$MODEL_NAME \
173+
--instance_data_dir=$INSTANCE_DIR \
174+
--output_dir=$OUTPUT_DIR \
175+
--do_fp8_training \
176+
--gradient_checkpointing \
177+
--cache_latents \
178+
--instance_prompt="a photo of sks dog" \
179+
--resolution=1024 \
180+
--train_batch_size=1 \
181+
--guidance_scale=5.0 \
182+
--use_8bit_adam \
183+
--gradient_accumulation_steps=4 \
184+
--optimizer="adamW" \
185+
--learning_rate=1e-4 \
186+
--report_to="wandb" \
187+
--lr_scheduler="constant" \
188+
--lr_warmup_steps=100 \
189+
--max_train_steps=500 \
190+
--validation_prompt="A photo of sks dog in a bucket" \
191+
--validation_epochs=25 \
192+
--seed="0" \
193+
--push_to_hub
194+
```
195+
196+
### FSDP on the transformer
197+
198+
By setting the accelerate configuration with FSDP, the transformer block will be wrapped automatically. E.g. set the configuration to:
199+
200+
```yaml
201+
distributed_type: FSDP
202+
fsdp_config:
203+
fsdp_version: 2
204+
fsdp_offload_params: false
205+
fsdp_sharding_strategy: HYBRID_SHARD
206+
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
207+
fsdp_transformer_layer_cls_to_wrap: ZImageTransformerBlock
208+
fsdp_forward_prefetch: true
209+
fsdp_sync_module_states: false
210+
fsdp_state_dict_type: FULL_STATE_DICT
211+
fsdp_use_orig_params: false
212+
fsdp_activation_checkpointing: true
213+
fsdp_reshard_after_forward: true
214+
fsdp_cpu_ram_efficient_loading: false
215+
```
216+
217+
### Prodigy Optimizer
218+
219+
Prodigy is an adaptive optimizer that dynamically adjusts the learning rate learned parameters based on past gradients, allowing for more efficient convergence.
220+
By using prodigy we can "eliminate" the need for manual learning rate tuning. Read more [here](https://huggingface.co/blog/sdxl_lora_advanced_script#adaptive-optimizers).
221+
222+
To use prodigy, first make sure to install the prodigyopt library: `pip install prodigyopt`, and then specify:
223+
```bash
224+
--optimizer="prodigy"
225+
```
226+
227+
> [!TIP]
228+
> When using prodigy it's generally good practice to set `--learning_rate=1.0`
229+
230+
```bash
231+
export MODEL_NAME="Tongyi-MAI/Z-Image"
232+
export INSTANCE_DIR="dog"
233+
export OUTPUT_DIR="trained-z-image-lora-prodigy"
234+
235+
accelerate launch train_dreambooth_lora_z_image.py \
236+
--pretrained_model_name_or_path=$MODEL_NAME \
237+
--instance_data_dir=$INSTANCE_DIR \
238+
--output_dir=$OUTPUT_DIR \
239+
--mixed_precision="bf16" \
240+
--gradient_checkpointing \
241+
--cache_latents \
242+
--instance_prompt="a photo of sks dog" \
243+
--resolution=1024 \
244+
--train_batch_size=1 \
245+
--guidance_scale=5.0 \
246+
--gradient_accumulation_steps=4 \
247+
--optimizer="prodigy" \
248+
--learning_rate=1.0 \
249+
--report_to="wandb" \
250+
--lr_scheduler="constant_with_warmup" \
251+
--lr_warmup_steps=100 \
252+
--max_train_steps=500 \
253+
--validation_prompt="A photo of sks dog in a bucket" \
254+
--validation_epochs=25 \
255+
--seed="0" \
256+
--push_to_hub
257+
```
258+
259+
### LoRA Rank and Alpha
260+
261+
Two key LoRA hyperparameters are LoRA rank and LoRA alpha:
262+
263+
- `--rank`: Defines the dimension of the trainable LoRA matrices. A higher rank means more expressiveness and capacity to learn (and more parameters).
264+
- `--lora_alpha`: A scaling factor for the LoRA's output. The LoRA update is scaled by `lora_alpha / lora_rank`.
265+
266+
**lora_alpha vs. rank:**
267+
268+
This ratio dictates the LoRA's effective strength:
269+
- `lora_alpha == rank`: Scaling factor is 1. The LoRA is applied with its learned strength. (e.g., alpha=16, rank=16)
270+
- `lora_alpha < rank`: Scaling factor < 1. Reduces the LoRA's impact. Useful for subtle changes or to prevent overpowering the base model. (e.g., alpha=8, rank=16)
271+
- `lora_alpha > rank`: Scaling factor > 1. Amplifies the LoRA's impact. Allows a lower rank LoRA to have a stronger effect. (e.g., alpha=32, rank=16)
272+
273+
> [!TIP]
274+
> A common starting point is to set `lora_alpha` equal to `rank`.
275+
> Some also set `lora_alpha` to be twice the `rank` (e.g., lora_alpha=32 for lora_rank=16)
276+
> to give the LoRA updates more influence without increasing parameter count.
277+
> If you find your LoRA is "overcooking" or learning too aggressively, consider setting `lora_alpha` to half of `rank`
278+
> (e.g., lora_alpha=8 for rank=16). Experimentation is often key to finding the optimal balance for your use case.
279+
280+
### Target Modules
281+
282+
When LoRA was first adapted from language models to diffusion models, it was applied to the cross-attention layers in the UNet that relate the image representations with the prompts that describe them.
283+
More recently, SOTA text-to-image diffusion models replaced the UNet with a diffusion Transformer (DiT). With this change, we may also want to explore applying LoRA training onto different types of layers and blocks.
284+
285+
To allow more flexibility and control over the targeted modules we added `--lora_layers`, in which you can specify in a comma separated string the exact modules for LoRA training. Here are some examples of target modules you can provide:
286+
287+
- For attention only layers: `--lora_layers="to_k,to_q,to_v,to_out.0"`
288+
- For attention and feed-forward layers: `--lora_layers="to_k,to_q,to_v,to_out.0,ff.net.0.proj,ff.net.2"`
289+
290+
> [!NOTE]
291+
> `--lora_layers` can also be used to specify which **blocks** to apply LoRA training to. To do so, simply add a block prefix to each layer in the comma separated string.
292+
293+
> [!NOTE]
294+
> Keep in mind that while training more layers can improve quality and expressiveness, it also increases the size of the output LoRA weights.
295+
296+
### Aspect Ratio Bucketing
297+
298+
We've added aspect ratio bucketing support which allows training on images with different aspect ratios without cropping them to a single square resolution. This technique helps preserve the original composition of training images and can improve training efficiency.
299+
300+
To enable aspect ratio bucketing, pass `--aspect_ratio_buckets` argument with a semicolon-separated list of height,width pairs, such as:
301+
302+
```bash
303+
--aspect_ratio_buckets="672,1568;688,1504;720,1456;752,1392;800,1328;832,1248;880,1184;944,1104;1024,1024;1104,944;1184,880;1248,832;1328,800;1392,752;1456,720;1504,688;1568,672"
304+
```
305+
306+
### Bilingual Prompts
307+
308+
Z-Image has strong support for both Chinese and English prompts. When training with Chinese prompts, ensure your dataset captions are properly encoded in UTF-8:
309+
310+
```bash
311+
--instance_prompt="一只sks狗的照片"
312+
--validation_prompt="一只sks狗在桶里的照片"
313+
```
314+
315+
> [!TIP]
316+
> Z-Image excels at text rendering in generated images, especially for Chinese characters. If your use case involves generating images with text, consider including text-related examples in your training data.
317+
318+
## Inference
319+
320+
Once you have trained a LoRA, you can load it for inference:
321+
322+
```python
323+
import torch
324+
from diffusers import ZImagePipeline
325+
326+
pipe = ZImagePipeline.from_pretrained("Tongyi-MAI/Z-Image", torch_dtype=torch.bfloat16)
327+
pipe.to("cuda")
328+
329+
# Load your trained LoRA
330+
pipe.load_lora_weights("path/to/your/trained-z-image-lora")
331+
332+
# Generate an image
333+
image = pipe(
334+
prompt="A photo of sks dog in a bucket",
335+
height=1024,
336+
width=1024,
337+
num_inference_steps=50,
338+
guidance_scale=5.0,
339+
generator=torch.Generator("cuda").manual_seed(42),
340+
).images[0]
341+
342+
image.save("output.png")
343+
```
344+
345+
---
346+
347+
Since Z-Image finetuning is still in an experimental phase, we encourage you to explore different settings and share your insights! 🤗

0 commit comments

Comments
 (0)