| #!/usr/bin/env bash |
| set -euo pipefail |
|
|
| |
| |
| |
| |
| |
| |
|
|
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| cd "$SCRIPT_DIR" |
|
|
| |
| export AFFECTNET_ROOT="${AFFECTNET_ROOT:-/workspace/data_affectnet/AffectNet}" |
| export AFFECTNET_EXTRACT_ROOT="${AFFECTNET_EXTRACT_ROOT:-${AFFECTNET_ROOT}/extracted}" |
| export AFFECTNET_ANNO_ROOT="${AFFECTNET_ANNO_ROOT:-$SCRIPT_DIR/affectnet_annotations}" |
| export NUM_WORKERS="${NUM_WORKERS:-0}" |
| export BATCHSIZE="${BATCHSIZE:-64}" |
| export TRAIN_ARCHIVE="${TRAIN_ARCHIVE:-${AFFECTNET_ROOT}/train_set.tar}" |
| export VAL_ARCHIVE="${VAL_ARCHIVE:-${AFFECTNET_ROOT}/val_set.zip}" |
| export EXTRACT_ROOT="${EXTRACT_ROOT:-${AFFECTNET_EXTRACT_ROOT}}" |
| export TRAIN_EXTRACT_DIR="${TRAIN_EXTRACT_DIR:-${EXTRACT_ROOT}/train_extracted}" |
| export VAL_EXTRACT_DIR="${VAL_EXTRACT_DIR:-${EXTRACT_ROOT}/val_extracted}" |
| export AUTO_EXTRACT="${AUTO_EXTRACT:-1}" |
|
|
| PY_BIN="${PY_BIN:-python3}" |
| SKIP_PIP_INSTALL="${SKIP_PIP_INSTALL:-0}" |
|
|
| echo "[INFO] SCRIPT_DIR=$SCRIPT_DIR" |
| echo "[INFO] AFFECTNET_ROOT=$AFFECTNET_ROOT" |
| echo "[INFO] AFFECTNET_EXTRACT_ROOT=$AFFECTNET_EXTRACT_ROOT" |
| echo "[INFO] TRAIN_ARCHIVE=$TRAIN_ARCHIVE" |
| echo "[INFO] VAL_ARCHIVE=$VAL_ARCHIVE" |
| echo "[INFO] EXTRACT_ROOT=$EXTRACT_ROOT" |
| echo "[INFO] TRAIN_EXTRACT_DIR=$TRAIN_EXTRACT_DIR" |
| echo "[INFO] VAL_EXTRACT_DIR=$VAL_EXTRACT_DIR" |
| echo "[INFO] AUTO_EXTRACT=$AUTO_EXTRACT" |
| echo "[INFO] AFFECTNET_ANNO_ROOT=$AFFECTNET_ANNO_ROOT" |
| echo "[INFO] NUM_WORKERS=$NUM_WORKERS" |
| echo "[INFO] BATCHSIZE=$BATCHSIZE" |
| echo "[INFO] PY_BIN=$PY_BIN" |
|
|
| has_dataset_layout() { |
| local root="$1" |
| if [[ ! -d "$root" ]]; then |
| return 1 |
| fi |
| if [[ -d "$root/images" && -d "$root/annotations" ]]; then |
| return 0 |
| fi |
| if find "$root" -type d -name images 2>/dev/null | grep -q .; then |
| if find "$root" -type d -name annotations 2>/dev/null | grep -q .; then |
| return 0 |
| fi |
| fi |
| return 1 |
| } |
|
|
| extract_tar_if_needed() { |
| local tar_path="$1" |
| local out_dir="$2" |
| local marker="$out_dir/.extracted_done" |
| mkdir -p "$out_dir" |
| if [[ -f "$marker" ]]; then |
| echo "[SKIP] already extracted: $tar_path" |
| return |
| fi |
| echo "[EXTRACT] $tar_path -> $out_dir" |
| tar -xf "$tar_path" -C "$out_dir" |
| touch "$marker" |
| echo "[DONE] train extracted" |
| } |
|
|
| extract_zip_if_needed() { |
| local zip_path="$1" |
| local out_dir="$2" |
| local marker="$out_dir/.extracted_done" |
| mkdir -p "$out_dir" |
| if [[ -f "$marker" ]]; then |
| echo "[SKIP] already extracted: $zip_path" |
| return |
| fi |
| echo "[EXTRACT] $zip_path -> $out_dir" |
| unzip -q "$zip_path" -d "$out_dir" |
| touch "$marker" |
| echo "[DONE] val extracted" |
| } |
|
|
| if [[ "$SKIP_PIP_INSTALL" != "1" ]]; then |
| echo "[STEP] Installing dependencies" |
| "$PY_BIN" -m pip install -r requirements.txt |
| echo "[STEP] Installing mmcv (required by APViT)" |
| "$PY_BIN" -m pip install mmcv |
| else |
| echo "[STEP] Skipping dependency install (SKIP_PIP_INSTALL=1)" |
| fi |
|
|
| |
| APVIT_PATH="$SCRIPT_DIR/APViT" |
| if [[ ! -d "$APVIT_PATH/.git" ]]; then |
| echo "[STEP] Cloning APViT repo" |
| git clone https://github.com/youqingxiaozhua/APViT.git --depth=1 "$APVIT_PATH" |
| else |
| echo "[SKIP] APViT repo already present at $APVIT_PATH" |
| fi |
|
|
| WEIGHTS_DIR="$APVIT_PATH/weights" |
| mkdir -p "$WEIGHTS_DIR" |
|
|
| VIT_SMALL_W="$WEIGHTS_DIR/vit_small_p16_224-15ec54c9.pth" |
| if [[ ! -f "$VIT_SMALL_W" ]]; then |
| echo "[STEP] Downloading ViT-Small pretrained weights" |
| wget -q -O "$VIT_SMALL_W" \ |
| "https://github.com/rwightman/pytorch-image-models/releases/download/v0.1-weights/vit_small_p16_224-15ec54c9.pth" |
| else |
| echo "[SKIP] ViT-Small weights already present" |
| fi |
|
|
| IR50_W="$WEIGHTS_DIR/backbone_ir50_ms1m_epoch120.pth" |
| if [[ ! -f "$IR50_W" ]]; then |
| echo "[WARNING] IR-50 pretrained weights not found at $IR50_W" |
| echo "[WARNING] Download backbone_ir50_ms1m_epoch120.pth from face.evoLVe model zoo" |
| echo "[WARNING] (https://github.com/ZhaoJ9014/face.evoLVe/#model-zoo) and place it at $IR50_W" |
| echo "[WARNING] Training will proceed with random init for the IR-50 extractor." |
| fi |
| |
|
|
| if [[ ! -f "$AFFECTNET_ANNO_ROOT/train_set_annotation_without_lnd.csv" ]]; then |
| echo "[ERROR] Missing train annotation CSV in $AFFECTNET_ANNO_ROOT" |
| exit 1 |
| fi |
| if [[ ! -f "$AFFECTNET_ANNO_ROOT/val_set_annotation_without_lnd.csv" ]]; then |
| echo "[ERROR] Missing val annotation CSV in $AFFECTNET_ANNO_ROOT" |
| exit 1 |
| fi |
|
|
| train_ready=0 |
| val_ready=0 |
| if has_dataset_layout "$TRAIN_EXTRACT_DIR"; then |
| train_ready=1 |
| fi |
| if has_dataset_layout "$VAL_EXTRACT_DIR"; then |
| val_ready=1 |
| fi |
|
|
| if [[ "$train_ready" -eq 1 && "$val_ready" -eq 1 ]]; then |
| echo "[SKIP] Found existing extracted train/val folders" |
| else |
| if [[ "$AUTO_EXTRACT" != "1" ]]; then |
| echo "[ERROR] Extracted folders not found and AUTO_EXTRACT is disabled" |
| echo "[HINT] Set AUTO_EXTRACT=1 or point TRAIN_EXTRACT_DIR / VAL_EXTRACT_DIR to existing extracted data" |
| exit 1 |
| fi |
|
|
| if [[ ! -f "$TRAIN_ARCHIVE" ]]; then |
| echo "[ERROR] Missing TRAIN_ARCHIVE: $TRAIN_ARCHIVE" |
| exit 1 |
| fi |
| if [[ ! -f "$VAL_ARCHIVE" ]]; then |
| echo "[ERROR] Missing VAL_ARCHIVE: $VAL_ARCHIVE" |
| exit 1 |
| fi |
|
|
| extract_tar_if_needed "$TRAIN_ARCHIVE" "$TRAIN_EXTRACT_DIR" |
| extract_zip_if_needed "$VAL_ARCHIVE" "$VAL_EXTRACT_DIR" |
| fi |
|
|
| echo "[STEP] Train Combined" |
| cd "$SCRIPT_DIR/models/AffectNet8_Maxvit_Combined" |
| "$PY_BIN" train.py |
|
|
| echo "[STEP] Generate Combined inference CSV" |
| "$PY_BIN" generate_csv.py |
|
|
| echo "[STEP] Train VA" |
| cd "$SCRIPT_DIR/models/AffectNet8_Maxvit_VA" |
| "$PY_BIN" train.py |
|
|
| echo "[STEP] Generate VA inference CSV" |
| "$PY_BIN" generate_csv.py |
|
|
| echo "[STEP] Evaluate" |
| cd "$SCRIPT_DIR/models" |
| "$PY_BIN" evaluation.py |
|
|
| echo "[DONE] Full pipeline completed successfully." |
|
|