Add training template: setup.sh
Browse files- training-template/setup.sh +359 -0
training-template/setup.sh
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# ============================================================================
|
| 3 |
+
# Daimon Training β RunPod First-Boot Setup
|
| 4 |
+
# Liberation Labs
|
| 5 |
+
# ============================================================================
|
| 6 |
+
#
|
| 7 |
+
# Run this ONCE on a fresh RunPod pod before training.
|
| 8 |
+
# It installs dependencies, pulls the model & data, and verifies the environment.
|
| 9 |
+
#
|
| 10 |
+
# Requirements:
|
| 11 |
+
# - 1x H200 SXM 141GB
|
| 12 |
+
# - 188GB+ system RAM (critical for CPU-offloaded optimizer)
|
| 13 |
+
# - 400GB+ disk on /workspace (persistent volume)
|
| 14 |
+
# - HF_TOKEN environment variable set (model is gated)
|
| 15 |
+
#
|
| 16 |
+
# Usage:
|
| 17 |
+
# export HF_TOKEN="hf_your_token_here"
|
| 18 |
+
# bash /workspace/runpod-template/setup.sh
|
| 19 |
+
# ============================================================================
|
| 20 |
+
|
| 21 |
+
set -e
|
| 22 |
+
|
| 23 |
+
echo "============================================================"
|
| 24 |
+
echo " DAIMON FULL-PARAMETER SFT β POD SETUP"
|
| 25 |
+
echo " Liberation Labs"
|
| 26 |
+
echo " $(date)"
|
| 27 |
+
echo "============================================================"
|
| 28 |
+
|
| 29 |
+
# ββ 1. Find Python ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 30 |
+
export PATH=/opt/conda/bin:/usr/local/bin:$PATH
|
| 31 |
+
PYTHON=$(which python3.11 2>/dev/null || which python3 2>/dev/null)
|
| 32 |
+
echo "Python: $PYTHON ($($PYTHON --version 2>&1))"
|
| 33 |
+
|
| 34 |
+
# ββ 2. Check GPU ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 35 |
+
echo ""
|
| 36 |
+
echo "=== GPU Check ==="
|
| 37 |
+
GPU_COUNT=$(nvidia-smi --query-gpu=name --format=csv,noheader | wc -l)
|
| 38 |
+
echo "GPUs detected: $GPU_COUNT"
|
| 39 |
+
nvidia-smi --query-gpu=name,memory.total --format=csv,noheader
|
| 40 |
+
|
| 41 |
+
if [ "$GPU_COUNT" -lt 1 ]; then
|
| 42 |
+
echo ""
|
| 43 |
+
echo "FATAL: No GPUs detected."
|
| 44 |
+
exit 1
|
| 45 |
+
fi
|
| 46 |
+
|
| 47 |
+
# Check VRAM (need >= 140GB for full SFT on single GPU)
|
| 48 |
+
VRAM=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1 | tr -d ' ')
|
| 49 |
+
echo "VRAM: ${VRAM} MiB"
|
| 50 |
+
if [ "$VRAM" -lt 140000 ]; then
|
| 51 |
+
echo ""
|
| 52 |
+
echo "FATAL: GPU has ${VRAM} MiB VRAM. Need >= 140,000 MiB."
|
| 53 |
+
echo ""
|
| 54 |
+
echo "Why: Full-parameter SFT memory budget:"
|
| 55 |
+
echo " Model params (bf16): ~70GB β GPU"
|
| 56 |
+
echo " Activations (grad ckpt): ~20GB β GPU"
|
| 57 |
+
echo " Total GPU: ~90GB of 141GB"
|
| 58 |
+
echo ""
|
| 59 |
+
echo "Fix: Provision a pod with 1x H200 SXM 141GB."
|
| 60 |
+
exit 1
|
| 61 |
+
fi
|
| 62 |
+
|
| 63 |
+
# ββ 3. Check system RAM ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 64 |
+
echo ""
|
| 65 |
+
echo "=== System RAM ==="
|
| 66 |
+
TOTAL_RAM=$(free -g | grep Mem | awk '{print $2}')
|
| 67 |
+
echo "Total: ${TOTAL_RAM} GB"
|
| 68 |
+
|
| 69 |
+
# System RAM is CRITICAL for full SFT β optimizer states and gradients are CPU-offloaded
|
| 70 |
+
if [ "$TOTAL_RAM" -lt 180 ]; then
|
| 71 |
+
echo "FATAL: System RAM is ${TOTAL_RAM}GB. Need >= 180GB."
|
| 72 |
+
echo ""
|
| 73 |
+
echo "Why: Full SFT CPU-offloaded memory budget:"
|
| 74 |
+
echo " Gradients (bf16): ~70GB β CPU"
|
| 75 |
+
echo " Adafactor optimizer: ~35GB β CPU"
|
| 76 |
+
echo " Total CPU: ~105GB"
|
| 77 |
+
echo " Plus OS/data overhead: ~30GB"
|
| 78 |
+
echo ""
|
| 79 |
+
echo "AdamW is NOT viable β its fp32 states would need ~280GB CPU RAM."
|
| 80 |
+
echo "Even Adafactor needs ~105GB + headroom."
|
| 81 |
+
echo ""
|
| 82 |
+
echo "Fix: Provision a pod with >= 188GB system RAM."
|
| 83 |
+
exit 1
|
| 84 |
+
fi
|
| 85 |
+
|
| 86 |
+
# ββ 4. Check disk space ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 87 |
+
echo ""
|
| 88 |
+
echo "=== Disk Space ==="
|
| 89 |
+
AVAIL_GB=$(df -BG /workspace | tail -1 | awk '{print $4}' | tr -d 'G')
|
| 90 |
+
echo "Available on /workspace: ${AVAIL_GB} GB"
|
| 91 |
+
|
| 92 |
+
if [ "$AVAIL_GB" -lt 300 ]; then
|
| 93 |
+
echo "FATAL: Less than 300GB on /workspace."
|
| 94 |
+
echo "Full SFT needs: model (~70GB) + data + checkpoints (~210GB for 3 Γ 70GB)."
|
| 95 |
+
echo "Mount a 400GB+ persistent volume."
|
| 96 |
+
exit 1
|
| 97 |
+
elif [ "$AVAIL_GB" -lt 400 ]; then
|
| 98 |
+
echo "WARNING: Less than 400GB on /workspace."
|
| 99 |
+
echo "Full model checkpoints are ~70GB each. With save_total_limit=3, need ~210GB."
|
| 100 |
+
echo "Will be tight β consider a larger volume."
|
| 101 |
+
fi
|
| 102 |
+
|
| 103 |
+
# ββ 5. Check HF_TOKEN ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 104 |
+
echo ""
|
| 105 |
+
echo "=== HuggingFace Authentication ==="
|
| 106 |
+
if [ -z "$HF_TOKEN" ]; then
|
| 107 |
+
echo "FATAL: HF_TOKEN environment variable not set."
|
| 108 |
+
echo "Qwen3.6-35B-A3B is a gated model. You need a HuggingFace token."
|
| 109 |
+
echo ""
|
| 110 |
+
echo "Fix: export HF_TOKEN='hf_your_token_here'"
|
| 111 |
+
echo "Or set it in the RunPod pod template environment variables."
|
| 112 |
+
exit 1
|
| 113 |
+
else
|
| 114 |
+
echo "HF_TOKEN is set (${#HF_TOKEN} chars)"
|
| 115 |
+
fi
|
| 116 |
+
|
| 117 |
+
# ββ 6. Install dependencies (pinned versions) βββββββββββββββββββββββββββββ
|
| 118 |
+
echo ""
|
| 119 |
+
echo "=== Installing Dependencies ==="
|
| 120 |
+
$PYTHON -m pip install --upgrade -q pip
|
| 121 |
+
|
| 122 |
+
echo "Installing PyTorch..."
|
| 123 |
+
$PYTHON -m pip install -q \
|
| 124 |
+
torch==2.7.1 \
|
| 125 |
+
torchvision==0.22.1 \
|
| 126 |
+
--index-url https://download.pytorch.org/whl/cu124 \
|
| 127 |
+
2>&1 | tail -2
|
| 128 |
+
|
| 129 |
+
echo "Installing training stack (pinned versions)..."
|
| 130 |
+
$PYTHON -m pip install -q \
|
| 131 |
+
transformers==5.12.1 \
|
| 132 |
+
trl==1.7.0 \
|
| 133 |
+
datasets==5.0.0 \
|
| 134 |
+
accelerate==1.14.0 \
|
| 135 |
+
deepspeed==0.16.7 \
|
| 136 |
+
safetensors==0.8.0 \
|
| 137 |
+
pyyaml==6.0.2 \
|
| 138 |
+
2>&1 | tail -3
|
| 139 |
+
|
| 140 |
+
echo "Installing flash-attn (may take a few minutes to compile)..."
|
| 141 |
+
$PYTHON -m pip install -q flash-attn --no-build-isolation 2>&1 | tail -3 || {
|
| 142 |
+
echo "WARNING: flash-attn failed to install. Will fall back to SDPA attention."
|
| 143 |
+
echo "This is fine β SDPA is only ~5% slower on H200."
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
echo "Dependencies installed."
|
| 147 |
+
|
| 148 |
+
# ββ 7. Verify critical packages ββββββββββββββββββββββββββββββββββββββββββββ
|
| 149 |
+
echo ""
|
| 150 |
+
echo "=== Package Verification ==="
|
| 151 |
+
$PYTHON -c "
|
| 152 |
+
import torch, transformers, trl, datasets, accelerate, deepspeed, safetensors
|
| 153 |
+
print(f'torch: {torch.__version__}')
|
| 154 |
+
print(f'transformers: {transformers.__version__}')
|
| 155 |
+
print(f'trl: {trl.__version__}')
|
| 156 |
+
print(f'datasets: {datasets.__version__}')
|
| 157 |
+
print(f'accelerate: {accelerate.__version__}')
|
| 158 |
+
print(f'deepspeed: {deepspeed.__version__}')
|
| 159 |
+
print(f'safetensors: {safetensors.__version__}')
|
| 160 |
+
print(f'CUDA: {torch.version.cuda}')
|
| 161 |
+
print(f'GPUs: {torch.cuda.device_count()}')
|
| 162 |
+
try:
|
| 163 |
+
import flash_attn
|
| 164 |
+
print(f'flash_attn: {flash_attn.__version__}')
|
| 165 |
+
except ImportError:
|
| 166 |
+
print('flash_attn: not installed (using SDPA fallback)')
|
| 167 |
+
"
|
| 168 |
+
|
| 169 |
+
# ββ 8. Verify Qwen3.6 architecture support βββββββββββββββββββββββββββββββββ
|
| 170 |
+
echo ""
|
| 171 |
+
echo "=== Model Architecture Check ==="
|
| 172 |
+
MODEL_REVISION="995ad96eacd98c81ed38be0c5b274b04031597b0"
|
| 173 |
+
$PYTHON -c "
|
| 174 |
+
from transformers import AutoConfig
|
| 175 |
+
c = AutoConfig.from_pretrained('Qwen/Qwen3.6-35B-A3B', revision='$MODEL_REVISION', trust_remote_code=True)
|
| 176 |
+
print(f'Model type: {c.model_type}')
|
| 177 |
+
print(f'Hidden size: {c.hidden_size}')
|
| 178 |
+
print(f'Num layers: {c.num_hidden_layers}')
|
| 179 |
+
print(f'Num experts: {getattr(c, \"num_experts\", \"N/A\")}')
|
| 180 |
+
print(f'Vocab size: {c.vocab_size}')
|
| 181 |
+
print(f'Pinned revision: $MODEL_REVISION')
|
| 182 |
+
print('Architecture supported: OK')
|
| 183 |
+
" || {
|
| 184 |
+
echo "FATAL: Qwen3.6 architecture not supported by installed transformers."
|
| 185 |
+
echo "Upgrade: pip install --upgrade transformers"
|
| 186 |
+
exit 1
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
# ββ 9. Pull model from HuggingFace βββββββββββββββββββββββββββββββββββββββββ
|
| 190 |
+
echo ""
|
| 191 |
+
echo "=== Model Download ==="
|
| 192 |
+
MODEL_DIR="/workspace/models/Qwen3.6-35B-A3B"
|
| 193 |
+
if [ -d "$MODEL_DIR" ] && [ -f "$MODEL_DIR/config.json" ]; then
|
| 194 |
+
echo "Model already downloaded at $MODEL_DIR"
|
| 195 |
+
else
|
| 196 |
+
echo "Downloading Qwen3.6-35B-A3B (~70GB, this will take a while)..."
|
| 197 |
+
mkdir -p /workspace/models
|
| 198 |
+
$PYTHON -c "
|
| 199 |
+
from huggingface_hub import snapshot_download
|
| 200 |
+
import os
|
| 201 |
+
snapshot_download(
|
| 202 |
+
'Qwen/Qwen3.6-35B-A3B',
|
| 203 |
+
revision='$MODEL_REVISION',
|
| 204 |
+
local_dir='$MODEL_DIR',
|
| 205 |
+
token=os.environ['HF_TOKEN'],
|
| 206 |
+
)
|
| 207 |
+
print('Model download complete.')
|
| 208 |
+
"
|
| 209 |
+
fi
|
| 210 |
+
|
| 211 |
+
# ββ 10. Pull training data ββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 212 |
+
echo ""
|
| 213 |
+
echo "=== Training Data ==="
|
| 214 |
+
DATA_DIR="/workspace/daimon-data"
|
| 215 |
+
mkdir -p "$DATA_DIR"
|
| 216 |
+
|
| 217 |
+
if [ -d "$DATA_DIR/train_arrow" ] && [ -d "$DATA_DIR/valid_arrow" ]; then
|
| 218 |
+
echo "Arrow data already present. Verifying..."
|
| 219 |
+
$PYTHON -c "
|
| 220 |
+
from datasets import load_from_disk
|
| 221 |
+
t = load_from_disk('$DATA_DIR/train_arrow')
|
| 222 |
+
v = load_from_disk('$DATA_DIR/valid_arrow')
|
| 223 |
+
print(f'Train: {len(t):,} samples | Valid: {len(v):,} samples β OK')
|
| 224 |
+
"
|
| 225 |
+
else
|
| 226 |
+
echo "Downloading and preparing training data..."
|
| 227 |
+
$PYTHON -c "
|
| 228 |
+
import os, json, gzip, shutil
|
| 229 |
+
from huggingface_hub import hf_hub_download, list_repo_files
|
| 230 |
+
from datasets import Dataset, load_dataset
|
| 231 |
+
|
| 232 |
+
DATA_DIR = '$DATA_DIR'
|
| 233 |
+
REPO = 'HumboldtJoker/daimon-sft-data'
|
| 234 |
+
token = os.environ.get('HF_TOKEN')
|
| 235 |
+
|
| 236 |
+
try:
|
| 237 |
+
# Try loading as a HF dataset first
|
| 238 |
+
ds = load_dataset(REPO, token=token)
|
| 239 |
+
if 'train' in ds:
|
| 240 |
+
ds['train'].save_to_disk(f'{DATA_DIR}/train_arrow')
|
| 241 |
+
print(f'Train: {len(ds[\"train\"]):,} samples saved as Arrow')
|
| 242 |
+
if 'validation' in ds:
|
| 243 |
+
ds['validation'].save_to_disk(f'{DATA_DIR}/valid_arrow')
|
| 244 |
+
print(f'Valid: {len(ds[\"validation\"]):,} samples saved as Arrow')
|
| 245 |
+
elif 'test' in ds:
|
| 246 |
+
ds['test'].save_to_disk(f'{DATA_DIR}/valid_arrow')
|
| 247 |
+
print(f'Valid: {len(ds[\"test\"]):,} samples saved as Arrow')
|
| 248 |
+
else:
|
| 249 |
+
# Split train into train/valid
|
| 250 |
+
split = ds['train'].train_test_split(test_size=0.05, seed=42)
|
| 251 |
+
split['train'].save_to_disk(f'{DATA_DIR}/train_arrow')
|
| 252 |
+
split['test'].save_to_disk(f'{DATA_DIR}/valid_arrow')
|
| 253 |
+
print(f'Auto-split: Train {len(split[\"train\"]):,} | Valid {len(split[\"test\"]):,}')
|
| 254 |
+
except Exception as e:
|
| 255 |
+
print(f'HF dataset load failed: {e}')
|
| 256 |
+
print('Trying file-based download...')
|
| 257 |
+
|
| 258 |
+
# Fall back to downloading individual files
|
| 259 |
+
try:
|
| 260 |
+
files = list_repo_files(REPO, repo_type='dataset', token=token)
|
| 261 |
+
for f in files:
|
| 262 |
+
if f.endswith(('.jsonl', '.jsonl.gz', '.json')):
|
| 263 |
+
print(f'Downloading {f}...')
|
| 264 |
+
hf_hub_download(REPO, f, repo_type='dataset', local_dir=DATA_DIR, token=token)
|
| 265 |
+
except Exception as e2:
|
| 266 |
+
print(f'File download also failed: {e2}')
|
| 267 |
+
print('DATA MUST BE UPLOADED MANUALLY to {DATA_DIR}/')
|
| 268 |
+
print('Expected format: JSONL with {\"messages\": [{\"role\": ..., \"content\": ...}, ...]}')
|
| 269 |
+
|
| 270 |
+
# Convert any JSONL files to Arrow
|
| 271 |
+
for split_name in ['train', 'valid']:
|
| 272 |
+
jsonl = f'{DATA_DIR}/{split_name}.jsonl'
|
| 273 |
+
gz = f'{DATA_DIR}/{split_name}.jsonl.gz'
|
| 274 |
+
arrow_dir = f'{DATA_DIR}/{split_name}_arrow'
|
| 275 |
+
|
| 276 |
+
if os.path.exists(gz) and not os.path.exists(jsonl):
|
| 277 |
+
with gzip.open(gz, 'rb') as fin, open(jsonl, 'wb') as fout:
|
| 278 |
+
shutil.copyfileobj(fin, fout)
|
| 279 |
+
|
| 280 |
+
if os.path.exists(jsonl) and not os.path.exists(arrow_dir):
|
| 281 |
+
data = []
|
| 282 |
+
with open(jsonl) as fh:
|
| 283 |
+
for line in fh:
|
| 284 |
+
line = line.strip()
|
| 285 |
+
if not line:
|
| 286 |
+
continue
|
| 287 |
+
try:
|
| 288 |
+
d = json.loads(line)
|
| 289 |
+
if 'messages' in d and len(d['messages']) >= 2:
|
| 290 |
+
data.append(d)
|
| 291 |
+
except:
|
| 292 |
+
pass
|
| 293 |
+
ds = Dataset.from_list(data)
|
| 294 |
+
ds.save_to_disk(arrow_dir)
|
| 295 |
+
print(f'{split_name}: {len(data):,} examples saved as Arrow')
|
| 296 |
+
|
| 297 |
+
# Final verification
|
| 298 |
+
try:
|
| 299 |
+
from datasets import load_from_disk
|
| 300 |
+
t = load_from_disk(f'{DATA_DIR}/train_arrow')
|
| 301 |
+
print(f'Verified train: {len(t):,} samples')
|
| 302 |
+
if os.path.isdir(f'{DATA_DIR}/valid_arrow'):
|
| 303 |
+
v = load_from_disk(f'{DATA_DIR}/valid_arrow')
|
| 304 |
+
print(f'Verified valid: {len(v):,} samples')
|
| 305 |
+
except:
|
| 306 |
+
print('WARNING: Could not verify data. Check $DATA_DIR manually.')
|
| 307 |
+
"
|
| 308 |
+
fi
|
| 309 |
+
|
| 310 |
+
# ββ 11. Create persistent directories ββββββββββββββββββββββββββββββββββββββ
|
| 311 |
+
echo ""
|
| 312 |
+
echo "=== Creating Directories ==="
|
| 313 |
+
mkdir -p /workspace/daimon-sft/logs
|
| 314 |
+
mkdir -p /workspace/daimon-sft/checkpoints
|
| 315 |
+
echo "Output directories created on persistent volume."
|
| 316 |
+
|
| 317 |
+
# ββ 12. Copy template files to /workspace βββββββββββββββββββββββββββββββββββ
|
| 318 |
+
echo ""
|
| 319 |
+
echo "=== Copying Template Files ==="
|
| 320 |
+
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
| 321 |
+
cp "$SCRIPT_DIR/train_daimon.py" /workspace/runpod-template/train_daimon.py 2>/dev/null || true
|
| 322 |
+
cp "$SCRIPT_DIR/train_daimon_config.yaml" /workspace/runpod-template/train_daimon_config.yaml 2>/dev/null || true
|
| 323 |
+
cp "$SCRIPT_DIR/ds_config_zero2.json" /workspace/runpod-template/ds_config_zero2.json 2>/dev/null || true
|
| 324 |
+
cp "$SCRIPT_DIR/launch.sh" /workspace/runpod-template/launch.sh 2>/dev/null || true
|
| 325 |
+
cp "$SCRIPT_DIR/test_template.py" /workspace/runpod-template/test_template.py 2>/dev/null || true
|
| 326 |
+
echo "Template files in /workspace/runpod-template/"
|
| 327 |
+
|
| 328 |
+
# ββ 13. Add SSH key for remote access ββββββββββββββββββββββββββββββββββββββ
|
| 329 |
+
echo ""
|
| 330 |
+
echo "=== SSH Key ==="
|
| 331 |
+
mkdir -p ~/.ssh
|
| 332 |
+
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtjekz8l1s6xTAXlhZJg/A0N3d6mZAyF/EyrEMiBCDG thomas@coalition" >> ~/.ssh/authorized_keys
|
| 333 |
+
chmod 700 ~/.ssh
|
| 334 |
+
chmod 600 ~/.ssh/authorized_keys
|
| 335 |
+
echo "SSH key added."
|
| 336 |
+
|
| 337 |
+
# ββ 14. Clean up HF token from disk cache ββββββββββββββββββββββββββββββββββ
|
| 338 |
+
echo ""
|
| 339 |
+
echo "=== Security Cleanup ==="
|
| 340 |
+
rm -f ~/.cache/huggingface/token 2>/dev/null || true
|
| 341 |
+
echo "Cleared cached HF token from disk."
|
| 342 |
+
|
| 343 |
+
# ββ 15. Summary βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 344 |
+
echo ""
|
| 345 |
+
echo "============================================================"
|
| 346 |
+
echo " SETUP COMPLETE β FULL-PARAMETER SFT"
|
| 347 |
+
echo ""
|
| 348 |
+
echo " Memory budget:"
|
| 349 |
+
echo " GPU: ~90GB of 141GB (model + activations)"
|
| 350 |
+
echo " CPU: ~105GB of ${TOTAL_RAM}GB (gradients + Adafactor)"
|
| 351 |
+
echo ""
|
| 352 |
+
echo " Next steps:"
|
| 353 |
+
echo " 1. Run validation: python3 /workspace/runpod-template/test_template.py"
|
| 354 |
+
echo " 2. Start training: bash /workspace/runpod-template/launch.sh"
|
| 355 |
+
echo ""
|
| 356 |
+
echo " Monitor:"
|
| 357 |
+
echo " watch -n 5 nvidia-smi"
|
| 358 |
+
echo " tail -f /workspace/daimon-sft/logs/training_*.log"
|
| 359 |
+
echo "============================================================"
|