quality.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. """GSM8K (first N) and HumanEval generations against a running server; HumanEval
  2. programs are written out for a separate no-network run.
  3. usage: quality.py LABEL [gsm_n]. Reads $QUALITY_DIR (default ./quality-data):
  4. gsm8k_test.jsonl (openai/grade-school-math) and HumanEval.jsonl
  5. (openai/human-eval); writes $QUALITY_DIR/LABEL/. Then score HumanEval with
  6. docker run --rm --network none -v $QUALITY_DIR/LABEL:/q:ro -v $PWD/run_he.py:/run_he.py:ro \
  7. --entrypoint python3 <serving image> /run_he.py /q
  8. """
  9. import concurrent.futures as cf, json, os, re, sys, urllib.request
  10. LABEL = sys.argv[1]; GSM_N = int(sys.argv[2]) if len(sys.argv) > 2 else 250
  11. BASE = os.environ.get("QUALITY_URL", "http://127.0.0.1:8002") + "/v1/chat/completions"
  12. DATA = os.environ.get("QUALITY_DIR", "quality-data")
  13. OUT = f"{DATA}/{LABEL}"; os.makedirs(f"{OUT}/he", exist_ok=True)
  14. def chat(prompt, max_tokens=1024):
  15. body = {"model": "glm53", "messages": [{"role": "user", "content": prompt}], "max_tokens": max_tokens,
  16. "temperature": 0, "seed": 1234, "chat_template_kwargs": {"thinking": False}}
  17. r = urllib.request.Request(BASE, json.dumps(body).encode(), {"Content-Type": "application/json"})
  18. return json.loads(urllib.request.urlopen(r, timeout=900).read())["choices"][0]["message"]["content"] or ""
  19. def num(s):
  20. s = s.replace(",", "").replace("$", "").strip()
  21. try: return float(s)
  22. except ValueError: return None
  23. gsm = [json.loads(l) for l in open(f"{DATA}/gsm8k_test.jsonl")][:GSM_N]
  24. def do_gsm(q):
  25. txt = chat("Solve the problem. Show brief working, then give the final answer on the last line as '#### <number>'.\n\n" + q["question"])
  26. m = re.findall(r"####\s*([-\d.,$]+)", txt) or re.findall(r"(-?[\d,]*\.?\d+)", txt)
  27. got = num(m[-1]) if m else None
  28. gold = num(q["answer"].split("####")[-1])
  29. return got is not None and gold is not None and abs(got - gold) < 1e-6, txt
  30. with cf.ThreadPoolExecutor(8) as ex:
  31. res = list(ex.map(do_gsm, gsm))
  32. acc = sum(ok for ok, _ in res) / len(res)
  33. json.dump([t for _, t in res], open(f"{OUT}/gsm8k.json", "w"))
  34. print(f"{LABEL} GSM8K first {len(gsm)}: {acc * 100:.1f}%", flush=True)
  35. he = [json.loads(l) for l in open(f"{DATA}/HumanEval.jsonl")]
  36. PRELUDE = "from typing import *\nimport math, re, string, collections, itertools, functools, heapq, bisect\n"
  37. def do_he(p):
  38. txt = chat("Complete the following Python function. Reply with the whole function in one ```python code block and nothing else.\n\n" + p["prompt"])
  39. m = re.findall(r"```(?:python)?\n(.*?)```", txt, re.S)
  40. code = m[0] if m else txt
  41. if f"def {p['entry_point']}" not in code:
  42. code = p["prompt"] + code
  43. prog = PRELUDE + code + "\n\n" + p["test"] + f"\n\ncheck({p['entry_point']})\n"
  44. open(f"{OUT}/he/{p['task_id'].replace('/', '_')}.py", "w").write(prog)
  45. with cf.ThreadPoolExecutor(8) as ex:
  46. list(ex.map(do_he, he))
  47. print(f"{LABEL} HumanEval: {len(he)} programs written", flush=True)