I am encountering a issue where the diffusion model's training loss fails to converge when fine-tuning with LoRA (system.use_lora=True). Instead of decreasing, the loss oscillates significantly throughout the training process.
To isolate the problem, I attempted to fine-tune the model using the minimal example dataset provided (the single object in ./data/shape_diffusion/objaverse). Using the configuration file detailed below, I ran the training for 200 epochs with the command: CUDA_VISIBLE_DEVICES=0 python train.py --config path/to/config.yaml --train --gpu 0 system.use_lora=True. The expected behavior of a steadily decreasing loss did not occur. Instead, the loss value remained unstable and oscillated for the entire duration, as shown in the attached loss curve.
I have confirmed this behavior occurs both when training with labels and without them; neither setup leads to convergence. Interestingly, despite the unstable training, the fine-tuned model checkpoint is able to produce seemingly normal inferences.
This behavior is not limited to the example data. My initial attempt was on a custom dataset built from parnet-mobility objects, which I processed using the data/watertight_and_sampling.py script. During that process, I first encountered a NaN loss, an issue similar to one reported by jseobyun. I resolved the NaN loss by filtering out the problematic sharp_surface data. However, even after fixing the data and retraining for about 100 epochs, the primary issue of the oscillating loss persisted.
Since the problem occurs on both a larger custom dataset and the minimal single-object example, I suspect that the issue may originate from the data, the training configuration, or perhaps even the code. I would appreciate any guidance or suggestions on how to resolve this convergence issue.
Loss curvs is as follows

Configuration (step1x-3d-geometry-label-1300m.yaml)
# [INFO]
# | Name | Type | Params
# -------------------------------------------------------------
# 0 | shape_model | MichelangeloAutoencoder | 191 M
# 1 | visual_condition | Dinov2CLIPEncoder | 731 M
# 2 | label_condition | LabelEncoder | 8.2 K
# 3 | denoiser_model | FluxDenoiser | 1.3 B
# -------------------------------------------------------------
# 1.3 B Trainable params
# 923 M Non-trainable params
# 2.2 B Total params
exp_root_dir: "outputs_test"
name: "step1x-3d-geometry-label/dinov2reglarge518-clip-label-fluxflow-dit1300m"
#tag: "${rmspace:${system.shape_model_type}+n${data.n_samples}+${system.optimizer.name}lr${system.optimizer.args.lr},_}"
tag: "objaverse-200ep-wlabel-wcaption-lora-t7181228-testpret"
seed: 0
data_type: "Objaverse-datamodule"
data:
root_dir: "./data/shape_diffusion/objaverse"
load_geometry: True # whether to load geometry
geo_data_type: "sdf"
with_sharp_data: True
n_samples: 32768
noise_sigma: 0.
random_flip: True # whether to randomly flip the input mesh
random_color_jitter: True # whether to add random color jitter to the input images
random_rotate: True # whether to add random rotation to the input images
load_image: True # whether to load images
image_type: "rgb" # rgb, normal
idx: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] # front view
n_views: 1
background_color: [255, 255, 255]
load_caption: True # whether to load captions #False
load_label: True # whether to load labels #True
batch_size: 8 # TODO: change this for your own dataset
num_workers: 4 # change this for your own dataset
system_type: "rectified-flow-system"
system:
val_samples_json: "val_data/images/val_samples_rgb_image.json"
guidance_scale: 7.5
num_inference_steps: 30
eta: 0.0
shape_model_type: michelangelo-autoencoder
shape_model:
pretrained_model_name_or_path: /home/yuantingyu/models
subfolder: Step1X-3D-Geometry-Label-1300m
n_samples: ${data.n_samples}
with_sharp_data: ${data.with_sharp_data}
use_downsample: true
num_latents: 2048
embed_dim: 64
point_feats: 3
out_dim: 1
num_freqs: 8
include_pi: false
heads: 12
width: 768
num_encoder_layers: 8
num_decoder_layers: 16
use_ln_post: true
init_scale: 0.25
qkv_bias: false
use_flash: true #true
use_checkpoint: false
visual_condition_type: "dinov2-clip-encoder"
visual_condition:
pretrained_dino_name_or_path: /home/yuantingyu/models/dinov2-large
pretrained_clip_name_or_path: /home/yuantingyu/models/clip-vit-large-patch14
encode_camera: false
n_views: ${data.n_views}
empty_embeds_ratio: 0.1
normalize_embeds: false
zero_uncond_embeds: true
image_size: 224
label_condition_type: "label-encoder"
label_condition:
hidden_size: 1024
empty_embeds_ratio: 0.1
normalize_embeds: false
zero_uncond_embeds: true
denoiser_model_type: "flux-denoiser"
denoiser_model:
pretrained_model_name_or_path: "/home/yuantingyu/models/modelscope/Step1X-3D-Geometry-Label-1300m/transformer/diffusion_pytorch_model.safetensors"
input_channels: ${system.shape_model.embed_dim}
width: 1536
layers: 8
num_single_layers: 16
num_heads: 16
use_visual_condition: True
visual_condition_dim: 1024
n_views: ${data.n_views}
use_label_condition: True
label_condition_dim: ${system.label_condition.hidden_size}
noise_scheduler_type: "diffusers.schedulers.FlowMatchEulerDiscreteScheduler"
noise_scheduler:
num_train_timesteps: 1000
denoise_scheduler_type: "diffusers.schedulers.FlowMatchEulerDiscreteScheduler"
denoise_scheduler:
num_train_timesteps: 1000
loggers:
wandb:
enable: false
project: "step1x-3d"
name: image-to-shape-diffusion+${name}+${tag}
loss:
loss_type: "mse"
lambda_diffusion: 1.
optimizer:
name: AdamW
args:
lr: 1.e-5
betas: [0.9, 0.99]
eps: 1.e-6
trainer:
num_nodes: 1
max_epochs: 200
log_every_n_steps: 5
num_sanity_val_steps: 1
val_check_interval: 1.0
enable_progress_bar: true
precision: 32
strategy: 'deepspeed_stage_2'
checkpoint:
save_last: true
save_top_k: -1
every_n_epochs: 10
I am encountering a issue where the diffusion model's training loss fails to converge when fine-tuning with LoRA (system.use_lora=True). Instead of decreasing, the loss oscillates significantly throughout the training process.
To isolate the problem, I attempted to fine-tune the model using the minimal example dataset provided (the single object in ./data/shape_diffusion/objaverse). Using the configuration file detailed below, I ran the training for 200 epochs with the command:
CUDA_VISIBLE_DEVICES=0 python train.py --config path/to/config.yaml --train --gpu 0 system.use_lora=True.The expected behavior of a steadily decreasing loss did not occur. Instead, the loss value remained unstable and oscillated for the entire duration, as shown in the attached loss curve.I have confirmed this behavior occurs both when training with labels and without them; neither setup leads to convergence. Interestingly, despite the unstable training, the fine-tuned model checkpoint is able to produce seemingly normal inferences.
This behavior is not limited to the example data. My initial attempt was on a custom dataset built from parnet-mobility objects, which I processed using the
data/watertight_and_sampling.pyscript. During that process, I first encountered a NaN loss, an issue similar to one reported by jseobyun. I resolved the NaN loss by filtering out the problematic sharp_surface data. However, even after fixing the data and retraining for about 100 epochs, the primary issue of the oscillating loss persisted.Since the problem occurs on both a larger custom dataset and the minimal single-object example, I suspect that the issue may originate from the data, the training configuration, or perhaps even the code. I would appreciate any guidance or suggestions on how to resolve this convergence issue.
Loss curvs is as follows

Configuration (step1x-3d-geometry-label-1300m.yaml)