Download apptainer/python.sh from jeffry77/track_env: direct link, hf CLI and curl.
- Browser
- Download file 6.28 kB
-
https://huggingface.co/jeffry77/track_env/resolve/main/apptainer/python.sh
- Command line
-
hf download hf://jeffry77/track_env/apptainer/python.sh
-
curl -L -o python.sh https://huggingface.co/jeffry77/track_env/resolve/main/apptainer/python.sh
6.28 kB
| # Drop-in PYTHON_BIN for scripts/train_2node_16gpu.slurm. One container per node; | |
| # train_large.py launches eight workers using container sys.executable. | |
| set +x # Never trace runtime credentials, including if launched with bash -x. | |
| set -euo pipefail | |
| HERE="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" | |
| if [[ "${1:-}" == --help-container ]]; then | |
| echo 'IMAGE=/path/environment.sif PROJECT_DIR=/shared/checkout apptainer/python.sh [Python arguments]' | |
| echo 'Optional: DATA_DIR MODEL_DIR ASSET_DIR OUTPUT_DIR CONTAINER_CACHE_DIR WANDB_NETRC_FILE GPUS=all|none DRY_RUN=1.' | |
| echo 'Stage0 external assets: LORAT_ROOT LORAT_WEIGHT_PATH TORCH_HOME (existing host paths, automatically bound).' | |
| echo 'Credentials are forwarded through the environment only; dry-run redacts values.' | |
| exit 0 | |
| fi | |
| ROOT="$(cd -- "${PROJECT_DIR:-${TRACK_ANYTHING_ROOT:-$HERE/..}}" && pwd)" | |
| test -f "$ROOT/scripts/train_large.py" || { echo 'PROJECT_DIR must be the large-training checkout.' >&2; exit 2; } | |
| test -f "$ROOT/apptainer/entrypoint.sh" || { echo 'PROJECT_DIR must include apptainer/entrypoint.sh.' >&2; exit 2; } | |
| : "${IMAGE:?Set IMAGE to the built large-cu128-wandb-v1 SIF}" | |
| IMAGE="$(realpath -e -- "$IMAGE")" | |
| test -f "$IMAGE" || { echo 'IMAGE must be a regular SIF file.' >&2; exit 2; } | |
| CACHE="$(realpath -m -- "${CONTAINER_CACHE_DIR:-$ROOT/.container-cache}")" | |
| check_path() { [[ "$2" != *:* && "$2" != *,* && "$2" != *$'\n'* ]] || { echo "$1 cannot contain colon, comma or newline." >&2; exit 2; }; } | |
| for name in ROOT CACHE; do check_path "$name" "${!name}"; done | |
| args=(exec --cleanenv --no-eval --no-home --no-mount home,cwd,hostfs,bind-paths | |
| --pwd "$ROOT" --bind "$ROOT:$ROOT" --bind "$CACHE:/cache") | |
| for name in DATA_DIR MODEL_DIR ASSET_DIR OUTPUT_DIR; do | |
| value="${!name:-}" | |
| if [[ -n "$value" ]]; then | |
| test -d "$value" || { echo "$name must already exist on each node." >&2; exit 2; } | |
| value="$(cd -- "$value" && pwd)"; check_path "$name" "$value" | |
| if [[ "$name" == OUTPUT_DIR ]]; then mode=rw; else mode=ro; fi | |
| args+=(--bind "$value:$value:$mode") | |
| fi | |
| done | |
| # --cleanenv drops host asset settings, and --no-mount disables implicit host | |
| # binds. Resolve both the forwarded value and its bind from the SAME path; | |
| # canonicalization also handles symlinks whose targets leave the checkout. | |
| # Bind only the weight file, not its possibly private parent directory. | |
| for name in LORAT_ROOT LORAT_WEIGHT_PATH TORCH_HOME; do | |
| value="${!name:-}" | |
| if [[ -z "$value" && "$name" == LORAT_ROOT && -d "$ROOT/third_party/LoRAT/trackit" ]]; then | |
| value="$ROOT/third_party/LoRAT" | |
| fi | |
| if [[ -n "$value" ]]; then | |
| if [[ "$name" == LORAT_WEIGHT_PATH ]]; then | |
| test -f "$value" || { echo "$name must be an existing file on each node." >&2; exit 2; } | |
| else | |
| test -d "$value" || { echo "$name must be an existing directory on each node." >&2; exit 2; } | |
| fi | |
| value="$(realpath -e -- "$value")"; check_path "$name" "$value" | |
| if [[ "$name" == LORAT_ROOT ]]; then | |
| test -d "$value/trackit" || { echo 'LORAT_ROOT must contain the LoRAT trackit package.' >&2; exit 2; } | |
| fi | |
| if [[ "$name" == TORCH_HOME ]]; then mode=rw; else mode=ro; fi | |
| args+=(--bind "$value:$value:$mode") | |
| printf -v "$name" '%s' "$value" | |
| export "$name" | |
| else | |
| # An empty optional setting means use the image/application default; it | |
| # must not overwrite TORCH_HOME=/cache/torch with an empty string. | |
| unset "$name" | |
| fi | |
| done | |
| if [[ -n "${WANDB_NETRC_FILE:-}" ]]; then | |
| test -f "$WANDB_NETRC_FILE" || { echo 'WANDB_NETRC_FILE must be an existing private credentials file.' >&2; exit 2; } | |
| value="$(realpath -e -- "$WANDB_NETRC_FILE")"; check_path WANDB_NETRC_FILE "$value" | |
| args+=(--bind "$value:/cache/home/.netrc:ro") | |
| fi | |
| unset APPTAINER_HOME SINGULARITY_HOME APPTAINER_BIND APPTAINER_BINDPATH SINGULARITY_BIND SINGULARITY_BINDPATH | |
| # Do not inherit arbitrary APPTAINERENV_ or SINGULARITYENV_ variables, especially | |
| # an old PYTHONPATH, HOME, or an accidental conflicting CUDA_VISIBLE_DEVICES. | |
| while IFS= read -r variable; do | |
| case "$variable" in APPTAINERENV_*|SINGULARITYENV_*) unset "$variable" ;; esac | |
| done < <(compgen -e) | |
| export APPTAINERENV_TRACK_ANYTHING_ROOT="$ROOT" | |
| export APPTAINERENV_WANDB_MODE="${WANDB_MODE:-online}" | |
| case "$APPTAINERENV_WANDB_MODE" in online|offline|disabled) ;; *) echo 'Invalid WANDB_MODE.' >&2; exit 2 ;; esac | |
| case "${GPUS:-all}" in | |
| none) export APPTAINERENV_CUDA_VISIBLE_DEVICES=-1 ;; | |
| all) | |
| args+=(--nv) | |
| if [[ "${CUDA_VISIBLE_DEVICES+x}" ]]; then export APPTAINERENV_CUDA_VISIBLE_DEVICES="$CUDA_VISIBLE_DEVICES"; fi | |
| ;; | |
| *) echo 'GPUS must be all (allocated set) or none; use the scheduler to allocate GPUs.' >&2; exit 2 ;; | |
| esac | |
| forward=(SLURM_NODEID SLURM_JOB_ID SLURM_JOB_NUM_NODES SLURM_NNODES SLURM_LOCALID | |
| MASTER_ADDR MASTER_PORT NODE_RANK TRACKING_SMOKE_RUN_ID | |
| NCCL_DEBUG NCCL_DEBUG_SUBSYS NCCL_SOCKET_IFNAME NCCL_SOCKET_FAMILY | |
| NCCL_IB_HCA NCCL_IB_GID_INDEX NCCL_IB_TC NCCL_IB_TIMEOUT NCCL_IB_DISABLE | |
| NCCL_NET_GDR_LEVEL NCCL_CUMEM_ENABLE NCCL_P2P_DISABLE | |
| TORCH_DISTRIBUTED_DEBUG TORCH_NCCL_ASYNC_ERROR_HANDLING | |
| LORAT_ROOT LORAT_WEIGHT_PATH TORCH_HOME | |
| WANDB_API_KEY WANDB_BASE_URL WANDB_ENTITY | |
| HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY http_proxy https_proxy all_proxy no_proxy) | |
| for variable in "${forward[@]}"; do | |
| if [[ "${!variable+x}" ]]; then | |
| export "APPTAINERENV_${variable}=${!variable}" | |
| fi | |
| done | |
| # Keep the environment-only SIF reusable: launch the checked-out entrypoint so | |
| # runtime fixes do not depend on rebuilding an already published image. | |
| args+=("$IMAGE" /bin/bash "$ROOT/apptainer/entrypoint.sh" /opt/venv/bin/python "$@") | |
| if [[ "${DRY_RUN:-0}" == 1 ]]; then | |
| printf 'Container command (environment values omitted): ' | |
| printf '%q ' "${APPTAINER:-apptainer}" "${args[@]}"; printf '\n' | |
| printf 'Forwarded environment names only:' | |
| for variable in "${forward[@]}"; do | |
| if [[ "${!variable+x}" ]]; then printf ' %s' "$variable"; fi | |
| done | |
| printf '\nNo process launched.\n' | |
| exit 0 | |
| fi | |
| command -v "${APPTAINER:-apptainer}" >/dev/null || { echo 'Load/install Apptainer on each node first.' >&2; exit 127; } | |
| umask 077 | |
| mkdir -p -- "$CACHE/home" | |
| exec "${APPTAINER:-apptainer}" "${args[@]}" | |