batchtest.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. #!/usr/bin/env python3
  2. """Step 1: greedy batches of 3 and 4 (prose prompts, 120 tokens) + batch of 4 at temperature 0.7.
  3. Prints first 80 chars of each response and a garbage verdict."""
  4. import json, time, sys, urllib.request, concurrent.futures as cf, re, statistics
  5. URL = "http://10.0.0.1:8888/v1/chat/completions"
  6. PROMPTS = [
  7. "Write a vivid short story (about 500 words) about a lighthouse keeper's last winter. Prose only, no headings.",
  8. "Write a vivid short story (about 500 words) about a city that only exists at night. Prose only, no headings.",
  9. "Write a vivid short story (about 500 words) about two rivals sharing a train compartment. Prose only, no headings.",
  10. "Write a vivid short story (about 500 words) about a violin found in a flooded cellar. Prose only, no headings.",
  11. "Describe, in flowing prose, a morning walk through a market town in early autumn.",
  12. "Explain in plain English how a bicycle's gears change the effort needed to climb a hill.",
  13. ]
  14. def gen(i, temp, n=120):
  15. body = dict(model="deepseek-v4.1-flash", temperature=temp, max_tokens=n, stream=False,
  16. chat_template_kwargs={"thinking": False},
  17. messages=[{"role": "user", "content": PROMPTS[i % len(PROMPTS)]}])
  18. if temp > 0: body["top_p"] = 0.95
  19. t0 = time.time()
  20. r = json.load(urllib.request.urlopen(urllib.request.Request(URL, data=json.dumps(body).encode(),
  21. headers={"Content-Type": "application/json"}), timeout=900))
  22. dt = time.time() - t0
  23. c = r["choices"][0]
  24. return r["usage"]["completion_tokens"], dt, c["finish_reason"], c["message"]["content"]
  25. def garbage(txt):
  26. # Latin prose expected: flag if <70% of non-space chars are ASCII letters/punct, or CJK present
  27. if not txt.strip(): return True
  28. cjk = re.search(r'[ -鿿가-힯]', txt) is not None
  29. body = [ch for ch in txt if not ch.isspace()]
  30. latin = sum(1 for ch in body if ch.isascii() and (ch.isalpha() or ch in ".,;:'\"!?-()"))
  31. return cjk or (latin / max(1, len(body)) < 0.7)
  32. def level(c, temp, k=0, n=120):
  33. t0 = time.time()
  34. with cf.ThreadPoolExecutor(c) as ex:
  35. rs = list(ex.map(lambda i: gen(i, temp, n), range(k, k + c)))
  36. wall = time.time() - t0
  37. tot = sum(r[0] for r in rs)
  38. bad = 0
  39. print(f"batch={c} temp={temp}: aggregate {tot/wall:5.1f} tok/s wall {wall:5.1f}s tokens {tot}")
  40. for i, (nt, dt, fr, txt) in enumerate(rs):
  41. g = garbage(txt); bad += g
  42. print(f" [{i}] {nt:4d} tok {nt/dt:5.1f} tok/s {'GARBAGE' if g else 'ok '} {txt[:80]!r}")
  43. print(f" => {bad}/{c} garbled")
  44. return bad
  45. if __name__ == "__main__":
  46. tag = sys.argv[1] if len(sys.argv) > 1 else ""
  47. print(f"== batch test {tag} {time.strftime('%H:%M:%S')} ==")
  48. total = 0
  49. total += level(3, 0.0)
  50. total += level(4, 0.0)
  51. total += level(4, 0.7)
  52. print(f"RESULT {tag}: {total} garbled responses total")