#!/bin/bash # Run native eSEN fine-tuning directly or submit it to Slurm. set -euo pipefail DEMO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ESEN_DIR="$(cd "$DEMO_DIR/.." && pwd)" PARSER="$DEMO_DIR/_parse_config.py" CONFIG="" SUBMIT=false while [[ $# -gt 0 ]]; do case "$1" in --config) CONFIG="$2"; shift 2 ;; --config=*) CONFIG="${1#*=}"; shift ;; --submit) SUBMIT=true; shift ;; -h|--help) echo "Usage: bash demo/run.sh --config configs/.yaml" echo "Set launch.mode: submit in YAML to submit a Slurm job." exit 0 ;; *) echo "Unknown argument: $1" >&2; exit 2 ;; esac done [[ -n "$CONFIG" ]] || { echo "Please specify --config configs/.yaml" >&2; exit 2; } [[ "$CONFIG" = /* ]] || CONFIG="$DEMO_DIR/$CONFIG" [[ -f "$CONFIG" ]] || { echo "Config not found: $CONFIG" >&2; exit 2; } if [[ -z "${CONDA_PREFIX:-}" ]]; then echo "Activate a OneScience MatChem conda environment before running this script." >&2 exit 2 fi export ESEN_REPO_DIR="$ESEN_DIR" export ESEN_DATASET_DIR="${ESEN_DATASET_DIR:-$ESEN_DIR/datasets/oxides}" export ONESCIENCE_ESEN_JD_PATH="${ONESCIENCE_ESEN_JD_PATH:-$ESEN_DIR/weight/Jd.pt}" NAME="$(python3 "$PARSER" "$CONFIG" name)" eval "$(python3 "$PARSER" "$CONFIG" launch)" eval "$(python3 "$PARSER" "$CONFIG" slurm)" ENV_EXPORTS="$(python3 "$PARSER" "$CONFIG" env)" if [[ "$RUN_MODE" == "submit" ]]; then SUBMIT=true fi if ! $SUBMIT; then AUTO_SUBMIT_REASON="" if (( NODES > 1 )); then AUTO_SUBMIT_REASON="the config requests $NODES nodes" else AVAILABLE_GPUS="$(python3 -c 'import torch; print(torch.cuda.device_count() if torch.cuda.is_available() else 0)' 2>/dev/null || echo 0)" if (( AVAILABLE_GPUS < GPUS_PER_NODE )); then AUTO_SUBMIT_REASON="the config requests $GPUS_PER_NODE DCUs but only $AVAILABLE_GPUS are visible" fi fi if [[ -n "$AUTO_SUBMIT_REASON" ]]; then if ! command -v sbatch >/dev/null 2>&1; then echo "Cannot run locally: $AUTO_SUBMIT_REASON, and sbatch is unavailable." >&2 exit 2 fi echo "Local resources are insufficient: $AUTO_SUBMIT_REASON. Submitting to Slurm." SUBMIT=true fi fi TIMESTAMP="$(date +%Y%m%d_%H%M%S)" OUTPUT_ROOT="${ESEN_OUTPUT_ROOT:-$ESEN_DIR/outputs}" OUTPUT_DIR="$OUTPUT_ROOT/${NAME}_${TIMESTAMP}" mkdir -p "$OUTPUT_DIR/checkpoints" cp "$CONFIG" "$OUTPUT_DIR/config.yaml" FINETUNE_CONFIG="$OUTPUT_DIR/finetune.yaml" python3 "$PARSER" "$CONFIG" finetune-config > "$FINETUNE_CONFIG" if $SUBMIT; then SLURM_SCRIPT="$OUTPUT_DIR/submit.sh" cat > "$SLURM_SCRIPT" <> "$SLURM_SCRIPT" < 1 )); then unset HIP_VISIBLE_DEVICES fi $ENV_EXPORTS cd "$OUTPUT_DIR" EOF if (( NODES > 1 )); then cat >> "$SLURM_SCRIPT" < 1 )); then cat >> "$SLURM_SCRIPT" <> "$SLURM_SCRIPT" fi chmod u+x "$SLURM_SCRIPT" echo "Submitting eSEN job: $SLURM_SCRIPT" sbatch "$SLURM_SCRIPT" exit 0 fi eval "$ENV_EXPORTS" cd "$OUTPUT_DIR" if (( GPUS_PER_NODE > 1 )); then exec torchrun --standalone --nproc_per_node="$GPUS_PER_NODE" \ "$ESEN_DIR/finetune.py" --config "$FINETUNE_CONFIG" fi exec python "$ESEN_DIR/finetune.py" --config "$FINETUNE_CONFIG"