Download code/bench/determinism.py from nandukmelath/nirnay: direct link, hf CLI and curl.
- Browser
- Download file 2.81 kB
-
https://huggingface.co/nandukmelath/nirnay/resolve/main/code/bench/determinism.py
- Command line
-
hf download hf://nandukmelath/nirnay/code/bench/determinism.py
-
curl -L -o determinism.py https://huggingface.co/nandukmelath/nirnay/resolve/main/code/bench/determinism.py
2.81 kB
| """Determinism across thread counts: the same cases answered with 1 / 4 / 8 / 16 threads must give | |
| byte-identical answers (probabilities are reported to 4 decimals, as Laya does). | |
| python bench\\determinism.py nirnay:models\\nirnay-v1 | |
| python bench\\determinism.py laya:laya-multilingual (slow; uses 60 cases) | |
| """ | |
| import json | |
| import os | |
| import random | |
| import sys | |
| from collections import defaultdict | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| ROOT = os.path.dirname(HERE) | |
| sys.path.insert(0, ROOT) | |
| sys.path.insert(0, HERE) | |
| from eval_suites import Adapter # noqa: E402 | |
| def main(): | |
| spec = sys.argv[1] | |
| threads = [int(x) for x in os.environ.get("DET_THREADS", "1,4,8,16").split(",")] | |
| per_suite = int(os.environ.get("DET_PER_SUITE", "25" if spec.startswith("nirnay") else "5")) | |
| cases = [json.loads(l) for l in open(os.path.join(HERE, "data", "suites.jsonl"), encoding="utf-8")] | |
| by = defaultdict(list) | |
| for c in cases: | |
| by[c["suite"]].append(c) | |
| sample = [c for cs in by.values() for c in cs[:per_suite]] | |
| import torch | |
| runs = {} | |
| for th in threads: | |
| ad = Adapter(spec, th) # reload: ONNX Runtime fixes its thread pool at session creation | |
| torch.set_num_threads(th) | |
| runs[th] = [json.dumps(ad.batch([c["state"]], c["questions"])[0]["answers"], sort_keys=True) for c in sample] | |
| print("threads %2d done" % th, flush=True) | |
| del ad | |
| base = runs[threads[0]] | |
| same = sum(all(runs[t][i] == base[i] for t in threads) for i in range(len(sample))) | |
| # how big are the differences that do occur? (decision changes vs last-digit probability changes) | |
| answer_changes, max_prob_diff = 0, 0.0 | |
| for i in range(len(sample)): | |
| a0 = json.loads(base[i]) | |
| for t in threads[1:]: | |
| a1 = json.loads(runs[t][i]) | |
| for qid in a0: | |
| x, y = a0[qid], a1[qid] | |
| if x.get("choice") != y.get("choice") or ((x.get("noul", 0) >= 0.5) != (y.get("noul", 0) >= 0.5)): | |
| answer_changes += 1 | |
| px = x.get("probabilities") or {"p": x.get("noul")} | |
| py = y.get("probabilities") or {"p": y.get("noul")} | |
| max_prob_diff = max(max_prob_diff, max(abs(px[k] - py[k]) for k in px)) | |
| res = {"model": spec, "threads": threads, "cases": len(sample), "identical_rate": round(same / len(sample), 4), | |
| "answer_changes": answer_changes, "max_probability_diff": round(max_prob_diff, 6)} | |
| name = os.environ.get("DET_OUT") or ("nirnay_determinism.json" if spec.startswith("nirnay") | |
| else "laya_determinism__%s.json" % spec.split(":")[1]) | |
| json.dump(res, open(os.path.join(HERE, "results", name), "w"), indent=2) | |
| print(res) | |
| if __name__ == "__main__": | |
| main() | |