A from-scratch, dependency-light LoRA training implementation for Z-Image-Turbo - the companion to
Z_Image_Inference_From_Scratch.
This project performs SFT LoRA fine-tuning of the 6B Z-Image-Turbo diffusion transformer using hand-written model definitions and a hand-written LoRA, with no external training-framework runtime dependency. The model code is shared with the inference project.
The 6B DiT, a 4B Qwen3 text encoder, and a Flux VAE do not fit together on a 24 GB card. This trainer avoids that in the simplest way possible:
(image, prompt) pair into (latent, prompt-embedding), then freed. The cached results are tiny.No accelerate, no peft, no DeepSpeed - just PyTorch.
diffusers, no peft.to_q,to_k,to_v,to_out.0,w1,w2,w3 LoRA targets at rank 32, AdamW (lr 1e-4, wd 0.01), 5 epochs over a 50Γ-repeated dataset.epoch-<n>.safetensors uses the standard <path>.lora_A.weight / <path>.lora_B.weight layout, so it loads straight into any compatible LoRA loader (and the from-scratch inference_lora.py here).meta device and weights loaded with assign=True (same trick as the inference project).bash Z-Image-Turbo-Train-lora.sh
or directly:
python train_lora.py \
--dataset_base_path /path/to/Z-Image-Turbo \
--dataset_metadata_path /path/to/Z-Image-Turbo/metadata.csv \
--max_pixels 1048576 --dataset_repeat 50 \
--learning_rate 1e-4 --num_epochs 5 \
--lora_target_modules "to_q,to_k,to_v,to_out.0,w1,w2,w3" \
--lora_rank 32 --lora_alpha 32 \
--use_gradient_checkpointing \
--output_path output/Z-Image-Turbo_lora
Each epoch writes output/Z-Image-Turbo_lora/epoch-<n>.safetensors.
bash Z-Image-Turbo-Train-lora.sh
or directly:
python inference_lora.py \
--lora_path output/Z-Image-Turbo_lora/epoch-4.safetensors \
--prompt "a dog" --output lora_dog.jpg
The bundled example_images/ set is five dog photos, each paired with a short prompt in example_images/metadata.csv. This is the entire fine-tuning set - repeated 50Γ per epoch, trained at LoRA rank 32.
| # | Prompt |
|---|---|
| 1 | dog, white and brown dog, sitting on wall, under pink flowers |
| 2 | dog, brown and white dog, standing, concrete structure |
| 3 | dog, corgi dog, sits ledge, smiles camera, orange background |
| 4 | dog, corgi dog, sitting on grass, looking at camera, happily |
| 5 | dog, white and brown dog, sitting outdoors, tongue out |
After fine-tuning, generating with the simple prompt a dog from the epoch-4 checkpoint (1024Γ1024, 8 steps):
The LoRA steers the base Z-Image-Turbo toward the dog concept captured by the five reference photos: the generated dog reflects the appearance and style of the training set, while the underlying 6B DiT retains its general image priors.
For each sample (batch size 1), following the flow-match SFT loss:
t from the 1000-step Z-Image flow-match schedule (shift = 3.0).noisy = (1 - Ο) Β· latent + Ο Β· noise.target = noise β latent.pred = model_fn_z_image_turbo(dit, noisy, t, prompt_embeds).MSE(pred, target) Β· w(t), where w(t) is the BSMNTW bell-shaped weight.Only the LoRA A/B matrices receive gradients; the 6B base DiT is frozen. AdamW updates the LoRA weights.
(latent, prompt-embed) pairs are encoded up-front and kept on CPU RAM. This is ideal for small/medium datasets (the bundled 5-image set, a few hundred images). For very large datasets you'd want on-the-fly encoding instead.CUDA_VISIBLE_DEVICES). Multi-GPU would need accelerate, which is deliberately out of scope for "as simple as possible".Built directly on Z_Image_Inference_From_Scratch (which itself credits DiffSynth-Studio and Z-Image). The training recipe, flow-match loss, BSMNTW weighting, and VAE-encoder architecture follow DiffSynth-Studio's implementation. Model weights are from the official Tongyi-MAI/Z-Image-Turbo release.
An independent, from-scratch reimplementation for research and educational purposes. The Z-Image-Turbo model weights remain under their own license - please respect the terms set by Tongyi-MAI/Z-Image-Turbo.
Python
99.0%
Shell
1.0%
A from-scratch, dependency-light LoRA training implementation for Z-Image-Turbo - the companion to
Z_Image_Inference_From_Scratch.
This project performs SFT LoRA fine-tuning of the 6B Z-Image-Turbo diffusion transformer using hand-written model definitions and a hand-written LoRA, with no external training-framework runtime dependency. The model code is shared with the inference project.
The 6B DiT, a 4B Qwen3 text encoder, and a Flux VAE do not fit together on a 24 GB card. This trainer avoids that in the simplest way possible:
(image, prompt) pair into (latent, prompt-embedding), then freed. The cached results are tiny.No accelerate, no peft, no DeepSpeed - just PyTorch.
diffusers, no peft.to_q,to_k,to_v,to_out.0,w1,w2,w3 LoRA targets at rank 32, AdamW (lr 1e-4, wd 0.01), 5 epochs over a 50Γ-repeated dataset.epoch-<n>.safetensors uses the standard <path>.lora_A.weight / <path>.lora_B.weight layout, so it loads straight into any compatible LoRA loader (and the from-scratch inference_lora.py here).meta device and weights loaded with assign=True (same trick as the inference project).bash Z-Image-Turbo-Train-lora.sh
or directly:
python train_lora.py \
--dataset_base_path /path/to/Z-Image-Turbo \
--dataset_metadata_path /path/to/Z-Image-Turbo/metadata.csv \
--max_pixels 1048576 --dataset_repeat 50 \
--learning_rate 1e-4 --num_epochs 5 \
--lora_target_modules "to_q,to_k,to_v,to_out.0,w1,w2,w3" \
--lora_rank 32 --lora_alpha 32 \
--use_gradient_checkpointing \
--output_path output/Z-Image-Turbo_lora
Each epoch writes output/Z-Image-Turbo_lora/epoch-<n>.safetensors.
bash Z-Image-Turbo-Train-lora.sh
or directly:
python inference_lora.py \
--lora_path output/Z-Image-Turbo_lora/epoch-4.safetensors \
--prompt "a dog" --output lora_dog.jpg
The bundled example_images/ set is five dog photos, each paired with a short prompt in example_images/metadata.csv. This is the entire fine-tuning set - repeated 50Γ per epoch, trained at LoRA rank 32.
| # | Prompt |
|---|---|
| 1 | dog, white and brown dog, sitting on wall, under pink flowers |
| 2 | dog, brown and white dog, standing, concrete structure |
| 3 | dog, corgi dog, sits ledge, smiles camera, orange background |
| 4 | dog, corgi dog, sitting on grass, looking at camera, happily |
| 5 | dog, white and brown dog, sitting outdoors, tongue out |
After fine-tuning, generating with the simple prompt a dog from the epoch-4 checkpoint (1024Γ1024, 8 steps):
The LoRA steers the base Z-Image-Turbo toward the dog concept captured by the five reference photos: the generated dog reflects the appearance and style of the training set, while the underlying 6B DiT retains its general image priors.
For each sample (batch size 1), following the flow-match SFT loss:
t from the 1000-step Z-Image flow-match schedule (shift = 3.0).noisy = (1 - Ο) Β· latent + Ο Β· noise.target = noise β latent.pred = model_fn_z_image_turbo(dit, noisy, t, prompt_embeds).MSE(pred, target) Β· w(t), where w(t) is the BSMNTW bell-shaped weight.Only the LoRA A/B matrices receive gradients; the 6B base DiT is frozen. AdamW updates the LoRA weights.
(latent, prompt-embed) pairs are encoded up-front and kept on CPU RAM. This is ideal for small/medium datasets (the bundled 5-image set, a few hundred images). For very large datasets you'd want on-the-fly encoding instead.CUDA_VISIBLE_DEVICES). Multi-GPU would need accelerate, which is deliberately out of scope for "as simple as possible".Built directly on Z_Image_Inference_From_Scratch (which itself credits DiffSynth-Studio and Z-Image). The training recipe, flow-match loss, BSMNTW weighting, and VAE-encoder architecture follow DiffSynth-Studio's implementation. Model weights are from the official Tongyi-MAI/Z-Image-Turbo release.
An independent, from-scratch reimplementation for research and educational purposes. The Z-Image-Turbo model weights remain under their own license - please respect the terms set by Tongyi-MAI/Z-Image-Turbo.
Python
99.0%
Shell
1.0%