tensorfold-1017-prepare.sh 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/env bash
  2. # tensorfold-1017-prepare — host-side staging for the TensorFold 2x 1017 lane.
  3. #
  4. # Idempotent: every step is skipped when its output already exists. Runs on
  5. # each launch node before the containers start (recipe `before_serve`), with
  6. # NODE_RANK exported by the launcher.
  7. #
  8. # Everything here works WITHOUT the image: the launcher runs pre-serve hooks
  9. # *before* it builds/syncs the image, so the helper files (Engram packer, chat
  10. # template, CUDA prebuild inputs) are published to the NAS by the recipe image's
  11. # build.sh. The one image-dependent step (CUDA prebuild) is skipped when the
  12. # image is not on this node yet and simply runs on the next serve.
  13. #
  14. # Steps
  15. # 1. node-local copy of the EXL3 2.9bpw checkpoint (EXL3 streams weights on
  16. # every decode step — reading them off the NAS costs most of the decode);
  17. # 2. the chat template the TensorFold HTTP app requires at init (the EXL3
  18. # checkpoint carries none);
  19. # 3. the per-rank Engram packs (layers 1 + 14, ~47 GiB each) built from the
  20. # official 1017 shards 47/48 — rank r owns hash heads [12r, 12r+12);
  21. # 4. the CUDA extension prebuild (CPU-only, 18/18 builders) when the image is
  22. # already present.
  23. #
  24. # Overrides (env): TF1017_ROOT (default /home/kilork/ns/1017-tf),
  25. # TF1017_NAS (default /mnt/nas/ai/huggingface/hub), TF1017_IMAGE,
  26. # TF1017_SKIP_WEIGHTS=1, TF1017_SKIP_PACK=1, TF1017_SKIP_PREBUILD=1.
  27. set -euo pipefail
  28. ROOT="${TF1017_ROOT:-/home/kilork/ns/1017-tf}"
  29. NAS="${TF1017_NAS:-/mnt/nas/ai/huggingface/hub}"
  30. PUB="${TF1017_PUB:-/mnt/nas/ai/sm121/dsv41-tf-1017}"
  31. IMG="${TF1017_IMAGE:-dsv41-tf-1017:v1}"
  32. RANK="${NODE_RANK:-0}"
  33. REV="${TF1017_MODEL_REV:-afc7aa0aab98ee735c0f54e0a122019af1ac08f1}"
  34. EREV="${TF1017_ENGRAM_REV:-1bae0e1088993b9b82de08f59de5be5a34e42170}"
  35. WBUNDLE="$NAS/models--LibertAIDAI--DeepSeek-V4.1-Flash-1017-EXL3-2.9bpw/snapshots/$REV"
  36. EBUNDLE="$NAS/models--deepseek-ai--DeepSeek-V4.1-Flash-1017/snapshots/$EREV"
  37. CKPT="$ROOT/models/checkpoint"
  38. PACKED="$ROOT/engram-packed-1017"
  39. CACHE="$ROOT/cache"
  40. HELP="$ROOT/helpers"
  41. mkdir -p "$CKPT" "$PACKED" "$CACHE" "$HELP" "$ROOT/state"
  42. echo "[tf1017] rank $RANK — root $ROOT"
  43. # 0. helper files (published to the NAS by the image's build.sh) -------------
  44. for f in pack_engram.py prebuild_ext.py prebuild-offline.py pfdense-table.json \
  45. chat_template.jinja; do
  46. if [[ ! -s "$HELP/$f" ]]; then
  47. if [[ -s "$PUB/$f" ]]; then
  48. cp -f "$PUB/$f" "$HELP/$f"
  49. elif docker image inspect "$IMG" >/dev/null 2>&1; then
  50. docker run --rm --network none --entrypoint cat "$IMG" "/opt/sm121-helpers/$f" > "$HELP/$f"
  51. else
  52. echo "[tf1017] FATAL: $f not published at $PUB and image $IMG absent" >&2
  53. exit 1
  54. fi
  55. fi
  56. done
  57. # 1. weights -----------------------------------------------------------------
  58. if [[ "${TF1017_SKIP_WEIGHTS:-0}" != "1" ]]; then
  59. have=$(find "$CKPT" -maxdepth 1 -name '*.safetensors' | wc -l)
  60. if [[ "$have" -lt 43 ]]; then
  61. echo "[tf1017] copying EXL3 checkpoint from the NAS ($have/43 shards present)"
  62. tar -chf - -C "$WBUNDLE" . | tar -xf - -C "$CKPT"
  63. fi
  64. have=$(find "$CKPT" -maxdepth 1 -name '*.safetensors' | wc -l)
  65. [[ "$have" -ge 43 ]] || { echo "[tf1017] FATAL: checkpoint incomplete ($have/43)" >&2; exit 1; }
  66. fi
  67. # 2. chat template -----------------------------------------------------------
  68. [[ -s "$CKPT/chat_template.jinja" ]] || cp "$HELP/chat_template.jinja" "$CKPT/chat_template.jinja"
  69. # 3. per-rank Engram packs (host python + numpy; no image needed) ------------
  70. if [[ "${TF1017_SKIP_PACK:-0}" != "1" ]]; then
  71. if [[ ! -s "$PACKED/engram-l14-r${RANK}of2.bin" ]]; then
  72. python3 -c 'import numpy' 2>/dev/null || python3 -m pip install --user --quiet numpy
  73. echo "[tf1017] packing Engram tables for rank $RANK (~94 GiB, reads 189 GiB from the NAS)"
  74. python3 "$HELP/pack_engram.py" \
  75. --src "$EBUNDLE" --config "$CKPT/config.json" \
  76. --out "$PACKED" --rank "$RANK"
  77. fi
  78. [[ -s "$PACKED/engram-l1-r${RANK}of2.bin" && -s "$PACKED/engram-l14-r${RANK}of2.bin" ]] \
  79. || { echo "[tf1017] FATAL: Engram packs missing for rank $RANK" >&2; exit 1; }
  80. fi
  81. # 4. CUDA extension prebuild (needs the image; skipped on a first serve) -----
  82. if [[ "${TF1017_SKIP_PREBUILD:-0}" != "1" && ! -s "$CACHE/pfdense-table.json" ]]; then
  83. if docker image inspect "$IMG" >/dev/null 2>&1; then
  84. echo "[tf1017] prebuilding CUDA extensions (CPU-only)"
  85. docker run --rm --network none --memory 8g --cpus 4 \
  86. -e CUDA_VISIBLE_DEVICES= -e TORCH_CUDA_ARCH_LIST=12.1 -e MAX_JOBS=4 \
  87. -e TORCH_EXTENSIONS_DIR=/cache/torch_extensions \
  88. -v "$CACHE":/cache \
  89. -v "$HELP/prebuild-offline.py":/offline.py:ro \
  90. -v "$HELP/prebuild_ext.py":/prebuild.py:ro \
  91. -v "$HELP/pfdense-table.json":/table.json:ro \
  92. --entrypoint bash "$IMG" \
  93. -c 'python /offline.py && cp /table.json /cache/pfdense-table.json'
  94. else
  95. echo "[tf1017] image $IMG not on this node yet — extensions will compile at first start"
  96. fi
  97. fi
  98. echo "[tf1017] rank $RANK ready"