#!/usr/bin/env bash # # Re-run every experiment invalidated by removing the assessment event token, # requiring train-split RobustScale, and deleting the mixed distribution. # # The workflow runs: # 1. seed-42 full factorial experiments; # 2. seed-43/44 key-model experiments; # 3. seed-42/43/44 disease-history T/O/S ablation; # 4. seed-42/43/44 assessment + smoking + alcohol experiment; # 5. AUC and calibration evaluation for all four campaigns. set -euo pipefail SCRIPT_DIR="${BASH_SOURCE[0]%/*}" if [[ "$SCRIPT_DIR" == "${BASH_SOURCE[0]}" ]]; then SCRIPT_DIR="." fi SCRIPT_DIR="$(cd -- "$SCRIPT_DIR" && pwd)" cd "$SCRIPT_DIR" NUM_GPUS=1 NUM_GPUS_SET=0 GPU_CSV="" NUM_CPUS=16 PYTHON_BIN="${PYTHON_BIN:-python}" BASH_BIN="${BASH:-bash}" DRY_RUN=0 FULL_FACTORIAL_CAMPAIGN="full_factorial_smoking_alcohol_bmi" KEY_MODELS_CAMPAIGN="key_models_multiseed_smoking_alcohol_bmi" HISTORY_CAMPAIGN="disease_history_ablation_no_extra" EXTRA_INFO_CAMPAIGN="extra_info_assessment_smoking_alcohol_robust_multiseed" usage() { cat <<'EOF' Usage: bash rerun_all_required_experiments_linux.sh [options] Options: --num-gpus N Number of GPUs; uses GPU ids 0 through N-1 (default: 1). --gpus LIST Explicit comma-separated GPU ids, for example 0,2. Cannot be combined with --num-gpus. --num-cpus N Total CPU workers shared across active GPUs (default: 16). --python PATH Python executable used by every child script. --dry-run Print commands without training or evaluation. -h, --help Show this help message. Examples: bash rerun_all_required_experiments_linux.sh --num-gpus 1 --num-cpus 16 bash rerun_all_required_experiments_linux.sh --num-gpus 4 --num-cpus 32 bash rerun_all_required_experiments_linux.sh --gpus 0,2 --num-cpus 16 CPU allocation: The script divides --num-cpus evenly across simultaneously active GPUs. For example, 4 GPUs and 32 CPUs gives each GPU job 8 workers. EOF } while (($# > 0)); do case "$1" in --num-gpus) [[ $# -ge 2 ]] || { echo "ERROR: --num-gpus requires a value." >&2 exit 2 } [[ -z "$GPU_CSV" ]] || { echo "ERROR: --num-gpus cannot be combined with --gpus." >&2 exit 2 } NUM_GPUS="$2" NUM_GPUS_SET=1 shift 2 ;; --gpus) [[ $# -ge 2 ]] || { echo "ERROR: --gpus requires a value." >&2 exit 2 } ((NUM_GPUS_SET == 0)) || { echo "ERROR: --gpus cannot be combined with --num-gpus." >&2 exit 2 } GPU_CSV="$2" shift 2 ;; --num-cpus) [[ $# -ge 2 ]] || { echo "ERROR: --num-cpus requires a value." >&2 exit 2 } NUM_CPUS="$2" shift 2 ;; --python) [[ $# -ge 2 ]] || { echo "ERROR: --python requires a value." >&2 exit 2 } PYTHON_BIN="$2" shift 2 ;; --dry-run) DRY_RUN=1 shift ;; -h|--help) usage exit 0 ;; *) echo "ERROR: unknown argument: $1" >&2 usage >&2 exit 2 ;; esac done [[ "$NUM_GPUS" =~ ^[1-9][0-9]*$ ]] || { echo "ERROR: --num-gpus must be a positive integer." >&2 exit 2 } [[ "$NUM_CPUS" =~ ^[1-9][0-9]*$ ]] || { echo "ERROR: --num-cpus must be a positive integer." >&2 exit 2 } if [[ -z "$GPU_CSV" ]]; then for ((gpu_id = 0; gpu_id < NUM_GPUS; gpu_id++)); do if [[ -n "$GPU_CSV" ]]; then GPU_CSV+="," fi GPU_CSV+="$gpu_id" done else IFS=',' read -r -a GPU_IDS <<< "$GPU_CSV" NUM_GPUS="${#GPU_IDS[@]}" ((NUM_GPUS > 0)) || { echo "ERROR: --gpus must not be empty." >&2 exit 2 } for gpu_id in "${GPU_IDS[@]}"; do [[ "$gpu_id" =~ ^[0-9]+$ ]] || { echo "ERROR: invalid GPU id: $gpu_id" >&2 exit 2 } done fi ((NUM_CPUS >= NUM_GPUS)) || { echo "ERROR: --num-cpus must be at least the number of GPUs." >&2 exit 2 } WORKERS_PER_GPU=$((NUM_CPUS / NUM_GPUS)) required_scripts=( train_batch_linux.sh train_key_models_multiseed_linux.sh train_disease_history_ablation_linux.sh train_extra_info_assessment_all_multiseed_linux.sh evaluate_all_runs_linux.sh evaluate_calibration_all_runs_linux.sh ) for script in "${required_scripts[@]}"; do [[ -f "$SCRIPT_DIR/$script" ]] || { echo "ERROR: missing required script: $SCRIPT_DIR/$script" >&2 exit 2 } done run_command() { printf '>>' printf ' %q' "$@" printf '\n' if ((DRY_RUN == 0)); then "$@" fi } echo "GPUs: $GPU_CSV ($NUM_GPUS total)" echo "CPUs: $NUM_CPUS total; $WORKERS_PER_GPU workers per GPU job" echo "Python: $PYTHON_BIN" run_command "$BASH_BIN" "$SCRIPT_DIR/train_batch_linux.sh" \ --gpus "$GPU_CSV" \ --seed 42 \ --num-workers "$WORKERS_PER_GPU" \ --python "$PYTHON_BIN" run_command "$BASH_BIN" "$SCRIPT_DIR/train_key_models_multiseed_linux.sh" \ --gpus "$GPU_CSV" \ --seeds 43,44 \ --num-workers "$WORKERS_PER_GPU" \ --python "$PYTHON_BIN" run_command "$BASH_BIN" "$SCRIPT_DIR/train_disease_history_ablation_linux.sh" \ --gpus "$GPU_CSV" \ --seeds 42,43,44 \ --num-workers "$WORKERS_PER_GPU" \ --python "$PYTHON_BIN" run_command "$BASH_BIN" "$SCRIPT_DIR/train_extra_info_assessment_all_multiseed_linux.sh" \ --gpus "$GPU_CSV" \ --seeds 42,43,44 \ --num-workers "$WORKERS_PER_GPU" \ --python "$PYTHON_BIN" campaigns=( "$FULL_FACTORIAL_CAMPAIGN" "$KEY_MODELS_CAMPAIGN" "$HISTORY_CAMPAIGN" "$EXTRA_INFO_CAMPAIGN" ) for campaign in "${campaigns[@]}"; do runs_root="$SCRIPT_DIR/runs/$campaign" run_command "$BASH_BIN" "$SCRIPT_DIR/evaluate_all_runs_linux.sh" \ --gpus "$GPU_CSV" \ --runs-root "$runs_root" \ --log-root "$SCRIPT_DIR/batch_logs/evaluate_all_required/$campaign" \ --python "$PYTHON_BIN" \ --num-workers "$WORKERS_PER_GPU" \ --num-workers-auc "$WORKERS_PER_GPU" run_command "$BASH_BIN" "$SCRIPT_DIR/evaluate_calibration_all_runs_linux.sh" \ --gpus "$GPU_CSV" \ --runs-root "$runs_root" \ --log-root "$SCRIPT_DIR/batch_logs/evaluate_calibration_all_required/$campaign" \ --python "$PYTHON_BIN" \ --num-workers "$WORKERS_PER_GPU" \ --num-workers-calibration "$WORKERS_PER_GPU" done echo "All required re-training and evaluation workflows completed."