#!/bin/bash # =========================================================================== # remote_sync.sh — Sync UniDriveVLA NVFP4 resources to the quantization server # =========================================================================== # Uploads (via scp) everything needed to run NVFP4 quantization on the remote # server, which has NO internet access to huggingface.co (but pip works via the # Tencent cloud mirror): # 1. HF model cache — owl10/UniDriveVLA_Nusc_Base_Stage1 (bf16 weights, ~4 GB) # 2. HF dataset cache — OpenDriveLab/DriveLM (v1_1_train_nus.json + image zips, ~4.2 GB) # 3. Code — unidrive_vla_nusc_base_quantize_all.py + evaluation.py # 4. Env scripts — prepare_env.sh (run on the server after sync) # # nuScenes images: transferred as the DriveLM image zips # (drivelm_nus_imgs_{train,val}.zip, ~4.2 GB total). They are downloaded to the # local HF cache on first run (if missing) and uploaded as dataset blobs; the # server unzips them into nuscenes/samples/CAM_*/ so load_drivelm_dataset # resolves the multi-view image paths referenced by the JSON. Without these, # calibration/evaluation degrade to text-only input; with them, NVFP4 AWQ # calibration sees real multi-view activations. # # Idempotent: each scp is guarded by a remote existence check, so re-running the # script after a partial/interrupted transfer only uploads what is missing. A single # SSH ControlMaster connection is opened so the password is entered once even though # we run many ssh/scp commands. # # Connection (interactive password — NOT written into this script): # ssh -p 10914 root@43.180.252.174 # Server project dir: /mnt/vepfs/share/GW00387266/MODULES_PLAY # # Usage: # bash remote_sync.sh # upload everything missing, then prompt to run prepare_env.sh # SKIP_PREPARE=1 bash remote_sync.sh # upload only, do not run prepare_env.sh # =========================================================================== set -euo pipefail # --------------------------------------------------------------------------- # Connection config # --------------------------------------------------------------------------- REMOTE_HOST="10.240.97.245" REMOTE_PORT="22" REMOTE_USER="root" REMOTE_PROJECT="/mnt/vepfs/share/GW00387266/MODULES_PLAY" # Remote HF cache root. HF libs read $HF_HOME/hub (default ~/.cache/huggingface). # We place the caches under the project dir (which has 1.1 PB free on /mnt/vepfs) # rather than /root (200 GB), then point HF_HOME there at runtime. REMOTE_HF_HOME="${REMOTE_PROJECT}/hf_home" REMOTE_HF_HUB="${REMOTE_HF_HOME}/hub" # nuScenes images (unzipped from the DriveLM image zips) live here on the server. # load_drivelm_dataset resolves JSON image_paths like "../nuscenes/samples/CAM_FRONT/..." # against img_base; passing --nuscenes_dir points img_base here so the paths resolve. REMOTE_NUSCENES="${REMOTE_PROJECT}/nuscenes" # DriveLM image zips to download (from the OpenDriveLab/DriveLM dataset repo) and # upload. train ~3.48 GB, val ~0.70 GB. Downloaded to the local HF cache first if # missing (so the script works on a fresh machine with internet), then synced as # dataset blobs and unzipped on the server into REMOTE_NUSCENES. DRIVELM_DATASET_REPO="OpenDriveLab/DriveLM" DRIVELM_IMG_ZIPS=("drivelm_nus_imgs_train.zip" "drivelm_nus_imgs_val.zip") # A single SSH control socket so the password is entered once across all commands. SSH_SOCK="$(mktemp -u)/ssh_mux_unidrive" mkdir -p "$(dirname "$SSH_SOCK")" # Common ssh/scp flags. SSH_OPTS=(-o ControlMaster=auto -o ControlPath="$SSH_SOCK" -o ControlPersist=300 -o StrictHostKeyChecking=accept-new -o ServerAliveInterval=30) SSH_BASE=(ssh "${SSH_OPTS[@]}" -p "$REMOTE_PORT" "${REMOTE_USER}@${REMOTE_HOST}") SCP_BASE=(scp "${SSH_OPTS[@]}" -P "$REMOTE_PORT") # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- # Open the master SSH connection (prompts for password here, once). open_ssh_master() { echo "==> Opening SSH master connection to ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}" echo " (enter the server password when prompted; subsequent ssh/scp reuse this connection)" # A no-op remote command establishes the master. -f would background it, but we # keep it foreground-ish: ControlPersist keeps it alive for 300s after we exit. "${SSH_BASE[@]}" -o ConnectTimeout=20 'echo " master connection OK: $(hostname)"' } close_ssh_master() { "${SSH_BASE[@]}" -O exit 2>/dev/null || true rm -f "$SSH_SOCK" } # remote_exists -> echoes "yes"/"no" based on file existence. remote_exists() { local p="$1" local r r=$("${SSH_BASE[@]}" "test -e '$p' && echo yes || echo no" 2>/dev/null | tr -d '[:space:]') echo "${r:-no}" } # remote_size -> echoes file size in bytes (0 if missing). remote_size() { local p="$1" local r r=$("${SSH_BASE[@]}" "stat -c%s '$p' 2>/dev/null || echo 0" 2>/dev/null | tr -d '[:space:]') echo "${r:-0}" } # upload_file