icarus112 commited on
Commit
7186879
·
verified ·
1 Parent(s): 28df7d8

Update Feather H200 training runtime image

Browse files
Dockerfile CHANGED
@@ -22,7 +22,29 @@ RUN pip install --upgrade pip setuptools wheel && \
22
  rustbpe \
23
  pandas \
24
  tiktoken \
25
- pydantic
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  WORKDIR /workspace
28
  COPY overlay /workspace/feather
 
22
  rustbpe \
23
  pandas \
24
  tiktoken \
25
+ pydantic \
26
+ ninja \
27
+ packaging \
28
+ einops \
29
+ triton==3.2.0
30
+
31
+ # Mamba-3 fused CUDA kernel stack (mandatory — NO fallback allowed).
32
+ # causal-conv1d must be installed BEFORE mamba-ssm. CUDA_HOME is required so the
33
+ # build can find nvcc; TORCH_CUDA_ARCH_LIST targets Hopper (H100/H200) sm_90a
34
+ # plus Ada (L4/A10G) sm_89 so the same image runs on any HF Jobs flavor we pick.
35
+ ENV CUDA_HOME=/usr/local/cuda \
36
+ TORCH_CUDA_ARCH_LIST="8.9;9.0" \
37
+ MAMBA_FORCE_BUILD=TRUE \
38
+ CAUSAL_CONV1D_FORCE_BUILD=TRUE \
39
+ MAX_JOBS=4
40
+
41
+ RUN pip install --no-build-isolation 'causal-conv1d>=1.4.0' && \
42
+ pip install --no-build-isolation 'mamba-ssm[causal-conv1d]>=2.2.5' && \
43
+ python -c "from mamba_ssm import Mamba3; print('mamba_ssm Mamba3 import OK')"
44
+
45
+ # Optional tilelang for MIMO path — wrap in || true because some flavors may not
46
+ # need it; single-pass SISO Mamba3 still runs without it.
47
+ RUN pip install tilelang || echo "[dockerfile] tilelang optional install failed — continuing"
48
 
49
  WORKDIR /workspace
50
  COPY overlay /workspace/feather
README.md CHANGED
@@ -1,10 +1,11 @@
1
  ---
2
- title: Feather H200 Runtime
3
- emoji: 😻
4
- colorFrom: green
5
- colorTo: purple
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Feather H200 Runtime Slim
3
+ emoji: 📚
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ Feather runtime image used as a Docker Space source for Hugging Face Jobs.
__pycache__/entrypoint.cpython-312.pyc CHANGED
Binary files a/__pycache__/entrypoint.cpython-312.pyc and b/__pycache__/entrypoint.cpython-312.pyc differ
 
entrypoint.py CHANGED
@@ -1,7 +1,13 @@
1
  #!/usr/bin/env python3
 
 
 
2
  import os
3
  import subprocess
 
 
4
  from pathlib import Path
 
5
 
6
  from huggingface_hub import HfApi
7
 
@@ -11,6 +17,38 @@ LOG_FILE = REPO_ROOT / 'run_domain_expanded.log'
11
  JOB_ID = os.environ.get('JOB_ID', 'local-job')
12
  OUTPUT_REPO = os.environ.get('HF_REPO_ID', 'icarus112/feather-pretrain-checkpoints')
13
  TOKEN = os.environ.get('HF_TOKEN')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
 
16
  def upload_artifact(api: HfApi, path: Path, dest: str) -> None:
@@ -26,7 +64,7 @@ def upload_artifact(api: HfApi, path: Path, dest: str) -> None:
26
  print(f'[upload] uploaded {path} -> {OUTPUT_REPO}/{dest}', flush=True)
27
 
28
 
29
- def main() -> int:
30
  os.chdir(REPO_ROOT)
31
  os.environ.setdefault('HYDRA_TIME_BUDGET', '43200')
32
  os.environ.setdefault('HYDRA_TARGET_SHARDS', '2048')
@@ -35,6 +73,7 @@ def main() -> int:
35
  os.environ.setdefault('HYDRA_RESUME_CKPT', str(CACHE_ROOT / 'latest.pt'))
36
 
37
  cmd = [
 
38
  './scripts/run_domain_expanded_pretrain.sh',
39
  '--target-shards', os.environ['HYDRA_TARGET_SHARDS'],
40
  '--download-workers', os.environ['HYDRA_DOWNLOAD_WORKERS'],
@@ -62,5 +101,22 @@ def main() -> int:
62
  return proc.returncode
63
 
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  if __name__ == '__main__':
66
  raise SystemExit(main())
 
1
  #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
  import os
6
  import subprocess
7
+ import time
8
+ from http.server import BaseHTTPRequestHandler, HTTPServer
9
  from pathlib import Path
10
+ from threading import Thread
11
 
12
  from huggingface_hub import HfApi
13
 
 
17
  JOB_ID = os.environ.get('JOB_ID', 'local-job')
18
  OUTPUT_REPO = os.environ.get('HF_REPO_ID', 'icarus112/feather-pretrain-checkpoints')
19
  TOKEN = os.environ.get('HF_TOKEN')
20
+ RUNTIME_MODE = os.environ.get('FEATHER_RUNTIME_MODE', 'space')
21
+ APP_PORT = int(os.environ.get('PORT', '7860'))
22
+
23
+
24
+ class _HealthHandler(BaseHTTPRequestHandler):
25
+ def do_GET(self):
26
+ if self.path in ('/', '/health', '/healthz', '/ready'):
27
+ payload = {
28
+ 'status': 'ok',
29
+ 'mode': RUNTIME_MODE,
30
+ 'job_id': JOB_ID,
31
+ }
32
+ body = json.dumps(payload).encode('utf-8')
33
+ self.send_response(200)
34
+ self.send_header('Content-Type', 'application/json')
35
+ self.send_header('Content-Length', str(len(body)))
36
+ self.end_headers()
37
+ self.wfile.write(body)
38
+ return
39
+ self.send_response(404)
40
+ self.end_headers()
41
+
42
+ def log_message(self, format, *args):
43
+ return
44
+
45
+
46
+ def _start_health_server() -> HTTPServer:
47
+ server = HTTPServer(('0.0.0.0', APP_PORT), _HealthHandler)
48
+ thread = Thread(target=server.serve_forever, daemon=True)
49
+ thread.start()
50
+ print(f'[space] health server listening on 0.0.0.0:{APP_PORT}', flush=True)
51
+ return server
52
 
53
 
54
  def upload_artifact(api: HfApi, path: Path, dest: str) -> None:
 
64
  print(f'[upload] uploaded {path} -> {OUTPUT_REPO}/{dest}', flush=True)
65
 
66
 
67
+ def run_job_mode() -> int:
68
  os.chdir(REPO_ROOT)
69
  os.environ.setdefault('HYDRA_TIME_BUDGET', '43200')
70
  os.environ.setdefault('HYDRA_TARGET_SHARDS', '2048')
 
73
  os.environ.setdefault('HYDRA_RESUME_CKPT', str(CACHE_ROOT / 'latest.pt'))
74
 
75
  cmd = [
76
+ 'bash',
77
  './scripts/run_domain_expanded_pretrain.sh',
78
  '--target-shards', os.environ['HYDRA_TARGET_SHARDS'],
79
  '--download-workers', os.environ['HYDRA_DOWNLOAD_WORKERS'],
 
101
  return proc.returncode
102
 
103
 
104
+ def run_space_mode() -> int:
105
+ server = _start_health_server()
106
+ print('[space] Feather runtime image ready', flush=True)
107
+ try:
108
+ while True:
109
+ time.sleep(3600)
110
+ finally:
111
+ server.shutdown()
112
+ server.server_close()
113
+
114
+
115
+ def main() -> int:
116
+ if RUNTIME_MODE == 'job':
117
+ return run_job_mode()
118
+ return run_space_mode()
119
+
120
+
121
  if __name__ == '__main__':
122
  raise SystemExit(main())
overlay/hydra/__pycache__/mamba3_fallback.cpython-312.pyc ADDED
Binary file (8.85 kB). View file
 
overlay/hydra/__pycache__/model.cpython-312.pyc CHANGED
Binary files a/overlay/hydra/__pycache__/model.cpython-312.pyc and b/overlay/hydra/__pycache__/model.cpython-312.pyc differ
 
overlay/hydra/model.py CHANGED
@@ -35,6 +35,7 @@ import os
35
  import torch
36
  import torch.nn as nn
37
  import torch.nn.functional as F
 
38
  from mamba_ssm import Mamba3
39
 
40
  from subsystems.hestia_mini import HestiaQAT
@@ -70,7 +71,7 @@ class PostSemClawModel(nn.Module):
70
  # Token embedding
71
  self.wte = nn.Embedding(config.vocab_size, config.d_model)
72
 
73
- # Mamba-3 blocks (official mamba-ssm with CUDA parallel scan kernel)
74
  self.blocks = nn.ModuleList([
75
  Mamba3(
76
  d_model=config.d_model,
 
35
  import torch
36
  import torch.nn as nn
37
  import torch.nn.functional as F
38
+
39
  from mamba_ssm import Mamba3
40
 
41
  from subsystems.hestia_mini import HestiaQAT
 
71
  # Token embedding
72
  self.wte = nn.Embedding(config.vocab_size, config.d_model)
73
 
74
+ # Mamba-3 blocks (official mamba-ssm with CUDA parallel scan kernel — no fallbacks, no bypasses).
75
  self.blocks = nn.ModuleList([
76
  Mamba3(
77
  d_model=config.d_model,
overlay/subsystems/__pycache__/sdr_retina.cpython-312.pyc ADDED
Binary file (24.7 kB). View file
 
overlay/subsystems/sdr_retina.py CHANGED
@@ -61,7 +61,7 @@ TARGET_ACTIVE = int(N_BITS * TARGET_SPARSITY) # 327
61
 
62
  CONTEXT_WINDOW = 8 # +/- 8 tokens
63
  TOP_K_FEATURES = 64 # top-K context features per token
64
- TARGET_TRAIN_TOKENS = 10_000_000 # scan this many tokens from parquet
65
  MAX_DOCS_PER_SHARD = 200_000 # safety cap per shard
66
 
67
  # Kohonen SOM
@@ -498,105 +498,4 @@ def build_retina(target_tokens: int = TARGET_TRAIN_TOKENS) -> BuildReport:
498
  )
499
 
500
 
501
- # ---------------------------------------------------------------------------
502
- # Validation
503
- # ---------------------------------------------------------------------------
504
-
505
- def _jaccard(a: np.ndarray, b: np.ndarray) -> float:
506
- inter = int(np.logical_and(a, b).sum())
507
- uni = int(np.logical_or(a, b).sum())
508
- if uni == 0:
509
- return 0.0
510
- return inter / uni
511
-
512
-
513
- def _token_id_for_word(tokenizer: Tokenizer, word: str) -> int:
514
- """Return the single-token id for a leading-space word if possible.
515
- We try " word" first (BPE merges usually favor space-prefixed single tokens),
516
- then bare "word", then take the first token of the encoding as a fallback.
517
- """
518
- for candidate in (" " + word, word):
519
- ids = tokenizer.enc.encode_ordinary(candidate)
520
- if len(ids) == 1:
521
- return ids[0]
522
- # Fallback: use the first token id of the bare word, with a warning.
523
- ids = tokenizer.enc.encode_ordinary(word)
524
- return ids[0]
525
-
526
-
527
- def validate_retina() -> bool:
528
- print("[validate] loading retina...")
529
- with np.load(RETINA_PATH) as f:
530
- sdr = f["sdr"]
531
- vocab_size = int(f["vocab_size"])
532
- n_bits = int(f["n_bits"])
533
- assert sdr.shape == (vocab_size, n_bits), f"bad shape {sdr.shape}"
534
- per_row = sdr.sum(axis=1)
535
- print(f"[validate] shape={sdr.shape} active/row min/max={int(per_row.min())}/{int(per_row.max())} "
536
- f"mean={per_row.mean():.1f}")
537
-
538
- tokenizer = Tokenizer.from_directory(TOKENIZER_DIR)
539
-
540
- pairs = [
541
- ("the", "a", "zebra"),
542
- ("man", "woman", "rock"),
543
- ("king", "queen", "dinosaur"),
544
- ]
545
- all_pass = True
546
- print(f"\n{'pair':<30}{'close':>10}{'far':>10}{'passed?':>10}")
547
- print("-" * 60)
548
- for anchor, close_w, far_w in pairs:
549
- a_id = _token_id_for_word(tokenizer, anchor)
550
- c_id = _token_id_for_word(tokenizer, close_w)
551
- f_id = _token_id_for_word(tokenizer, far_w)
552
- j_close = _jaccard(sdr[a_id], sdr[c_id])
553
- j_far = _jaccard(sdr[a_id], sdr[f_id])
554
- passed = j_close > j_far
555
- all_pass = all_pass and passed
556
- print(f"{anchor!r:<10} vs {close_w!r:<8} / {far_w!r:<8}"
557
- f"{j_close:>10.4f}{j_far:>10.4f}{'PASS' if passed else 'FAIL':>10}")
558
- # also print the ids we used, for debuggability
559
- print(f" token ids: {anchor!r}={a_id} {close_w!r}={c_id} {far_w!r}={f_id}")
560
-
561
- if all_pass:
562
- print("\n[validate] ALL 3 overlap tests PASSED")
563
- else:
564
- print("\n[validate] ONE OR MORE TESTS FAILED")
565
- return all_pass
566
-
567
-
568
- # ---------------------------------------------------------------------------
569
- # Entry point
570
- # ---------------------------------------------------------------------------
571
-
572
- def main():
573
- parser = argparse.ArgumentParser(description="Build / validate the semantic-folding SDR retina.")
574
- parser.add_argument("--build", action="store_true", help="Build retina.npz from the corpus.")
575
- parser.add_argument("--validate", action="store_true", help="Run analogy overlap tests against retina.npz.")
576
- parser.add_argument("--target-tokens", type=int, default=TARGET_TRAIN_TOKENS,
577
- help="Approximate number of tokens to stream for cooccurrence.")
578
- parser.add_argument("--epochs", type=int, default=SOM_EPOCHS, help="Kohonen SOM epochs.")
579
- parser.add_argument("--top-k", type=int, default=TOP_K_FEATURES,
580
- help="Top-K context features per token (PMI).")
581
- args = parser.parse_args()
582
-
583
- if not args.build and not args.validate:
584
- parser.error("specify --build and/or --validate")
585
-
586
- # Override module-level knobs used inside the pipeline with CLI values.
587
- globals()["SOM_EPOCHS"] = int(args.epochs)
588
- globals()["TOP_K_FEATURES"] = int(args.top_k)
589
-
590
- if args.build:
591
- build_retina(target_tokens=args.target_tokens)
592
-
593
- ok = True
594
- if args.validate:
595
- ok = validate_retina()
596
-
597
- if not ok:
598
- sys.exit(1)
599
-
600
 
601
- if __name__ == "__main__":
602
- main()
 
61
 
62
  CONTEXT_WINDOW = 8 # +/- 8 tokens
63
  TOP_K_FEATURES = 64 # top-K context features per token
64
+ TARGET_TRAIN_TOKENS = 10000000 # scan this many tokens from parquet
65
  MAX_DOCS_PER_SHARD = 200_000 # safety cap per shard
66
 
67
  # Kohonen SOM
 
498
  )
499
 
500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501