PoPTard5 / model-3 /src /embed.py
Jyo-K's picture
Upload folder using huggingface_hub
e79d917 verified
Raw History Blame Contribute Delete
3.69 kB
"""Unified, resumable embedding stage — replaces model-2's embed_train.py + embed_test.py.
python src/embed.py --split train --part pool --gpu 0
python src/embed.py --split test --part pool --gpu 1
python src/embed.py --split test --part s1 --gpu 1
Parts
-----
pool : Source 2 + Source 3 (S2 rows first, then S3) -- the search corpus, doc prefix
s1 : Source 1 -- the queries, query prefix
all : pool then s1
Notes
-----
* `--split train --part s1` is OPTIONAL and off by default in scripts/queue.sh.
run_train_eval.py only queries n_s1_ce+n_s1_stack+n_s1_val (=200k) of the 2.21M
train S1, and caches those itself. Embedding all 2.21M is the dead work that cost
model-2 ~50 min. `--split test --part s1` IS required (every test S1 must be scored).
* Every run is resumable and fingerprint-checked -- see encoder.py.
* --gpu is mandatory-by-default so nothing silently lands on a busy cuda:0.
"""
from __future__ import annotations
import argparse
import os
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import pandas as pd # noqa: E402
from config import CFG, EMB, PATHS, emb_dir, model_spec # noqa: E402
from encoder import encode_to_shards, write_ids # noqa: E402
COLS = ["entity_id", "business_name", "business_address", "country"]
T0 = time.time()
def log(m):
print(f"[{time.time() - T0:7.0f}s] {m}", flush=True)
def record_text(name, addr, country):
"""Must stay byte-identical to the text used at search time."""
return f"{name} | {addr} | {country}"
def read_part(split, part):
p = PATHS[split]
if part == "pool":
df = pd.concat([pd.read_parquet(p["source2"], columns=COLS),
pd.read_parquet(p["source3"], columns=COLS)], ignore_index=True)
else:
df = pd.read_parquet(p["source1"], columns=COLS)
for c in COLS:
df[c] = df[c].fillna("").astype(str)
return df
def run(split, part, device, model_name=None):
hf_id, qpre, dpre, _dim, lic = model_spec(model_name)
prefix = dpre if part == "pool" else qpre
df = read_part(split, part)
log(f"{split}/{part}: {len(df):,} records | model={hf_id} ({lic}) | prefix={prefix!r}")
texts = [record_text(a, b, c) for a, b, c in
zip(df["business_name"], df["business_address"], df["country"])]
ids = df["entity_id"].tolist()
del df
d = emb_dir(f"{split}_{part}", model_name)
os.makedirs(d, exist_ok=True)
write_ids(os.path.join(d, "ids.txt"), ids)
return encode_to_shards(texts, ids, d, hf_id, prefix, EMB["max_len"], EMB["batch"],
device, EMB["shard_rows"], log)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--split", choices=["train", "test"], required=True)
ap.add_argument("--part", choices=["pool", "s1", "all"], default="pool")
ap.add_argument("--gpu", default=None,
help="GPU index, or 'cpu'. Required unless M3_GPU is set -- this is "
"deliberate: model-2 lost runs by defaulting to a saturated cuda:0.")
ap.add_argument("--model", default=None, help=f"override (default {EMB['model']})")
a = ap.parse_args()
gpu = a.gpu if a.gpu is not None else os.environ.get("M3_GPU")
if gpu is None:
sys.exit("refusing to guess a GPU: pass --gpu 0 / --gpu 1 / --gpu cpu (or set M3_GPU)")
device = "cpu" if str(gpu) == "cpu" else f"cuda:{int(gpu)}"
parts = ["pool", "s1"] if a.part == "all" else [a.part]
for p in parts:
run(a.split, p, device, a.model)
log("all requested parts complete")
if __name__ == "__main__":
main()