Download Code-agent-main/ycode/lm/cli.py from Yazhiniyan/YCode: direct link, hf CLI and curl.
- Browser
- Download file 24.5 kB
-
https://huggingface.co/Yazhiniyan/YCode/resolve/main/Code-agent-main/ycode/lm/cli.py
- Command line
-
hf download hf://Yazhiniyan/YCode/Code-agent-main/ycode/lm/cli.py
-
curl -L -o cli.py https://huggingface.co/Yazhiniyan/YCode/resolve/main/Code-agent-main/ycode/lm/cli.py
24.5 kB
| """``ycode-lm``: build, train and talk to your own from-scratch coding model. | |
| ycode-lm prepare --source ~/code --out data/ # corpus + tokenizer + datasets | |
| ycode-lm train --data data/ --out models/base # pretrain on code | |
| ycode-lm sft --data data/ --init-from models/base --out models/chat | |
| ycode-lm chat --model models/chat # ask it questions | |
| ycode-lm sample --model models/base --prompt "def quicksort(" | |
| ycode-lm info --model models/chat | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| from pathlib import Path | |
| from ycode.config import default_local_model_dir | |
| from ycode.config import resolve_local_model as default_model_dir | |
| def _require_torch() -> None: | |
| import importlib.util | |
| if importlib.util.find_spec("torch") is None or importlib.util.find_spec("numpy") is None: | |
| print("ycode-lm needs PyTorch and NumPy. Install them with:\n\n pip install -e \".[local]\"\n", | |
| file=sys.stderr) | |
| raise SystemExit(2) | |
| def _train_args(p: argparse.ArgumentParser, *, sft: bool) -> None: | |
| p.add_argument("--data", required=True, type=Path, help="Directory produced by `ycode-lm prepare`.") | |
| p.add_argument("--out", type=Path, default=None, help="Where to write the model.") | |
| if sft: | |
| p.add_argument("--init-from", required=True, type=Path, help="Pretrained model directory.") | |
| p.add_argument("--resume", action="store_true", | |
| help="Continue an interrupted SFT run in --out (falls back to --init-from).") | |
| else: | |
| p.add_argument("--preset", default="v2-small", | |
| help="Model size: v3-40m, v2-tiny, v2-small (default), v2-base, v2-medium, v2-large, or v1 presets.") | |
| p.add_argument("--layers", type=int, help="Override number of layers.") | |
| p.add_argument("--heads", type=int, help="Override number of attention heads.") | |
| p.add_argument("--embd", type=int, help="Override embedding width.") | |
| p.add_argument("--context", type=int, help="Override context length (tokens).") | |
| p.add_argument("--resume", action="store_true", help="Continue training the model in --out.") | |
| p.add_argument("--init-from", type=Path, default=None, | |
| help="Start from this trained/grown model instead of random weights " | |
| "(continued pretraining, e.g. after `ycode-lm grow`).") | |
| p.add_argument("--steps", type=int, default=None, help="Optimizer steps (the LR schedule spans all of them).") | |
| p.add_argument("--until-step", type=int, default=None, | |
| help="Stop at this step and save; continue later with --resume (segmented training).") | |
| p.add_argument("--minutes", type=float, default=None, help="Stop after this many minutes.") | |
| p.add_argument("--batch-size", type=int, default=16) | |
| p.add_argument("--grad-accum", type=int, default=1) | |
| p.add_argument("--lr", type=float, default=None) | |
| p.add_argument("--eval-interval", type=int, default=100) | |
| p.add_argument("--eval-iters", type=int, default=20, help="Batches per evaluation (per split).") | |
| p.add_argument("--save-interval", type=int, default=None, | |
| help="Also checkpoint every N steps without evaluating (cheap protection against crashes).") | |
| p.add_argument("--device", default="auto", help="auto, cpu, cuda or mps.") | |
| p.add_argument("--precision", default="auto", choices=("auto", "fp32", "bf16", "fp16")) | |
| p.add_argument("--grad-checkpoint", action="store_true", | |
| help="Recompute activations in backward: far less GPU memory, ~30%% slower.") | |
| p.add_argument("--shard", action="store_true", | |
| help="With several GPUs (torchrun): split weights and optimizer state across them (FSDP) " | |
| "so models too big for one GPU can train.") | |
| p.add_argument("--schedule", default="wsd", choices=("wsd", "cosine"), | |
| help="LR schedule: warmup-stable-decay (default) or cosine.") | |
| p.add_argument("--compile", action="store_true", help="Use torch.compile (faster on many machines).") | |
| p.add_argument("--optimizer", default=None, choices=("adamw", "muon", "lion"), | |
| help="adamw, or muon (Muon for hidden matrices + AdamW for the rest). " | |
| "Default: muon for v3 presets, adamw otherwise.") | |
| p.add_argument("--muon-lr", type=float, default=0.02) | |
| if sft: | |
| p.add_argument("--no-pack", action="store_true", help="One example per row instead of packing.") | |
| else: | |
| p.add_argument("--anneal-mix", type=float, default=0.2, | |
| help="Share of instruction data mixed in during the LR decay phase (0 disables).") | |
| p.add_argument("--seed", type=int, default=1337) | |
| def build_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser(prog="ycode-lm", description="Train your own coding LLM from scratch.") | |
| sub = parser.add_subparsers(dest="command", required=True) | |
| p = sub.add_parser("prepare", help="Collect code, train the tokenizer and encode datasets.") | |
| p.add_argument("--source", action="append", type=Path, default=[], | |
| help="File or directory of code (repeatable). Default: the Python standard library.") | |
| p.add_argument("--sft-data", action="append", type=Path, default=[], | |
| help="Extra instruction data: JSONL with {\"prompt\", \"response\"} per line (repeatable).") | |
| p.add_argument("--out", required=True, type=Path, help="Output data directory.") | |
| p.add_argument("--vocab-size", type=int, default=8192) | |
| p.add_argument("--exclude", action="append", default=[], | |
| help="Glob of paths to leave out, e.g. '*/tests/*' (repeatable). Use it to hold out eval data.") | |
| p.add_argument("--workers", type=int, default=None, help="Tokenizer processes (default: all CPU cores).") | |
| p.add_argument("--sft-only", action="store_true", | |
| help="Only rebuild the instruction data, reusing --tokenizer (for re-tuning a pretrained model).") | |
| p.add_argument("--tokenizer", type=Path, default=None, | |
| help="Reuse this tokenizer.json (needed to continue training an existing model).") | |
| p.add_argument("--max-mb", type=float, default=None, help="Cap the code corpus at this many MB.") | |
| _train_args(sub.add_parser("train", help="Pretrain a model on the code corpus."), sft=False) | |
| _train_args(sub.add_parser("sft", help="Instruction-tune a pretrained model so it answers requests."), | |
| sft=True) | |
| p = sub.add_parser("grow", help="Deepen a trained model; the grown model starts out computing the same function.") | |
| p.add_argument("--model", required=True, type=Path, help="Trained model directory.") | |
| p.add_argument("--out", required=True, type=Path, help="Output directory (use as --init-from for train).") | |
| p.add_argument("--layers", type=int, default=None, help="New number of layers.") | |
| p.add_argument("--width", type=int, default=None, help="New width (embedding size); heads scale with it.") | |
| p.add_argument("--version", type=int, default=None, help="Architecture version to record (e.g. 4).") | |
| p = sub.add_parser("export", help="Write a slim inference-only copy of a model (no optimizer state).") | |
| p.add_argument("--model", required=True, type=Path, help="Trained model directory.") | |
| p.add_argument("--out", required=True, type=Path, help="Output directory.") | |
| p.add_argument("--dtype", default="bf16", choices=("bf16", "fp32"), help="bf16 halves the size (default).") | |
| p.add_argument("--max-shard-mb", type=float, default=None, | |
| help="Split weights into files of at most this size (e.g. 45 to stay under GitHub's limits).") | |
| p = sub.add_parser("autotrain", help="Grow, train, tune, evaluate and publish a model across GPU sessions " | |
| "(Kaggle/Colab), syncing checkpoints to Hugging Face.") | |
| p.add_argument("--base-model", required=True, type=Path, help="Model to grow from, e.g. models/ycode-lm-v4.") | |
| p.add_argument("--preset", default="v5-385m", help="Target architecture (default v5-385m).") | |
| p.add_argument("--work", type=Path, default=Path("ycode-autotrain"), help="Local working directory.") | |
| p.add_argument("--hf-repo", default=None, help="Hugging Face repo for the finished model, e.g. you/ycode-lm-v5.") | |
| p.add_argument("--ckpt-repo", default=None, help="Private repo for checkpoints (default: <hf-repo>-checkpoints).") | |
| p.add_argument("--public", action="store_true", help="Make the finished-model repo public.") | |
| p.add_argument("--local-hub", type=Path, default=None, help="Use a local folder instead of Hugging Face.") | |
| p.add_argument("--pretrain-steps", type=int, default=6000) | |
| p.add_argument("--sft-steps", type=int, default=800) | |
| p.add_argument("--batch-size", type=int, default=8) | |
| p.add_argument("--grad-accum", type=int, default=1) | |
| p.add_argument("--nproc", type=int, default=None, help="GPUs to use (default: all visible).") | |
| p.add_argument("--hours", type=float, default=11.0, help="Session time budget (Kaggle sessions last 12 h).") | |
| p.add_argument("--segment-minutes", type=float, default=90.0, help="Checkpoint upload interval.") | |
| p.add_argument("--max-mb", type=float, default=1000.0, help="Cap on the code corpus size.") | |
| p.add_argument("--source", action="append", type=Path, default=[], help="Code to train on (default: " | |
| "the Python standard library + installed packages).") | |
| p.add_argument("--no-grad-checkpoint", action="store_true", help="Faster but needs much more GPU memory.") | |
| p.add_argument("--shard", default="auto", choices=("auto", "yes", "no"), | |
| help="Split the model across GPUs (FSDP). auto: for models over 600M parameters.") | |
| p.add_argument("--lr", type=float, default=None, help="Pretraining LR for AdamW-trained weights.") | |
| p.add_argument("--muon-lr", type=float, default=None, help="Pretraining LR for Muon-trained matrices.") | |
| p.add_argument("--compile", action="store_true") | |
| p.add_argument("--device", default="auto") | |
| p.add_argument("--precision", default="auto", choices=("auto", "fp32", "bf16", "fp16")) | |
| p.add_argument("--max-segments", type=int, default=None, help=argparse.SUPPRESS) | |
| p.add_argument("--eval-interval", type=int, default=250) | |
| p = sub.add_parser("push-hf", help="Upload an exported model folder to a Hugging Face model repo.") | |
| p.add_argument("--model", required=True, type=Path, help="Folder from `ycode-lm export`.") | |
| p.add_argument("--repo", required=True, help="Repo id, e.g. you/ycode-lm-v5.") | |
| p.add_argument("--public", action="store_true") | |
| p = sub.add_parser("eval", help="Score models: bits/byte on held-out code + pass rate on coding problems.") | |
| p.add_argument("--model", action="append", type=Path, default=[], | |
| help="Model directory (repeat to compare several, e.g. v1 and v2).") | |
| p.add_argument("--heldout", action="append", type=Path, default=[], | |
| help="Code the models never trained on, for bits-per-byte (repeatable).") | |
| p.add_argument("--samples", type=int, default=1, help="Samples per problem for pass@k (default 1 = greedy).") | |
| p.add_argument("--no-functional", action="store_true", help="Skip the coding-problem benchmark.") | |
| p.add_argument("--verbose", action="store_true", help="Show each problem's result.") | |
| p.add_argument("--device", default="auto") | |
| for name, help_text in (("chat", "Interactive Q&A with your model."), | |
| ("sample", "Continue a code prompt."), ("info", "Show model details.")): | |
| p = sub.add_parser(name, help=help_text) | |
| p.add_argument("--model", type=Path, default=None, help=f"Model directory (default {default_model_dir()}).") | |
| p.add_argument("--device", default="auto") | |
| if name != "info": | |
| p.add_argument("--temperature", type=float, default=0.7) | |
| p.add_argument("--max-tokens", type=int, default=300) | |
| if name == "sample": | |
| p.add_argument("--prompt", required=True) | |
| return parser | |
| def main(argv: list[str] | None = None) -> int: | |
| args = build_parser().parse_args(argv) | |
| _require_torch() | |
| if args.command == "prepare": | |
| from ycode.lm.data import default_sources, prepare_dataset | |
| sources = args.source or default_sources() | |
| if args.sft_only: | |
| from ycode.lm.data import prepare_sft_dataset | |
| if args.tokenizer is None: | |
| print("error: --sft-only needs --tokenizer path/to/tokenizer.json", file=sys.stderr) | |
| return 2 | |
| try: | |
| prepare_sft_dataset(sources, args.out, args.tokenizer, extra_sft=args.sft_data, | |
| exclude=args.exclude) | |
| except (ValueError, OSError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| return 0 | |
| try: | |
| prepare_dataset(sources, args.out, vocab_size=args.vocab_size, extra_sft=args.sft_data, | |
| exclude=args.exclude, workers=args.workers, tokenizer_path=args.tokenizer, | |
| max_mb=args.max_mb) | |
| except (ValueError, OSError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| return 0 | |
| if args.command in ("train", "sft"): | |
| from ycode.lm.train import TrainConfig, train | |
| overrides = {} | |
| if args.command == "train": | |
| for key, attr in (("n_layer", "layers"), ("n_head", "heads"), ("n_embd", "embd"), | |
| ("block_size", "context")): | |
| if getattr(args, attr) is not None: | |
| overrides[key] = getattr(args, attr) | |
| sft = args.command == "sft" | |
| cfg = TrainConfig( | |
| stage="sft" if sft else "pretrain", | |
| preset=getattr(args, "preset", "v2-small"), | |
| model_overrides=overrides, | |
| batch_size=args.batch_size, | |
| grad_accum=args.grad_accum, | |
| lr=args.lr or (3e-4 if sft else 1e-3), | |
| min_lr=(args.lr or (3e-4 if sft else 1e-3)) / 10, | |
| warmup_steps=50 if sft else 100, | |
| max_steps=args.steps or (1000 if sft else 5000), | |
| max_minutes=args.minutes, | |
| eval_interval=args.eval_interval, | |
| eval_iters=args.eval_iters, | |
| device=args.device, | |
| precision=args.precision, | |
| schedule=args.schedule, | |
| compile=args.compile, | |
| grad_checkpoint=args.grad_checkpoint, | |
| shard=args.shard, | |
| optimizer=args.optimizer or ("muon" if str(getattr(args, "preset", "")).startswith("v3") else "adamw"), | |
| muon_lr=args.muon_lr, | |
| pack=not getattr(args, "no_pack", False), | |
| anneal_mix=getattr(args, "anneal_mix", 0.0), | |
| seed=args.seed, | |
| init_from=str(args.init_from) if args.init_from else None, | |
| resume=getattr(args, "resume", False), | |
| until_step=args.until_step, | |
| save_interval=args.save_interval, | |
| ) | |
| out = args.out or default_local_model_dir() | |
| try: | |
| summary = train(args.data, out, cfg) | |
| except (ValueError, FileNotFoundError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| except KeyboardInterrupt: | |
| print("\nInterrupted. The last checkpoint is in", out) | |
| return 130 | |
| if summary: # empty on non-zero ranks of a multi-GPU run; rank 0 reports | |
| print(f"Saved model to {out} (val loss {summary['final']['val']:.3f})") | |
| return 0 | |
| if args.command == "autotrain": | |
| return _autotrain(args) | |
| if args.command == "push-hf": | |
| from ycode.lm.hub import HFHub | |
| try: | |
| hub = HFHub(args.repo, private=not args.public) | |
| hub.upload_folder(args.model, "", f"Upload {args.model.name}") | |
| except Exception as exc: # noqa: BLE001 - network/auth errors become a clear message | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| print(f"Uploaded {args.model} to {hub.url()}") | |
| return 0 | |
| if args.command == "grow": | |
| from ycode.lm.grow import grow_depth, grow_width | |
| from ycode.lm.train import load_checkpoint, save_checkpoint | |
| try: | |
| model, tok, payload = load_checkpoint(args.model) | |
| if args.layers is None and args.width is None: | |
| raise ValueError("pass --layers and/or --width") | |
| grown = model | |
| if args.width is not None and args.width != model.cfg.n_embd: | |
| grown = grow_width(grown, args.width, arch_version=args.version) | |
| if args.layers is not None and args.layers != grown.cfg.n_layer: | |
| grown = grow_depth(grown, args.layers, arch_version=args.version) | |
| except (FileNotFoundError, ValueError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| save_checkpoint(args.out, grown, tok, step=0, stage="grown", val_loss=None) | |
| print(f"Grew {model.cfg.n_layer}x{model.cfg.n_embd} -> {grown.cfg.n_layer}x{grown.cfg.n_embd}: " | |
| f"{model.num_params() / 1e6:.2f}M -> " | |
| f"{grown.num_params() / 1e6:.2f}M parameters, saved to {args.out}") | |
| return 0 | |
| if args.command == "export": | |
| from ycode.lm.train import export_checkpoint | |
| try: | |
| export_checkpoint(args.model, args.out, dtype=args.dtype, max_shard_mb=args.max_shard_mb) | |
| except (FileNotFoundError, ValueError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| files = sorted(args.out.glob("model*.pt")) | |
| total = sum(f.stat().st_size for f in files) / 1e6 | |
| print(f"Exported {args.model} -> {args.out} ({len(files)} file(s), {total:.1f} MB, {args.dtype})") | |
| return 0 | |
| from ycode.lm.generate import LocalLM | |
| if args.command == "eval": | |
| return _eval(args) | |
| model_dir = args.model or default_model_dir() | |
| try: | |
| lm = LocalLM(model_dir, device=args.device) | |
| except (FileNotFoundError, ValueError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| if args.command == "info": | |
| cfg = lm.model.cfg | |
| print(f"Model: {model_dir} (YCode-LM v{lm.version})") | |
| print(f"Parameters: {lm.num_params / 1e6:.2f}M") | |
| print(f"Layers: {cfg.n_layer}, heads {cfg.n_head}, width {cfg.n_embd}, context {cfg.block_size}") | |
| print(f"Vocab: {cfg.vocab_size}") | |
| print(f"Stage: {lm.stage} (step {lm.payload.get('step')}, val loss {lm.payload.get('val_loss')})") | |
| return 0 | |
| def echo(chunk: str) -> None: | |
| sys.stdout.write(chunk) | |
| sys.stdout.flush() | |
| if args.command == "sample": | |
| sys.stdout.write(args.prompt) | |
| lm.complete(args.prompt, max_new_tokens=args.max_tokens, temperature=args.temperature, on_text=echo) | |
| print() | |
| return 0 | |
| print(f"YCode local model ({lm.num_params / 1e6:.1f}M parameters, {lm.stage}). Ctrl+D to quit.") | |
| history: list[tuple[str, str]] = [] | |
| while True: | |
| try: | |
| question = input("\nyou> ").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| print() | |
| return 0 | |
| if not question: | |
| continue | |
| history.append(("user", question)) | |
| sys.stdout.write("model> ") | |
| try: | |
| answer = lm.chat(history[-6:], max_new_tokens=args.max_tokens, temperature=args.temperature, | |
| on_text=echo) | |
| except KeyboardInterrupt: | |
| print("\n(interrupted)") | |
| history.pop() | |
| continue | |
| print() | |
| history.append(("assistant", answer)) | |
| def _autotrain(args) -> int: # noqa: ANN001 | |
| from ycode.lm.autotrain import AutoTrainer, Plan, preset_params | |
| from ycode.lm.hub import HFHub, LocalHub | |
| import torch | |
| nproc = args.nproc if args.nproc is not None else max(1, torch.cuda.device_count()) | |
| big = preset_params(args.preset) > 600e6 | |
| shard = nproc > 1 and (args.shard == "yes" or (args.shard == "auto" and big)) | |
| if big and not shard and torch.cuda.is_available(): | |
| gb = torch.cuda.get_device_properties(0).total_memory / 1e9 | |
| if gb < 40: | |
| print(f"warning: {args.preset} needs about 18 GB of GPU memory for weights and optimizer state " | |
| f"alone; with one {gb:.0f} GB GPU it will likely run out of memory. Use 2+ GPUs " | |
| "(sharded) or a 40 GB+ GPU.", file=sys.stderr) | |
| extra = {k: v for k, v in (("lr", args.lr), ("muon_lr", args.muon_lr)) if v is not None} | |
| plan = Plan(shard=shard, release_shard_mb=1000.0 if big else 45.0, **extra,base_model=str(args.base_model), preset=args.preset, sources=[str(s) for s in args.source], | |
| max_mb=args.max_mb, pretrain_steps=args.pretrain_steps, sft_steps=args.sft_steps, | |
| batch_size=args.batch_size, grad_accum=args.grad_accum, nproc=nproc, precision=args.precision, | |
| grad_checkpoint=not args.no_grad_checkpoint, compile=args.compile, session_hours=args.hours, | |
| segment_minutes=args.segment_minutes, max_segments=args.max_segments, device=args.device, | |
| eval_interval=args.eval_interval) | |
| try: | |
| if args.local_hub is not None: | |
| ckpt, release = LocalHub(args.local_hub, "checkpoints"), LocalHub(args.local_hub, "release") | |
| else: | |
| if not args.hf_repo: | |
| print("error: pass --hf-repo you/ycode-lm-v5 (or --local-hub DIR for a dry run)", file=sys.stderr) | |
| return 2 | |
| ckpt = HFHub(args.ckpt_repo or f"{args.hf_repo}-checkpoints", private=True) | |
| release = HFHub(args.hf_repo, private=not args.public) | |
| state = AutoTrainer(plan, args.work, ckpt, release).run() | |
| except (RuntimeError, ValueError, FileNotFoundError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| print(f"Phase: {state.phase} | pretrain {state.pretrain_step}/{plan.pretrain_steps} | " | |
| f"sft {state.sft_step}/{plan.sft_steps}") | |
| return 0 | |
| def _eval(args) -> int: # noqa: ANN001 | |
| import json | |
| from ycode.lm.evaluate import BUGGY, PROBLEMS, bits_per_byte, bugfix_eval, functional_eval, load_heldout_texts | |
| from ycode.lm.generate import LocalLM | |
| models = args.model or [default_model_dir()] | |
| texts = load_heldout_texts(args.heldout) if args.heldout else [] | |
| if args.heldout and not texts: | |
| print("error: no code found in --heldout", file=sys.stderr) | |
| return 1 | |
| rows = [] | |
| for model_dir in models: | |
| try: | |
| lm = LocalLM(model_dir, device=args.device) | |
| except (FileNotFoundError, ValueError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| print(f"Evaluating {model_dir} (YCode-LM v{lm.version}, {lm.num_params / 1e6:.1f}M params) ...") | |
| row = {"model": str(model_dir), "version": lm.version, "params_m": round(lm.num_params / 1e6, 2)} | |
| if texts: | |
| with lm.precision(): | |
| row["bits_per_byte"] = round(bits_per_byte(lm.model, lm.tokenizer, texts, device=lm.device), 4) | |
| if not args.no_functional: | |
| res = functional_eval(lm, samples=args.samples, log=print if args.verbose else None) | |
| row["pass@1"] = round(res.pass_at_1, 4) | |
| if res.pass_at_k is not None: | |
| row[f"pass@{res.k}"] = round(res.pass_at_k, 4) | |
| row["solved"] = res.solved | |
| fix_rate, fixed = bugfix_eval(lm, log=print if args.verbose else None) | |
| row["fix@1"] = round(fix_rate, 4) | |
| row["fixed"] = fixed | |
| rows.append(row) | |
| print() | |
| header = ["model", "version", "params_m", "bits_per_byte", "pass@1"] + sorted( | |
| {k for r in rows for k in r if k.startswith("pass@") and k != "pass@1"}) + ["fix@1"] | |
| print(" | ".join(h for h in header)) | |
| for r in rows: | |
| print(" | ".join(str(r.get(h, "-")) for h in header)) | |
| if not args.no_functional: | |
| print(f"\n({len(PROBLEMS)} problems, {len(BUGGY)} bug fixes; bits/byte: lower is better; " | |
| "pass@k / fix@1: higher is better)") | |
| for r in rows: | |
| if r.get("solved"): | |
| print(f"{r['model']} solved: {', '.join(r['solved'])}") | |
| print(json.dumps(rows)) | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |