#!/bin/bash # DreamZero DROID Training Script with Wan2.2-TI2V-5B backbone # # Usage: # bash scripts/train/droid_training_wan22.sh # # Prerequisites: # - DROID dataset in LeRobot format at DROID_DATA_ROOT # Download: huggingface-cli download GEAR-Dreams/DreamZero-DROID-Data --repo-type dataset --local-dir ./data/droid_lerobot # - Wan2.2-TI2V-5B weights (download from HuggingFace) # huggingface-cli download Wan-AI/Wan2.2-TI2V-5B --local-dir ./checkpoints/Wan2.2-TI2V-5B # - Image encoder (CLIP) from Wan2.1 - Wan2.2-TI2V-5B does not include it # Option A: huggingface-cli download Wan-AI/Wan2.1-I2V-14B-480P --local-dir ./checkpoints/Wan2.1-I2V-14B-480P # Option B: Set IMAGE_ENCODER_DIR to a path containing models_clip_open-clip-xlm-roberta-large-vit-huge-14.pth # - umt5-xxl tokenizer (auto-downloaded or pre-downloaded) # huggingface-cli download google/umt5-xxl --local-dir ./checkpoints/umt5-xxl export HYDRA_FULL_ERROR=1 # Repo root: must be a directory that contains groot/ (so experiment.py can be found). # Beaker/weka uses /root/yejink/dreamzero; image has /root/dreamzero; else script location. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" if [ -n "$DREAMZERO_ROOT" ] && [ -d "$DREAMZERO_ROOT/groot" ]; then : # keep existing and valid elif [ -d "/root/yejink/dreamzero/groot" ]; then DREAMZERO_ROOT=/root/yejink/dreamzero elif [ -d "/root/dreamzero/groot" ]; then DREAMZERO_ROOT=/root/dreamzero elif [ -d "$SCRIPT_REPO_ROOT/groot" ]; then DREAMZERO_ROOT="$SCRIPT_REPO_ROOT" else DREAMZERO_ROOT="${DREAMZERO_ROOT:-/root/yejink/dreamzero}" fi if [ ! -d "$DREAMZERO_ROOT/groot" ]; then echo "ERROR: No groot/ under $DREAMZERO_ROOT. Set DREAMZERO_ROOT to the dreamzero repo root that contains groot/." exit 1 fi # ============ USER CONFIGURATION ============ NUM_GPUS=${NUM_GPUS:-8} DROID_DATA_ROOT=${DROID_DATA_ROOT:-"$DREAMZERO_ROOT/data/droid_lerobot"} # If env set the old relative default, resolve to repo root (e.g. Beaker image env) if [ "$DROID_DATA_ROOT" = "./data/droid_lerobot" ]; then DROID_DATA_ROOT="$DREAMZERO_ROOT/data/droid_lerobot" fi OUTPUT_DIR=${OUTPUT_DIR:-"$DREAMZERO_ROOT/checkpoints/dreamzero_droid_wan22_lora"} # Wan2.2-TI2V-5B checkpoint (contains: diffusion weights, T5, VAE) WAN22_CKPT_DIR=${WAN22_CKPT_DIR:-"$DREAMZERO_ROOT/checkpoints/Wan2.2-TI2V-5B"} # Image encoder: Wan2.2-TI2V-5B does NOT include CLIP - use Wan2.1's or standalone IMAGE_ENCODER_DIR=${IMAGE_ENCODER_DIR:-"$DREAMZERO_ROOT/checkpoints/Wan2.1-I2V-14B-480P"} TOKENIZER_DIR=${TOKENIZER_DIR:-"$DREAMZERO_ROOT/checkpoints/umt5-xxl"} # ============================================= # ============ AUTO-DOWNLOAD WEIGHTS ============ if [ ! -d "$WAN22_CKPT_DIR" ] || [ -z "$(ls -A "$WAN22_CKPT_DIR" 2>/dev/null)" ]; then echo "Wan2.2-TI2V-5B not found at $WAN22_CKPT_DIR. Downloading from HuggingFace..." huggingface-cli download Wan-AI/Wan2.2-TI2V-5B --local-dir "$WAN22_CKPT_DIR" fi if [ ! -d "$TOKENIZER_DIR" ] || [ -z "$(ls -A "$TOKENIZER_DIR" 2>/dev/null)" ]; then echo "umt5-xxl tokenizer not found at $TOKENIZER_DIR. Downloading from HuggingFace..." huggingface-cli download google/umt5-xxl --local-dir "$TOKENIZER_DIR" fi # Image encoder: download Wan2.1 if not present (only need CLIP from it) if [ ! -f "$IMAGE_ENCODER_DIR/models_clip_open-clip-xlm-roberta-large-vit-huge-14.pth" ]; then echo "Image encoder not found. Downloading Wan2.1-I2V-14B-480P (for CLIP only)..." huggingface-cli download Wan-AI/Wan2.1-I2V-14B-480P --local-dir "$IMAGE_ENCODER_DIR" fi # ================================================ # Validate dataset exists if [ ! -d "$DROID_DATA_ROOT" ]; then echo "ERROR: DROID dataset not found at $DROID_DATA_ROOT" echo "Download with: huggingface-cli download GEAR-Dreams/DreamZero-DROID-Data --repo-type dataset --local-dir $DROID_DATA_ROOT" exit 1 fi # Use image Python 3.11 when available (Dockerfile installs dreamzero with python3.11 -m pip). # Absolute path so worker processes open the correct file even if their cwd differs. EXPERIMENT_PY="$DREAMZERO_ROOT/groot/vla/experiment/experiment.py" if [ ! -f "$EXPERIMENT_PY" ]; then echo "ERROR: Not found: $EXPERIMENT_PY" exit 1 fi PYTHON_311="/usr/bin/python3.11" if [ -x "$PYTHON_311" ]; then if [ -n "${FIX_NUMPY_IN_SCRIPT:-}" ]; then "$PYTHON_311" -m pip install "numpy==1.26.4" --force-reinstall -q 2>/dev/null || true fi RUN_CMD=( "$PYTHON_311" -m torch.distributed.run --nproc_per_node "$NUM_GPUS" --standalone "$EXPERIMENT_PY" ) echo "Using image Python 3.11: $PYTHON_311" else RUN_CMD=( python3 -m torch.distributed.run --nproc_per_node "$NUM_GPUS" --standalone "$EXPERIMENT_PY" ) echo "Using: $(command -v python3)" fi cd "$DREAMZERO_ROOT" "${RUN_CMD[@]}" \ report_to=wandb \ data=dreamzero/droid_relative_wan22 \ wandb_project=dreamzero \ train_architecture=lora \ num_frames=33 \ action_horizon=24 \ num_views=3 \ model=dreamzero/vla \ model/dreamzero/action_head=wan_flow_matching_action_tf_wan22 \ model/dreamzero/transform=dreamzero_cotrain \ num_frame_per_block=2 \ num_action_per_block=24 \ num_state_per_block=1 \ seed=42 \ training_args.learning_rate=1e-5 \ training_args.deepspeed="groot/vla/configs/deepspeed/zero2.json" \ save_steps=1000 \ training_args.warmup_ratio=0.05 \ output_dir=$OUTPUT_DIR \ per_device_train_batch_size=1 \ max_steps=100 \ weight_decay=1e-5 \ save_total_limit=10 \ upload_checkpoints=false \ bf16=true \ tf32=true \ eval_bf16=true \ dataloader_pin_memory=false \ dataloader_num_workers=1 \ save_lora_only=true \ max_chunk_size=4 \ save_strategy=no \ droid_data_root=$DROID_DATA_ROOT \ dit_version=$WAN22_CKPT_DIR \ text_encoder_pretrained_path=$WAN22_CKPT_DIR/models_t5_umt5-xxl-enc-bf16.pth \ image_encoder_pretrained_path=$IMAGE_ENCODER_DIR/models_clip_open-clip-xlm-roberta-large-vit-huge-14.pth \ vae_pretrained_path=$WAN22_CKPT_DIR/Wan2.2_VAE.pth \ tokenizer_path=$TOKENIZER_DIR