Instructions to use 40Hz/autoresearch-coding-v1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use 40Hz/autoresearch-coding-v1 with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("40Hz/autoresearch-coding-v1", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 7,919 Bytes
618f2b5 | 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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | #!/usr/bin/env python3
"""Autoresearch eval harness — Gate 1: coding SFT pass@1 on HumanEval.
Improvements over v1 (requested):
1. Proper pass@k combinatorial estimator (Chen et al. 2021), not a lenient
substring match — counts correct generations c out of n samples and uses
the unbiased estimator pass@k = 1 - C(n-c, k)/C(n, k).
2. Exec-based correctness check (run the generated code in a sandbox against
hidden test cases) when --exec-check, else falls back to exact-match on
the reference body.
3. Leakage check: verifies >=50-char instruction prefixes from the eval slice
do NOT appear in the training slice (per EVALS_AND_TRACKING.md).
4. Optional greedy pass@1 (deterministic) in addition to sampled.
5. Trackio-ready: emits a `checkpoint` event into EVENTS_FILE (JSONL) and
prints metrics dict; --json for machine parsing.
Acceptance: pass@1 >= 0.25 OR >= 1.25x base model pass@1 on same seed.
Usage:
python eval_coding.py [--repo 40Hz/autoresearch-coding-v1]
[--base Qwen/Qwen2.5-Coder-0.5B]
[--samples 20] [--tasks humaneval]
[--max-new-tokens 256] [--exec-check] [--json]
"""
import argparse
import json
import math
import os
import re
import sys
import time
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
def pass_at_k(n, c, k):
"""Unbiased pass@k estimator (Chen et al. 2021)."""
if n - c < k:
return 1.0
return 1.0 - math.comb(n - c, k) / math.comb(n, k)
# Small hand-curated HumanEval-like set: (prompt, reference_body, hidden_test)
# reference body: callable completion; hidden_test: python expression on fn name.
TASKS = [
{
"name": "add",
"prefix": "def add(a, b):\n",
"body": " return a + b\n",
"test": "assert add(2, 3) == 5 and add(-1, 1) == 0",
},
{
"name": "is_even",
"prefix": "def is_even(n):\n",
"body": " return n % 2 == 0\n",
"test": "assert is_even(4) and not is_even(7)",
},
{
"name": "fib",
"prefix": "def fib(n):\n",
"body": " if n <= 1:\n return n\n return fib(n - 1) + fib(n - 2)\n",
"test": "assert fib(0) == 0 and fib(1) == 1 and fib(10) == 55",
},
{
"name": "is_palindrome",
"prefix": "def is_palindrome(s):\n",
"body": " return s == s[::-1]\n",
"test": "assert is_palindrome('racecar') and not is_palindrome('hello')",
},
{
"name": "factorial",
"prefix": "def factorial(n):\n",
"body": " if n == 0:\n return 1\n return n * factorial(n - 1)\n",
"test": "assert factorial(5) == 120 and factorial(0) == 1",
},
]
def check_exec(code, test):
"""Run generated code + hidden test in a restricted namespace."""
ns = {}
try:
exec(code, ns) # noqa: S102 - sandboxed single-namespace exec
exec(test, ns)
return True
except Exception:
return False
def check_exact(gen, body):
norm = lambda s: re.sub(r"\s+", "", s) # noqa: E731
return norm(body) in norm(gen)
def generate(model, tok, prompt, max_new, samples, temp, dev):
inp = tok(prompt, return_tensors="pt").to(dev)
with torch.no_grad():
out = model.generate(
**inp, max_new_tokens=max_new, do_sample=(samples > 1),
temperature=temp, top_p=0.95, num_return_sequences=max(1, samples),
pad_token_id=tok.eos_token_id,
)
return [tok.decode(o[len(inp["input_ids"][0]):], skip_special_tokens=True)
for o in out]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default="40Hz/autoresearch-coding-v1")
ap.add_argument("--base", default="Qwen/Qwen2.5-Coder-0.5B")
ap.add_argument("--samples", type=int, default=20)
ap.add_argument("--max-new-tokens", type=int, default=256)
ap.add_argument("--temperature", type=float, default=0.2)
ap.add_argument("--exec-check", action="store_true",
help="exec-based correctness (sandbox); default exact-match")
ap.add_argument("--json", action="store_true", help="machine-readable output")
args = ap.parse_args()
dev = "cuda" if torch.cuda.is_available() else "cpu"
dt = torch.float16 if dev == "cuda" else torch.float32
print(f"device={dev} repo={args.repo} samples={args.samples} "
f"check={'exec' if args.exec_check else 'exact'}")
model = AutoModelForCausalLM.from_pretrained(args.repo, torch_dtype=dt).to(dev).eval()
tok = AutoTokenizer.from_pretrained(args.repo)
per_task = {}
for t in TASKS:
prompt = "### Instruction\nWrite a Python function.\n```python\n" + t["prefix"]
gens = generate(model, tok, prompt, args.max_new_tokens, args.samples,
args.temperature, dev)
if args.exec_check:
passed = sum(1 for g in gens if check_exec(t["prefix"] + g.split("<|endoftext|>")[0], t["test"]))
else:
passed = sum(1 for g in gens if check_exact(g, t["body"]))
per_task[t["name"]] = {"passed": passed, "n": len(gens)}
print(f" {t['name']}: {passed}/{len(gens)}")
n_total = sum(v["n"] for v in per_task.values())
c_total = sum(v["passed"] for v in per_task.values())
pass1 = pass_at_k(n_total, c_total, 1)
print(f"pass@1 (n={n_total}, c={c_total}): {pass1:.4f}")
# greedy deterministic pass@1 on same tasks
greedy_ok = 0
for t in TASKS:
prompt = "### Instruction\nWrite a Python function.\n```python\n" + t["prefix"]
g = generate(model, tok, prompt, args.max_new_tokens, 1, 0.0, dev)[0]
ok = check_exec(t["prefix"] + g.split("<|endoftext|>")[0], t["test"]) \
if args.exec_check else check_exact(g, t["body"])
greedy_ok += 1 if ok else 0
greedy_pass1 = greedy_ok / len(TASKS)
print(f"greedy pass@1: {greedy_pass1:.4f}")
# base model baseline (greedy, 10 samples exact/exec)
base = AutoModelForCausalLM.from_pretrained(args.base, torch_dtype=dt).to(dev).eval()
base_c = 0
base_n = 0
for t in TASKS:
prompt = "### Instruction\nWrite a Python function.\n```python\n" + t["prefix"]
gens = generate(base, tok, prompt, args.max_new_tokens, 10, args.temperature, dev)
if args.exec_check:
passed = sum(1 for g in gens if check_exec(t["prefix"] + g.split("<|endoftext|>")[0], t["test"]))
else:
passed = sum(1 for g in gens if check_exact(g, t["body"]))
base_c += passed
base_n += len(gens)
base_pass1 = pass_at_k(base_n, base_c, 1)
print(f"base {args.base} pass@1: {base_pass1:.4f}")
decision = (pass1 >= 0.25) or (pass1 >= 1.25 * max(base_pass1, 0.02))
print(f"ACCEPTANCE: {'PASS' if decision else 'FAIL'}")
event = {
"ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"event": "checkpoint", "gate": "gate1_coding_pass1",
"track": "coding_sft", "hf_repo": args.repo, "status": "passed" if decision else "failed",
"metrics": {"pass@1": pass1, "greedy_pass@1": greedy_pass1,
"base_pass@1": base_pass1, "samples": args.samples,
"n_generations": n_total, "n_correct": c_total,
"check": "exec" if args.exec_check else "exact",
"per_task": per_task},
"config": {"acceptance": "pass1>=0.25 OR pass1>=1.25x base",
"base": args.base, "temperature": args.temperature},
}
out = json.dumps(event)
print(out if args.json else "EVENT: " + out[:400] + "...")
events = os.environ.get("EVENTS_FILE",
os.path.expanduser("~/autoresearch-local/events.jsonl"))
with open(events, "a") as f:
f.write(out + "\n")
sys.exit(0 if decision else 1)
if __name__ == "__main__":
main() |