Download scripts/sft_aesthetic.sh from MHHHH02/PortraitMT: direct link, hf CLI and curl.
- Browser
- Download file 7.38 kB
-
https://huggingface.co/MHHHH02/PortraitMT/resolve/main/scripts/sft_aesthetic.sh
- Command line
-
hf download hf://MHHHH02/PortraitMT/scripts/sft_aesthetic.sh
-
curl -L -o sft_aesthetic.sh https://huggingface.co/MHHHH02/PortraitMT/resolve/main/scripts/sft_aesthetic.sh
7.38 kB
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Training script for aesthetic scoring with custom score tokens. | |
| # | |
| # Each image is expanded into 14 independent samples: | |
| # - 13 per-criterion samples (score range 1β10, bins=crit_score_bins) | |
| # - 1 total-score sample (score range 0β100, bins=total_score_bins) | |
| # | |
| # Assistant output format (per sample): | |
| # <think>{reason}</think> | |
| # The score is <scoreK> β criteria sample | |
| # | |
| # The score is <totalK> β total sample | |
| # | |
| # Loss = CE_loss + crit_reg_weight * Huber(criteria) + total_reg_weight * Huber(total) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # export CUDA_VISIBLE_DEVICES=0 | |
| # ββ Distributed configuration (auto-detect) ββββββββββββββββββββββββββββββββββ | |
| MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} | |
| MASTER_PORT=${MASTER_PORT:-$(shuf -i 20001-29999 -n 1)} | |
| NNODES=${WORLD_SIZE:-1} | |
| if [ -z "$NPROC_PER_NODE" ]; then | |
| if command -v nvidia-smi &> /dev/null; then | |
| NPROC_PER_NODE=$(nvidia-smi --list-gpus | wc -l) | |
| else | |
| NPROC_PER_NODE=1 | |
| fi | |
| fi | |
| export DS_BUILD_SHM_COMM=0 # Disable building shared memory communication ops | |
| export DS_BUILD_OPS=0 # Disable building ops to avoid compilation errors | |
| # ββ Paths βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Base model: Qwen3-VL-8B or a previously fine-tuned checkpoint | |
| # LLM=/mnt/hdfs/zw04mlnn01/checkpoint/llm_platform/hldy/model/Qwen/Qwen3-VL-8B-Instruct/main | |
| LLM= | |
| # Image root directory (must contain all image_path entries in track_1_train.json) | |
| IMAGE_DIR=zijielou/PortraitCraft/main | |
| # Annotation file (image_path uses subdir format: images_00/xxx.jpg) | |
| ANNOTATION=PortraitCraft/track_1_train_subdir.json | |
| # Output | |
| RUN_NAME="qwen3vl_aesthetic_score_tokens_0509" | |
| OUTPUT_DIR=result/portrait/${RUN_NAME} | |
| # DeepSpeed config | |
| DEEPSPEED=./scripts/zero2.json | |
| # ββ Hyper-parameters ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| LR=2e-5 | |
| BATCH_SIZE=2 # per GPU | |
| GRAD_ACCUM=16 # effective batch = NPROC_PER_NODE * BATCH_SIZE * GRAD_ACCUM | |
| NUM_EPOCHS=3 | |
| # ββ Score token settings ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CRIT_BINS=20 # <score1>β¦<score20> covering 1.0β10.0 | |
| TOTAL_BINS=101 # <total1>β¦<total101> covering 0β100 | |
| # ββ Loss weights ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CE_WEIGHT=1.0 | |
| CRIT_REG_WEIGHT=0.5 # regression loss weight for criteria samples | |
| TOTAL_REG_WEIGHT=0.5 # regression loss weight for total-score samples | |
| REG_LOSS_TYPE=huber # huber | mse | |
| # ββ Image resolution ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MAX_PIXELS=$((32 * 32 * 1024)) # ~451k pixels (~672px side) | |
| MIN_PIXELS=$((32 * 32 * 224)) # ~12k pixels | |
| IMAGE_MAX_TOKEN_NUM=1024 | |
| # ββ Entry point βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ENTRY=qwenvl/train/train_qwen.py | |
| # ββ Update aesthetic data path in data registry βββββββββββββββββββββββββββββββ | |
| # Patch the image_dir at runtime via environment variable so we don't hard-code | |
| # it inside __init__.py. The AestheticScoringDataset reads IMAGE_DIR if set. | |
| export AESTHETIC_IMAGE_DIR=${IMAGE_DIR} | |
| export AESTHETIC_ANNOTATION=${ANNOTATION} | |
| export WANDB_DISABLED=true | |
| # ββ Auto-compute save_steps = half epoch ββββββββββββββββββββββββββββββββββββββ | |
| NUM_IMAGES=$(python -c "import json; print(len(json.load(open('${ANNOTATION}'))))") | |
| SAMPLES_PER_IMAGE=14 # 13 criteria + 1 total | |
| TOTAL_SAMPLES=$((NUM_IMAGES * SAMPLES_PER_IMAGE)) | |
| EFFECTIVE_BATCH=$((NPROC_PER_NODE * NNODES * BATCH_SIZE * GRAD_ACCUM)) | |
| STEPS_PER_EPOCH=$(( (TOTAL_SAMPLES + EFFECTIVE_BATCH - 1) / EFFECTIVE_BATCH )) | |
| SAVE_STEPS=$(( STEPS_PER_EPOCH / 2 )) | |
| [ ${SAVE_STEPS} -lt 1 ] && SAVE_STEPS=1 | |
| echo "[auto] ${NUM_IMAGES} images Γ ${SAMPLES_PER_IMAGE} = ${TOTAL_SAMPLES} samples" | |
| echo "[auto] effective_batch=${EFFECTIVE_BATCH}, steps/epoch=${STEPS_PER_EPOCH}, save_steps=${SAVE_STEPS} (half epoch)" | |
| # ββ Training arguments ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ARGS=" | |
| --model_name_or_path ${LLM} \ | |
| --use_score_tokens True \ | |
| --crit_score_bins ${CRIT_BINS} \ | |
| --total_score_bins ${TOTAL_BINS} \ | |
| --score_ce_weight ${CE_WEIGHT} \ | |
| --crit_reg_weight ${CRIT_REG_WEIGHT} \ | |
| --total_reg_weight ${TOTAL_REG_WEIGHT} \ | |
| --tune_mm_vision True \ | |
| --tune_mm_mlp True \ | |
| --tune_mm_llm True \ | |
| --bf16 True \ | |
| --output_dir ${OUTPUT_DIR} \ | |
| --num_train_epochs ${NUM_EPOCHS} \ | |
| --per_device_train_batch_size ${BATCH_SIZE} \ | |
| --per_device_eval_batch_size $((BATCH_SIZE * 2)) \ | |
| --gradient_accumulation_steps ${GRAD_ACCUM} \ | |
| --max_pixels ${MAX_PIXELS} \ | |
| --min_pixels ${MIN_PIXELS} \ | |
| --eval_strategy no \ | |
| --save_strategy steps \ | |
| --save_steps ${SAVE_STEPS} \ | |
| --save_total_limit 6 \ | |
| --learning_rate ${LR} \ | |
| --weight_decay 0.0 \ | |
| --warmup_ratio 0.03 \ | |
| --max_grad_norm 2.0 \ | |
| --lr_scheduler_type cosine \ | |
| --logging_steps 1 \ | |
| --model_max_length 4096 \ | |
| --gradient_checkpointing False \ | |
| --dataloader_num_workers 4 \ | |
| --run_name ${RUN_NAME} \ | |
| --sample_every_steps 500 \ | |
| --report_to none \ | |
| --deepspeed ${DEEPSPEED} | |
| " | |
| # ββ Launch ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| mkdir -p ${OUTPUT_DIR} | |
| echo "============================================================" | |
| echo " GPUs: ${NPROC_PER_NODE}, Nodes: ${NNODES}" | |
| echo " Master: ${MASTER_ADDR}:${MASTER_PORT}" | |
| echo " Output: ${OUTPUT_DIR}" | |
| echo "============================================================" | |
| torchrun \ | |
| --nproc_per_node=${NPROC_PER_NODE} \ | |
| --nnodes=${NNODES} \ | |
| --master_addr=${MASTER_ADDR} \ | |
| --master_port=${MASTER_PORT} \ | |
| ${ENTRY} ${ARGS} 2>&1 | tee ${OUTPUT_DIR}/train.log | |