-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
147 lines (118 loc) · 5.82 KB
/
Copy pathMakefile
File metadata and controls
147 lines (118 loc) · 5.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Anbani/word-embeddings — deterministic orchestration.
#
# Three stages (mirrors Anbani/homoglyph):
# stage 1 corpus -> vocab -> embed HEAVY. GPU forward passes. Node Docker only.
# stage 2 reduce -> dist CPU. Runs on the node right after embed
# (raw f32 vectors are large and live in work/ there), or locally from
# a rsync'd work/ backup. Emits the committed dist/.
# stage 3 evaluate + tests CPU. The gate; also runs in CI against the
# committed dist (probe metrics come from dist/neighbors.bin — no raw
# vectors needed, so CI can validate without the node artifacts).
#
# Parameterize per dataset/corpus: make embed DS=kawiki-eg make vocab CORPUS=kawiki
PYTHON ?= python3
export PYTHONHASHSEED = 0
export PYTHONUTF8 = 1
CORPUS ?= kawiki
DS ?= kawiki-eg
.PHONY: all corpus vocab embed reduce dist evaluate test stage1 stage2 clean \
docker-build-generate docker-build-build \
gpu-sync gpu-stage1 gpu-stage2 gpu-logs gpu-stop gpu-fetch
all: evaluate
# ---- stage 1 (heavy, GPU node) ---------------------------------------------
## corpus: ZIM / poem -> work/<corpus>/sentences.jsonl
corpus:
$(PYTHON) src/extract_corpus.py --corpus $(CORPUS)
## vocab: sentences -> work/<corpus>/{vocab.jsonl, form2lemma.json, occ.jsonl}
vocab:
$(PYTHON) src/build_vocab.py --corpus $(CORPUS)
## collapse: merge inflectional variants to one root per point (frozen vocab).
## Runs BEFORE embed for a fresh model; for an already-embedded run pass VECTORS
## to subselect existing vectors (no re-embed):
## make collapse CORPUS=kawiki VECTORS=work/kawiki-eg/vectors.f32.npy
collapse:
$(PYTHON) src/collapse_vocab.py --corpus $(CORPUS) $(if $(VECTORS),--vectors $(VECTORS),)
## embed: model forward passes -> work/<DS>/vectors.f32.npy (needs GPU)
embed:
$(PYTHON) src/embed_contextual.py --config $(DS)
# ---- stage 2 (CPU) ----------------------------------------------------------
## reduce: full-dim vectors -> UMAP-2D + alignment -> work/<DS>/layout.npz
reduce:
$(PYTHON) src/reduce_layout.py --config $(DS)
## dist: quantize + neighbors + pack -> dist/<DS>/*
dist:
$(PYTHON) src/build_dist.py --config $(DS)
## emoji: build the standalone emoji dataset (own space + UMAP) from a source word
## dataset's vectors -> dist/emoji-eg/. Keyword-lookup, no model/GPU (CPU image).
EMOJI_SOURCE ?= kawiki-eg
emoji:
$(PYTHON) src/embed_emoji.py --source $(EMOJI_SOURCE)
stage1: corpus vocab collapse embed
stage2: reduce dist
# ---- stage 3 (CPU, the gate) ------------------------------------------------
## evaluate: probe eval + schema/vocab_hash/displacement/blocklist asserts on dist/
evaluate:
$(PYTHON) src/evaluate.py
## test: stdlib unit suite (pure-python logic; artifact tests skip if dist absent)
test:
$(PYTHON) -m unittest discover -s tests -v
clean:
rm -rf src/__pycache__ tests/__pycache__ src/vendor/__pycache__
# ---- docker images ----------------------------------------------------------
docker-build-generate:
docker build -f docker/Dockerfile.generate -t anbani-we-generate .
docker-build-build:
docker build -f docker/Dockerfile.build -t anbani-we-build .
# ---- GPU node ("exce", Tailscale RTX 3090) ----------------------------------
# Docker-only there; never install on the host. Every target checks reachability
# first and fails fast. The kawiki ZIM is mounted read-only from the node's
# kiwix-desktop dir — never re-downloaded.
GPU_HOST ?= george@100.88.125.127
GPU_DIR ?= ~/word-embeddings-work
GPU_HFCACHE ?= ~/.hfcache
GPU_ZIM_DIR ?= ~/.local/share/kiwix-desktop
SSH_OPTS = -o ConnectTimeout=10 -o BatchMode=yes
GPU_ENV ?=
IMG_GEN = anbani-we-generate
IMG_BUILD = anbani-we-build
CONTAINER = anbani-we-stage1
## gpu-sync: rsync this repo to the node (excludes heavy/gitignored dirs)
gpu-sync:
@ssh $(SSH_OPTS) $(GPU_HOST) true || (echo "gpu-sync: $(GPU_HOST) unreachable" >&2; exit 1)
ssh $(SSH_OPTS) $(GPU_HOST) 'mkdir -p $(GPU_DIR) $(GPU_HFCACHE)'
rsync -az --delete \
--exclude .git --exclude work --exclude dist --exclude __pycache__ \
--exclude '*.npy' \
-e "ssh $(SSH_OPTS)" ./ $(GPU_HOST):$(GPU_DIR)/
## gpu-stage1: build the CUDA image and run corpus+vocab+embed DETACHED on the node.
## HF_TOKEN must be exported in the node's environment (gated Gemma weights).
## The ZIM dir is mounted read-only at /zim. Follow with `make gpu-logs`.
gpu-stage1: gpu-sync
ssh $(SSH_OPTS) $(GPU_HOST) "cd $(GPU_DIR) && \
docker build -f docker/Dockerfile.generate -t $(IMG_GEN) . && \
docker rm -f $(CONTAINER) 2>/dev/null || true; \
docker run -d --name $(CONTAINER) --gpus all \
-v \$$PWD:/work -w /work \
-v $(GPU_ZIM_DIR):/zim:ro \
-v $(GPU_HFCACHE):/root/.cache/huggingface \
-e HF_TOKEN -e WE_ZIM_DIR=/zim $(GPU_ENV) \
$(IMG_GEN) make corpus vocab embed DS=$(DS) CORPUS=$(CORPUS)"
@echo "gpu-stage1: detached ($(DS)). logs -> make gpu-logs ; artifacts -> make gpu-fetch"
## gpu-stage2: reduce+dist on the node (CPU build image), from the work/ vectors there
gpu-stage2:
@ssh $(SSH_OPTS) $(GPU_HOST) true || (echo "gpu-stage2: $(GPU_HOST) unreachable" >&2; exit 1)
ssh $(SSH_OPTS) $(GPU_HOST) "cd $(GPU_DIR) && \
docker build -f docker/Dockerfile.build -t $(IMG_BUILD) . && \
docker run --rm -v \$$PWD:/work -w /work $(IMG_BUILD) \
make reduce dist DS=$(DS)"
## gpu-logs: follow the detached stage-1 container
gpu-logs:
ssh $(SSH_OPTS) $(GPU_HOST) "docker logs -f $(CONTAINER)"
## gpu-stop: stop + remove the detached stage-1 container
gpu-stop:
-ssh $(SSH_OPTS) $(GPU_HOST) "docker rm -f $(CONTAINER)"
## gpu-fetch: rsync dist/ back (committed from the Mac) + a vectors backup
gpu-fetch:
@ssh $(SSH_OPTS) $(GPU_HOST) true || (echo "gpu-fetch: $(GPU_HOST) unreachable" >&2; exit 1)
rsync -az -e "ssh $(SSH_OPTS)" $(GPU_HOST):$(GPU_DIR)/dist/ dist/
-rsync -az -e "ssh $(SSH_OPTS)" $(GPU_HOST):$(GPU_DIR)/work/$(DS)/vectors.f32.npy work/$(DS)/vectors.f32.npy