decoding results
Browse files- common.py +837 -0
- decoding.py +558 -0
- decoding_results.json +214 -217
- generations.json +0 -0
common.py
ADDED
|
@@ -0,0 +1,837 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# =============================================================================
|
| 2 |
+
# common.py - shared utilities for ANLP Assignment 2
|
| 3 |
+
# * device / AMP / seeding helpers
|
| 4 |
+
# * Hugging Face Hub helpers (token from Kaggle secrets, push, download)
|
| 5 |
+
# * decoder-only Transformer with pluggable FFN (dense MLP or MoE)
|
| 6 |
+
# * KV-cache + batched greedy/sampled generation (uses model.forward only)
|
| 7 |
+
# =============================================================================
|
| 8 |
+
import os, math, json, time, random, contextlib, shutil, re, sys, glob, hashlib
|
| 9 |
+
from dataclasses import dataclass, asdict, field, fields
|
| 10 |
+
from typing import Optional, List, Dict
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
import torch
|
| 14 |
+
import torch.nn as nn
|
| 15 |
+
from torch.nn import functional as F
|
| 16 |
+
|
| 17 |
+
# -----------------------------------------------------------------------------
|
| 18 |
+
# basic helpers
|
| 19 |
+
# -----------------------------------------------------------------------------
|
| 20 |
+
def seed_everything(seed: int):
|
| 21 |
+
random.seed(seed); np.random.seed(seed); torch.manual_seed(seed)
|
| 22 |
+
if torch.cuda.is_available():
|
| 23 |
+
torch.cuda.manual_seed_all(seed)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def get_device():
|
| 27 |
+
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def amp_dtype(device):
|
| 31 |
+
"""bf16 on Ampere+ (A100/H100/L4), fp16 on Kaggle's T4/P100, None on CPU."""
|
| 32 |
+
if device.type != "cuda":
|
| 33 |
+
return None
|
| 34 |
+
major, _ = torch.cuda.get_device_capability(device)
|
| 35 |
+
return torch.bfloat16 if major >= 8 else torch.float16
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def autocast_ctx(device, dtype):
|
| 39 |
+
if dtype is None:
|
| 40 |
+
return contextlib.nullcontext()
|
| 41 |
+
return torch.autocast(device_type="cuda", dtype=dtype)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def make_grad_scaler(device, dtype):
|
| 45 |
+
enabled = (device.type == "cuda" and dtype == torch.float16)
|
| 46 |
+
try:
|
| 47 |
+
return torch.amp.GradScaler("cuda", enabled=enabled)
|
| 48 |
+
except Exception: # older torch
|
| 49 |
+
return torch.cuda.amp.GradScaler(enabled=enabled)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def fmt_num(n):
|
| 53 |
+
for unit, div in (("B", 1e9), ("M", 1e6), ("K", 1e3)):
|
| 54 |
+
if abs(n) >= div:
|
| 55 |
+
return f"{n/div:.2f}{unit}"
|
| 56 |
+
return str(n)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def save_json(obj, path):
|
| 60 |
+
os.makedirs(os.path.dirname(os.path.abspath(path)), exist_ok=True)
|
| 61 |
+
with open(path, "w", encoding="utf-8") as f:
|
| 62 |
+
json.dump(obj, f, indent=2, ensure_ascii=False, default=_json_default)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def load_json(path):
|
| 66 |
+
with open(path, encoding="utf-8") as f:
|
| 67 |
+
return json.load(f)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def _json_default(o):
|
| 71 |
+
if isinstance(o, (np.integer,)): return int(o)
|
| 72 |
+
if isinstance(o, (np.floating,)): return float(o)
|
| 73 |
+
if isinstance(o, np.ndarray): return o.tolist()
|
| 74 |
+
if isinstance(o, torch.Tensor): return o.tolist()
|
| 75 |
+
if isinstance(o, torch.dtype): return str(o)
|
| 76 |
+
return str(o)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def gpu_name():
|
| 80 |
+
return torch.cuda.get_device_name(0) if torch.cuda.is_available() else "cpu"
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
# -----------------------------------------------------------------------------
|
| 84 |
+
# Hugging Face Hub helpers
|
| 85 |
+
# -----------------------------------------------------------------------------
|
| 86 |
+
TOKENIZER_REPO = "anlp-a2-tokenizers" # holds mt_spm.model and lm_spm.model
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def get_hf_token():
|
| 90 |
+
"""HF token from env var HF_TOKEN or Kaggle secret named HF_TOKEN."""
|
| 91 |
+
tok = os.environ.get("HF_TOKEN")
|
| 92 |
+
if tok:
|
| 93 |
+
return tok
|
| 94 |
+
try:
|
| 95 |
+
from kaggle_secrets import UserSecretsClient
|
| 96 |
+
tok = UserSecretsClient().get_secret("HF_TOKEN")
|
| 97 |
+
if tok:
|
| 98 |
+
os.environ["HF_TOKEN"] = tok
|
| 99 |
+
return tok
|
| 100 |
+
except Exception:
|
| 101 |
+
pass
|
| 102 |
+
return None
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def hf_login(token):
|
| 106 |
+
if not token:
|
| 107 |
+
print("[hf] no HF token found - add a Kaggle secret named HF_TOKEN (write access).")
|
| 108 |
+
return
|
| 109 |
+
try:
|
| 110 |
+
from huggingface_hub import login
|
| 111 |
+
login(token=token, add_to_git_credential=False)
|
| 112 |
+
except Exception as e:
|
| 113 |
+
print("[hf] login failed:", e)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def hf_whoami(token):
|
| 117 |
+
from huggingface_hub import HfApi
|
| 118 |
+
return HfApi(token=token).whoami()["name"]
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def hf_resolve_user(cfg_user, token):
|
| 122 |
+
if cfg_user:
|
| 123 |
+
return cfg_user
|
| 124 |
+
if token:
|
| 125 |
+
try:
|
| 126 |
+
return hf_whoami(token)
|
| 127 |
+
except Exception as e:
|
| 128 |
+
print("[hf] whoami failed:", e)
|
| 129 |
+
return None
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def _retry(fn, tries=4, wait=10):
|
| 133 |
+
last = None
|
| 134 |
+
for i in range(tries):
|
| 135 |
+
try:
|
| 136 |
+
return fn()
|
| 137 |
+
except Exception as e:
|
| 138 |
+
last = e
|
| 139 |
+
print(f"[hf] attempt {i+1}/{tries} failed: {e}")
|
| 140 |
+
time.sleep(wait * (i + 1))
|
| 141 |
+
raise last
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def hf_create_repo(repo_id, token, private=False, repo_type="model"):
|
| 145 |
+
from huggingface_hub import HfApi
|
| 146 |
+
api = HfApi(token=token)
|
| 147 |
+
_retry(lambda: api.create_repo(repo_id, private=private, exist_ok=True, repo_type=repo_type))
|
| 148 |
+
return api
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def hf_push_folder(folder, repo_id, token, private=False, message="upload",
|
| 152 |
+
path_in_repo=None, run_as_future=False, repo_type="model"):
|
| 153 |
+
api = hf_create_repo(repo_id, token, private, repo_type)
|
| 154 |
+
kw = dict(folder_path=folder, repo_id=repo_id, repo_type=repo_type,
|
| 155 |
+
commit_message=message)
|
| 156 |
+
if path_in_repo:
|
| 157 |
+
kw["path_in_repo"] = path_in_repo
|
| 158 |
+
if run_as_future:
|
| 159 |
+
return api.upload_folder(run_as_future=True, **kw)
|
| 160 |
+
return _retry(lambda: api.upload_folder(**kw))
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def hf_push_file(local_path, path_in_repo, repo_id, token, private=False,
|
| 164 |
+
message="upload", run_as_future=False, repo_type="model"):
|
| 165 |
+
api = hf_create_repo(repo_id, token, private, repo_type)
|
| 166 |
+
kw = dict(path_or_fileobj=local_path, path_in_repo=path_in_repo, repo_id=repo_id,
|
| 167 |
+
repo_type=repo_type, commit_message=message)
|
| 168 |
+
if run_as_future:
|
| 169 |
+
return api.upload_file(run_as_future=True, **kw)
|
| 170 |
+
return _retry(lambda: api.upload_file(**kw))
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def hf_try_download(repo_id, filename, token=None, repo_type="model", force=False):
|
| 174 |
+
"""Returns a local path, or None if the repo/file does not exist."""
|
| 175 |
+
try:
|
| 176 |
+
from huggingface_hub import hf_hub_download
|
| 177 |
+
return hf_hub_download(repo_id=repo_id, filename=filename, token=token,
|
| 178 |
+
repo_type=repo_type, force_download=force)
|
| 179 |
+
except Exception as e:
|
| 180 |
+
print(f"[hf] could not download {repo_id}/{filename}: {type(e).__name__}")
|
| 181 |
+
return None
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def hf_list_files(repo_id, token=None, repo_type="model"):
|
| 185 |
+
try:
|
| 186 |
+
from huggingface_hub import HfApi
|
| 187 |
+
return HfApi(token=token).list_repo_files(repo_id, repo_type=repo_type)
|
| 188 |
+
except Exception:
|
| 189 |
+
return []
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
# -----------------------------------------------------------------------------
|
| 193 |
+
# Weights & Biases (assignment: upload training logs to WandB, public links in README/report)
|
| 194 |
+
# Fail-soft: if wandb is missing / not logged in, training continues and logs only to JSON.
|
| 195 |
+
# Auth: `wandb login` or WANDB_API_KEY (Kaggle secret of that name is picked up too).
|
| 196 |
+
# WANDB_MODE=offline logs locally (sync later with `wandb sync`); cfg["wandb"]=False disables.
|
| 197 |
+
# -----------------------------------------------------------------------------
|
| 198 |
+
WANDB_PROJECT = "anlp-a2"
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def _wandb_key():
|
| 202 |
+
key = os.environ.get("WANDB_API_KEY")
|
| 203 |
+
if key:
|
| 204 |
+
return key
|
| 205 |
+
try:
|
| 206 |
+
from kaggle_secrets import UserSecretsClient
|
| 207 |
+
key = UserSecretsClient().get_secret("WANDB_API_KEY")
|
| 208 |
+
if key:
|
| 209 |
+
os.environ["WANDB_API_KEY"] = key
|
| 210 |
+
return key
|
| 211 |
+
except Exception:
|
| 212 |
+
return None
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def wandb_init(cfg, name, config, tags=(), group=None, notes=None, stable_id=False):
|
| 216 |
+
"""Start (or resume, with the same stable id -> requeued jobs continue one run) a W&B run.
|
| 217 |
+
Returns the run, or None when disabled / unavailable."""
|
| 218 |
+
if not cfg.get("wandb", True):
|
| 219 |
+
return None
|
| 220 |
+
try:
|
| 221 |
+
import wandb
|
| 222 |
+
_wandb_key()
|
| 223 |
+
run = wandb.init(project=cfg.get("wandb_project") or WANDB_PROJECT, entity=cfg.get("wandb_entity"),
|
| 224 |
+
name=name, config=config,
|
| 225 |
+
**(dict(id=re.sub(r"[^A-Za-z0-9_-]", "-", name), resume="allow") if stable_id else {}),
|
| 226 |
+
tags=list(tags), group=group, notes=notes,
|
| 227 |
+
settings=wandb.Settings(init_timeout=120, console="off"))
|
| 228 |
+
print("[wandb] run:", getattr(run, "url", None) or "(offline - `wandb sync <dir>` later)")
|
| 229 |
+
return run
|
| 230 |
+
except Exception as e:
|
| 231 |
+
print(f"[wandb] disabled ({type(e).__name__}: {str(e)[:120]}) - logging to JSON only")
|
| 232 |
+
return None
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
def wandb_log(run, data, step=None):
|
| 236 |
+
if run is None:
|
| 237 |
+
return
|
| 238 |
+
try:
|
| 239 |
+
run.log({k: v for k, v in data.items() if v is not None}, step=step)
|
| 240 |
+
except Exception as e:
|
| 241 |
+
print("[wandb] log failed:", e)
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def wandb_images(run, paths, step=None):
|
| 245 |
+
"""paths: {key: png_path}."""
|
| 246 |
+
if run is None:
|
| 247 |
+
return
|
| 248 |
+
try:
|
| 249 |
+
import wandb
|
| 250 |
+
wandb_log(run, {k: wandb.Image(v) for k, v in paths.items() if os.path.exists(v)}, step)
|
| 251 |
+
except Exception as e:
|
| 252 |
+
print("[wandb] image log failed:", e)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def wandb_finish(run, summary=None):
|
| 256 |
+
if run is None:
|
| 257 |
+
return
|
| 258 |
+
try:
|
| 259 |
+
for k, v in (summary or {}).items():
|
| 260 |
+
run.summary[k] = v
|
| 261 |
+
run.finish()
|
| 262 |
+
except Exception as e:
|
| 263 |
+
print("[wandb] finish failed:", e)
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def expert_load_scalars(prefix, loads):
|
| 267 |
+
"""loads: [layer][expert] fractions -> flat {prefix/L{l}_E{e}: x} for W&B."""
|
| 268 |
+
return {f"{prefix}/L{l}_E{e}": float(x) for l, row in enumerate(loads) for e, x in enumerate(row)}
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
# -----------------------------------------------------------------------------
|
| 272 |
+
# Model
|
| 273 |
+
# -----------------------------------------------------------------------------
|
| 274 |
+
@dataclass
|
| 275 |
+
class ModelConfig:
|
| 276 |
+
vocab_size: int = 32000
|
| 277 |
+
block_size: int = 256
|
| 278 |
+
n_layer: int = 6
|
| 279 |
+
n_head: int = 8
|
| 280 |
+
n_embd: int = 512
|
| 281 |
+
dropout: float = 0.0
|
| 282 |
+
bias: bool = False
|
| 283 |
+
# ---- feed-forward ----
|
| 284 |
+
ffn_type: str = "dense" # "dense" | "moe"
|
| 285 |
+
mlp_hidden: int = 0 # dense hidden size (0 -> 4 * n_embd)
|
| 286 |
+
n_experts: int = 4 # number of *routed* experts
|
| 287 |
+
n_shared: int = 0 # number of always-on shared experts
|
| 288 |
+
top_k: int = 1 # routed experts active per token
|
| 289 |
+
expert_hidden: int = 0 # hidden size of each expert (routed & shared)
|
| 290 |
+
aux_loss_coef: float = 0.01 # Switch-style load-balancing loss
|
| 291 |
+
z_loss_coef: float = 1e-3 # router z-loss (ST-MoE)
|
| 292 |
+
|
| 293 |
+
def to_dict(self):
|
| 294 |
+
return asdict(self)
|
| 295 |
+
|
| 296 |
+
@classmethod
|
| 297 |
+
def from_dict(cls, d):
|
| 298 |
+
names = {f.name for f in fields(cls)}
|
| 299 |
+
return cls(**{k: v for k, v in d.items() if k in names})
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
# The five FFN variants of Part 1. H = 4 * d is the dense hidden size.
|
| 303 |
+
# dense : 1 MLP (d -> H -> d) total = active = 2dH
|
| 304 |
+
# moe_4e_top1 : 4 experts of hidden H/4, top-1 total = 2dH, active = 2dH/4
|
| 305 |
+
# moe_4e_top2 : 4 experts of hidden H/4, top-2 total = 2dH, active = 2dH/2
|
| 306 |
+
# moe_1s3r_top1 : 1 shared + 3 routed (hidden H/4), top-1 total = 2dH, active = 2dH/2
|
| 307 |
+
# moe_4e_top2_active: 4 experts of hidden H/2, top-2 total = 4dH, active = 2dH (= dense)
|
| 308 |
+
FFN_VARIANTS = ["dense", "moe_4e_top1", "moe_4e_top2", "moe_1s3r_top1", "moe_4e_top2_active"]
|
| 309 |
+
|
| 310 |
+
FFN_VARIANT_DESCRIPTIONS = {
|
| 311 |
+
"dense": "Standard 2-layer MLP (d -> 4d -> d)",
|
| 312 |
+
"moe_4e_top1": "MoE: 4 experts (hidden d), top-1 routing - same total params as dense",
|
| 313 |
+
"moe_4e_top2": "MoE: 4 experts (hidden d), top-2 routing - same total params as dense",
|
| 314 |
+
"moe_1s3r_top1": "MoE: 1 shared + 3 routed experts (hidden d), top-1 routed - same total params as dense",
|
| 315 |
+
"moe_4e_top2_active": "MoE: 4 experts (hidden 2d), top-2 routing - same ACTIVE params as dense",
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
def ffn_variant_kwargs(name, n_embd):
|
| 320 |
+
H = 4 * n_embd
|
| 321 |
+
if name == "dense":
|
| 322 |
+
return dict(ffn_type="dense", mlp_hidden=H)
|
| 323 |
+
if name == "moe_4e_top1":
|
| 324 |
+
return dict(ffn_type="moe", n_experts=4, n_shared=0, top_k=1, expert_hidden=H // 4)
|
| 325 |
+
if name == "moe_4e_top2":
|
| 326 |
+
return dict(ffn_type="moe", n_experts=4, n_shared=0, top_k=2, expert_hidden=H // 4)
|
| 327 |
+
if name == "moe_1s3r_top1":
|
| 328 |
+
return dict(ffn_type="moe", n_experts=3, n_shared=1, top_k=1, expert_hidden=H // 4)
|
| 329 |
+
if name == "moe_4e_top2_active":
|
| 330 |
+
return dict(ffn_type="moe", n_experts=4, n_shared=0, top_k=2, expert_hidden=H // 2)
|
| 331 |
+
raise ValueError(f"unknown FFN variant {name}")
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
class LayerNorm(nn.Module):
|
| 335 |
+
def __init__(self, ndim, bias):
|
| 336 |
+
super().__init__()
|
| 337 |
+
self.weight = nn.Parameter(torch.ones(ndim))
|
| 338 |
+
self.bias = nn.Parameter(torch.zeros(ndim)) if bias else None
|
| 339 |
+
|
| 340 |
+
def forward(self, x):
|
| 341 |
+
return F.layer_norm(x, self.weight.shape, self.weight, self.bias, 1e-5)
|
| 342 |
+
|
| 343 |
+
|
| 344 |
+
class KVCache:
|
| 345 |
+
"""Simple per-layer key/value cache. Tensors are (B, n_head, T, head_dim)."""
|
| 346 |
+
def __init__(self, n_layer):
|
| 347 |
+
self.k = [None] * n_layer
|
| 348 |
+
self.v = [None] * n_layer
|
| 349 |
+
|
| 350 |
+
@property
|
| 351 |
+
def length(self):
|
| 352 |
+
return 0 if self.k[0] is None else self.k[0].shape[2]
|
| 353 |
+
|
| 354 |
+
def update(self, i, k, v):
|
| 355 |
+
if self.k[i] is None:
|
| 356 |
+
self.k[i], self.v[i] = k, v
|
| 357 |
+
else:
|
| 358 |
+
self.k[i] = torch.cat([self.k[i], k], dim=2)
|
| 359 |
+
self.v[i] = torch.cat([self.v[i], v], dim=2)
|
| 360 |
+
return self.k[i], self.v[i]
|
| 361 |
+
|
| 362 |
+
def reorder(self, idx):
|
| 363 |
+
for i in range(len(self.k)):
|
| 364 |
+
if self.k[i] is not None:
|
| 365 |
+
self.k[i] = self.k[i].index_select(0, idx)
|
| 366 |
+
self.v[i] = self.v[i].index_select(0, idx)
|
| 367 |
+
|
| 368 |
+
|
| 369 |
+
class CausalSelfAttention(nn.Module):
|
| 370 |
+
def __init__(self, cfg: ModelConfig):
|
| 371 |
+
super().__init__()
|
| 372 |
+
assert cfg.n_embd % cfg.n_head == 0
|
| 373 |
+
self.c_attn = nn.Linear(cfg.n_embd, 3 * cfg.n_embd, bias=cfg.bias)
|
| 374 |
+
self.c_proj = nn.Linear(cfg.n_embd, cfg.n_embd, bias=cfg.bias)
|
| 375 |
+
self.resid_dropout = nn.Dropout(cfg.dropout)
|
| 376 |
+
self.n_head, self.n_embd, self.dropout = cfg.n_head, cfg.n_embd, cfg.dropout
|
| 377 |
+
|
| 378 |
+
def forward(self, x, attn_mask=None, cache=None, layer_idx=0):
|
| 379 |
+
B, T, C = x.size()
|
| 380 |
+
q, k, v = self.c_attn(x).split(self.n_embd, dim=2)
|
| 381 |
+
hs = C // self.n_head
|
| 382 |
+
q = q.view(B, T, self.n_head, hs).transpose(1, 2)
|
| 383 |
+
k = k.view(B, T, self.n_head, hs).transpose(1, 2)
|
| 384 |
+
v = v.view(B, T, self.n_head, hs).transpose(1, 2)
|
| 385 |
+
if cache is not None:
|
| 386 |
+
k, v = cache.update(layer_idx, k, v)
|
| 387 |
+
dp = self.dropout if self.training else 0.0
|
| 388 |
+
if attn_mask is None:
|
| 389 |
+
# plain causal attention; valid only when queries and keys are aligned
|
| 390 |
+
assert T == 1 or k.shape[2] == T, "pass an explicit attn_mask when prefilling a non-empty cache"
|
| 391 |
+
y = F.scaled_dot_product_attention(q, k, v, dropout_p=dp, is_causal=(T > 1))
|
| 392 |
+
else:
|
| 393 |
+
y = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask, dropout_p=dp)
|
| 394 |
+
y = y.transpose(1, 2).contiguous().view(B, T, C)
|
| 395 |
+
return self.resid_dropout(self.c_proj(y))
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
class MLP(nn.Module):
|
| 399 |
+
"""Standard 2-layer GELU MLP: d -> hidden -> d."""
|
| 400 |
+
def __init__(self, n_embd, hidden, bias=False, dropout=0.0):
|
| 401 |
+
super().__init__()
|
| 402 |
+
self.c_fc = nn.Linear(n_embd, hidden, bias=bias)
|
| 403 |
+
self.gelu = nn.GELU()
|
| 404 |
+
self.c_proj = nn.Linear(hidden, n_embd, bias=bias)
|
| 405 |
+
self.dropout = nn.Dropout(dropout)
|
| 406 |
+
|
| 407 |
+
def forward(self, x):
|
| 408 |
+
return self.dropout(self.c_proj(self.gelu(self.c_fc(x))))
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
class MoE(nn.Module):
|
| 412 |
+
"""Token-choice top-k Mixture-of-Experts, drop-in replacement for MLP.
|
| 413 |
+
|
| 414 |
+
* router: linear d -> n_experts, softmax over routed experts
|
| 415 |
+
* top-1: output = p_e * E_e(x) (Switch Transformer; keeps router gradient)
|
| 416 |
+
* top-k (k>1): gates renormalised over the chosen k (Mixtral-style)
|
| 417 |
+
* shared experts (DeepSeek-MoE style) are applied to every token and added
|
| 418 |
+
* aux loss = coef * E * sum_e f_e * P_e (+ router z-loss), computed on real tokens only
|
| 419 |
+
* optional tracking of which experts are chosen, per token group (language / segment)
|
| 420 |
+
"""
|
| 421 |
+
def __init__(self, cfg: ModelConfig):
|
| 422 |
+
super().__init__()
|
| 423 |
+
h = cfg.expert_hidden or (4 * cfg.n_embd // max(cfg.n_experts + cfg.n_shared, 1))
|
| 424 |
+
self.n_experts, self.top_k, self.n_shared = cfg.n_experts, cfg.top_k, cfg.n_shared
|
| 425 |
+
self.aux_coef, self.z_coef = cfg.aux_loss_coef, cfg.z_loss_coef
|
| 426 |
+
self.experts = nn.ModuleList([MLP(cfg.n_embd, h, cfg.bias, cfg.dropout) for _ in range(cfg.n_experts)])
|
| 427 |
+
self.shared = nn.ModuleList([MLP(cfg.n_embd, h, cfg.bias, cfg.dropout) for _ in range(cfg.n_shared)])
|
| 428 |
+
self.router = nn.Linear(cfg.n_embd, cfg.n_experts, bias=False)
|
| 429 |
+
self.aux_loss = torch.zeros(())
|
| 430 |
+
# tracking state
|
| 431 |
+
self.track = False
|
| 432 |
+
self.n_groups = 0
|
| 433 |
+
self.counts = None # (n_groups, n_experts) long
|
| 434 |
+
self.token_groups = None # (N,) long, -1 = ignore
|
| 435 |
+
self.load_accum = None # (n_experts,) running fraction for training logs
|
| 436 |
+
self.load_steps = 0
|
| 437 |
+
|
| 438 |
+
def reset_tracking(self, n_groups):
|
| 439 |
+
self.n_groups = n_groups
|
| 440 |
+
self.counts = torch.zeros(n_groups, self.n_experts, dtype=torch.long, device=self.router.weight.device)
|
| 441 |
+
|
| 442 |
+
def forward(self, x, tok_mask=None):
|
| 443 |
+
B, T, C = x.shape
|
| 444 |
+
xf = x.reshape(-1, C)
|
| 445 |
+
N = xf.shape[0]
|
| 446 |
+
if tok_mask is not None:
|
| 447 |
+
sel = tok_mask.reshape(-1).nonzero(as_tuple=True)[0]
|
| 448 |
+
xs = xf.index_select(0, sel)
|
| 449 |
+
else:
|
| 450 |
+
sel, xs = None, xf
|
| 451 |
+
|
| 452 |
+
logits = self.router(xs).float() # (n, E)
|
| 453 |
+
probs = F.softmax(logits, dim=-1)
|
| 454 |
+
topv, topi = probs.topk(self.top_k, dim=-1) # (n, k)
|
| 455 |
+
if self.top_k > 1:
|
| 456 |
+
topv = topv / topv.sum(-1, keepdim=True)
|
| 457 |
+
|
| 458 |
+
out = torch.zeros(xs.shape, dtype=torch.float32, device=xs.device)
|
| 459 |
+
for e, expert in enumerate(self.experts):
|
| 460 |
+
tok, slot = (topi == e).nonzero(as_tuple=True)
|
| 461 |
+
if tok.numel() == 0:
|
| 462 |
+
continue
|
| 463 |
+
y = expert(xs.index_select(0, tok)).float() * topv[tok, slot].unsqueeze(-1)
|
| 464 |
+
out.index_add_(0, tok, y)
|
| 465 |
+
for s in self.shared:
|
| 466 |
+
out = out + s(xs).float()
|
| 467 |
+
|
| 468 |
+
if self.training and xs.shape[0] > 0:
|
| 469 |
+
E = self.n_experts
|
| 470 |
+
f = F.one_hot(topi, E).sum(1).float().mean(0) / self.top_k # fraction of assignments
|
| 471 |
+
P = probs.mean(0) # mean router prob
|
| 472 |
+
aux = E * (f * P).sum()
|
| 473 |
+
z = torch.logsumexp(logits, dim=-1).pow(2).mean()
|
| 474 |
+
self.aux_loss = self.aux_coef * aux + self.z_coef * z
|
| 475 |
+
with torch.no_grad():
|
| 476 |
+
self.load_accum = f.detach() if self.load_accum is None else self.load_accum + f.detach()
|
| 477 |
+
self.load_steps += 1
|
| 478 |
+
else:
|
| 479 |
+
self.aux_loss = torch.zeros((), device=x.device)
|
| 480 |
+
|
| 481 |
+
if self.track and self.token_groups is not None:
|
| 482 |
+
with torch.no_grad():
|
| 483 |
+
g = self.token_groups.reshape(-1)
|
| 484 |
+
if sel is not None:
|
| 485 |
+
g = g.index_select(0, sel)
|
| 486 |
+
g = g.unsqueeze(1).expand_as(topi)
|
| 487 |
+
ok = g >= 0
|
| 488 |
+
flat = (g[ok] * self.n_experts + topi[ok]).reshape(-1)
|
| 489 |
+
self.counts += torch.bincount(flat, minlength=self.n_groups * self.n_experts).view(
|
| 490 |
+
self.n_groups, self.n_experts)
|
| 491 |
+
|
| 492 |
+
out = out.to(x.dtype)
|
| 493 |
+
if sel is not None:
|
| 494 |
+
full = torch.zeros_like(xf)
|
| 495 |
+
full.index_copy_(0, sel, out)
|
| 496 |
+
out = full
|
| 497 |
+
return out.view(B, T, C)
|
| 498 |
+
|
| 499 |
+
|
| 500 |
+
class Block(nn.Module):
|
| 501 |
+
def __init__(self, cfg: ModelConfig):
|
| 502 |
+
super().__init__()
|
| 503 |
+
self.ln_1 = LayerNorm(cfg.n_embd, cfg.bias)
|
| 504 |
+
self.attn = CausalSelfAttention(cfg)
|
| 505 |
+
self.ln_2 = LayerNorm(cfg.n_embd, cfg.bias)
|
| 506 |
+
if cfg.ffn_type == "moe":
|
| 507 |
+
self.ffn = MoE(cfg)
|
| 508 |
+
else:
|
| 509 |
+
self.ffn = MLP(cfg.n_embd, cfg.mlp_hidden or 4 * cfg.n_embd, cfg.bias, cfg.dropout)
|
| 510 |
+
self.is_moe = cfg.ffn_type == "moe"
|
| 511 |
+
|
| 512 |
+
def forward(self, x, attn_mask=None, cache=None, layer_idx=0, tok_mask=None):
|
| 513 |
+
x = x + self.attn(self.ln_1(x), attn_mask, cache, layer_idx)
|
| 514 |
+
h = self.ln_2(x)
|
| 515 |
+
x = x + (self.ffn(h, tok_mask) if self.is_moe else self.ffn(h))
|
| 516 |
+
return x
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
class Transformer(nn.Module):
|
| 520 |
+
def __init__(self, cfg: ModelConfig):
|
| 521 |
+
super().__init__()
|
| 522 |
+
self.config = cfg
|
| 523 |
+
self.transformer = nn.ModuleDict(dict(
|
| 524 |
+
wte=nn.Embedding(cfg.vocab_size, cfg.n_embd),
|
| 525 |
+
wpe=nn.Embedding(cfg.block_size, cfg.n_embd),
|
| 526 |
+
drop=nn.Dropout(cfg.dropout),
|
| 527 |
+
h=nn.ModuleList([Block(cfg) for _ in range(cfg.n_layer)]),
|
| 528 |
+
ln_f=LayerNorm(cfg.n_embd, cfg.bias),
|
| 529 |
+
))
|
| 530 |
+
self.lm_head = nn.Linear(cfg.n_embd, cfg.vocab_size, bias=False)
|
| 531 |
+
self.transformer.wte.weight = self.lm_head.weight # weight tying
|
| 532 |
+
self.apply(self._init_weights)
|
| 533 |
+
for pn, p in self.named_parameters():
|
| 534 |
+
if pn.endswith("c_proj.weight"):
|
| 535 |
+
torch.nn.init.normal_(p, mean=0.0, std=0.02 / math.sqrt(2 * cfg.n_layer))
|
| 536 |
+
|
| 537 |
+
def _init_weights(self, m):
|
| 538 |
+
if isinstance(m, nn.Linear):
|
| 539 |
+
torch.nn.init.normal_(m.weight, mean=0.0, std=0.02)
|
| 540 |
+
if m.bias is not None:
|
| 541 |
+
torch.nn.init.zeros_(m.bias)
|
| 542 |
+
elif isinstance(m, nn.Embedding):
|
| 543 |
+
torch.nn.init.normal_(m.weight, mean=0.0, std=0.02)
|
| 544 |
+
|
| 545 |
+
# ---- MoE helpers ----
|
| 546 |
+
def moe_layers(self):
|
| 547 |
+
return [b.ffn for b in self.transformer.h if isinstance(b.ffn, MoE)]
|
| 548 |
+
|
| 549 |
+
# ---- forward ----
|
| 550 |
+
def hidden_states(self, idx, pos=None, attn_mask=None, cache=None, tok_mask=None):
|
| 551 |
+
B, T = idx.shape
|
| 552 |
+
if pos is None:
|
| 553 |
+
start = cache.length if cache is not None else 0
|
| 554 |
+
assert start + T <= self.config.block_size, f"sequence length {start+T} > block_size"
|
| 555 |
+
pos = torch.arange(start, start + T, device=idx.device).unsqueeze(0)
|
| 556 |
+
x = self.transformer.drop(self.transformer.wte(idx) + self.transformer.wpe(pos))
|
| 557 |
+
for i, block in enumerate(self.transformer.h):
|
| 558 |
+
x = block(x, attn_mask, cache, i, tok_mask)
|
| 559 |
+
return self.transformer.ln_f(x)
|
| 560 |
+
|
| 561 |
+
def aux_loss(self):
|
| 562 |
+
layers = self.moe_layers()
|
| 563 |
+
if not layers:
|
| 564 |
+
return None
|
| 565 |
+
return sum(m.aux_loss for m in layers)
|
| 566 |
+
|
| 567 |
+
def forward(self, idx, targets=None, pos=None, attn_mask=None, cache=None,
|
| 568 |
+
tok_mask=None, last_only=False):
|
| 569 |
+
"""targets: (B,T) with -1 = ignore. Returns (logits, loss, aux_loss).
|
| 570 |
+
When targets are given, logits are only computed on supervised positions
|
| 571 |
+
(saves the big vocab projection on source / padding tokens) and None is returned."""
|
| 572 |
+
x = self.hidden_states(idx, pos, attn_mask, cache, tok_mask)
|
| 573 |
+
aux = self.aux_loss()
|
| 574 |
+
if targets is not None:
|
| 575 |
+
valid = targets != -1
|
| 576 |
+
logits = self.lm_head(x[valid])
|
| 577 |
+
loss = F.cross_entropy(logits.float(), targets[valid])
|
| 578 |
+
return None, loss, aux
|
| 579 |
+
if last_only:
|
| 580 |
+
x = x[:, -1:, :]
|
| 581 |
+
return self.lm_head(x), None, aux
|
| 582 |
+
|
| 583 |
+
@torch.no_grad()
|
| 584 |
+
def token_nll(self, idx, targets, tok_mask=None):
|
| 585 |
+
"""Per-token NLL (B,T), 0 where targets == -1."""
|
| 586 |
+
x = self.hidden_states(idx, tok_mask=tok_mask)
|
| 587 |
+
valid = targets != -1
|
| 588 |
+
out = torch.zeros(targets.shape, dtype=torch.float32, device=idx.device)
|
| 589 |
+
logits = self.lm_head(x[valid]).float()
|
| 590 |
+
out[valid] = F.cross_entropy(logits, targets[valid], reduction="none")
|
| 591 |
+
return out
|
| 592 |
+
|
| 593 |
+
|
| 594 |
+
# ---- parameter accounting ----
|
| 595 |
+
def _numel(m):
|
| 596 |
+
return sum(p.numel() for p in m.parameters())
|
| 597 |
+
|
| 598 |
+
|
| 599 |
+
def param_report(model: Transformer):
|
| 600 |
+
cfg = model.config
|
| 601 |
+
seen, total = set(), 0
|
| 602 |
+
for p in model.parameters():
|
| 603 |
+
if id(p) not in seen:
|
| 604 |
+
seen.add(id(p)); total += p.numel()
|
| 605 |
+
emb = model.transformer.wte.weight.numel() + model.transformer.wpe.weight.numel()
|
| 606 |
+
ffn_total = ffn_active = router = 0
|
| 607 |
+
for b in model.transformer.h:
|
| 608 |
+
f = b.ffn
|
| 609 |
+
if isinstance(f, MoE):
|
| 610 |
+
per_exp = _numel(f.experts[0])
|
| 611 |
+
r = _numel(f.router)
|
| 612 |
+
sh = sum(_numel(s) for s in f.shared)
|
| 613 |
+
ffn_total += per_exp * f.n_experts + sh + r
|
| 614 |
+
ffn_active += per_exp * f.top_k + sh + r
|
| 615 |
+
router += r
|
| 616 |
+
else:
|
| 617 |
+
ffn_total += _numel(f); ffn_active += _numel(f)
|
| 618 |
+
non_ffn = total - ffn_total
|
| 619 |
+
return {
|
| 620 |
+
"total_params": total,
|
| 621 |
+
"active_params_per_token": non_ffn + ffn_active,
|
| 622 |
+
"embedding_params": emb,
|
| 623 |
+
"total_non_embedding": total - emb,
|
| 624 |
+
"active_non_embedding": non_ffn + ffn_active - emb,
|
| 625 |
+
"ffn_total_params": ffn_total,
|
| 626 |
+
"ffn_active_params": ffn_active,
|
| 627 |
+
"router_params": router,
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
|
| 631 |
+
def print_param_report(rep, title=""):
|
| 632 |
+
print(f"--- parameters {title} ---")
|
| 633 |
+
for k, v in rep.items():
|
| 634 |
+
print(f" {k:26s} {v:>12,d} ({fmt_num(v)})")
|
| 635 |
+
|
| 636 |
+
|
| 637 |
+
# ---- save / load (safetensors handles the tied embedding) ----
|
| 638 |
+
def save_model_dir(model, out_dir, extra_config=None):
|
| 639 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 640 |
+
try:
|
| 641 |
+
from safetensors.torch import save_model
|
| 642 |
+
save_model(model, os.path.join(out_dir, "model.safetensors"))
|
| 643 |
+
except Exception as e:
|
| 644 |
+
print("[save] safetensors failed, falling back to torch.save:", e)
|
| 645 |
+
torch.save(model.state_dict(), os.path.join(out_dir, "pytorch_model.bin"))
|
| 646 |
+
cfg = model.config.to_dict()
|
| 647 |
+
if extra_config:
|
| 648 |
+
cfg.update(extra_config)
|
| 649 |
+
save_json(cfg, os.path.join(out_dir, "config.json"))
|
| 650 |
+
|
| 651 |
+
|
| 652 |
+
def load_model_dir(path_or_repo, token=None, device="cpu"):
|
| 653 |
+
"""Load a model saved by save_model_dir from a local dir or a HF repo id."""
|
| 654 |
+
if os.path.isdir(path_or_repo):
|
| 655 |
+
d = path_or_repo
|
| 656 |
+
cfg_path = os.path.join(d, "config.json")
|
| 657 |
+
st = os.path.join(d, "model.safetensors")
|
| 658 |
+
else:
|
| 659 |
+
cfg_path = hf_try_download(path_or_repo, "config.json", token)
|
| 660 |
+
st = hf_try_download(path_or_repo, "model.safetensors", token)
|
| 661 |
+
cfg = ModelConfig.from_dict(load_json(cfg_path))
|
| 662 |
+
model = Transformer(cfg)
|
| 663 |
+
from safetensors.torch import load_model
|
| 664 |
+
load_model(model, st, device="cpu")
|
| 665 |
+
return model.to(device)
|
| 666 |
+
|
| 667 |
+
|
| 668 |
+
# -----------------------------------------------------------------------------
|
| 669 |
+
# Generation (KV cache, left padding, batched). Uses model.forward only.
|
| 670 |
+
# -----------------------------------------------------------------------------
|
| 671 |
+
@torch.no_grad()
|
| 672 |
+
def generate(model, prompts: List[List[int]], max_new_tokens: int, eos_id: Optional[int],
|
| 673 |
+
pad_id: int = 0, temperature: float = 0.0, top_k: Optional[int] = None,
|
| 674 |
+
device=None, amp=None, generator=None):
|
| 675 |
+
"""Batched autoregressive generation. temperature=0 -> greedy.
|
| 676 |
+
Returns list of generated token lists (EOS stripped)."""
|
| 677 |
+
device = device or next(model.parameters()).device
|
| 678 |
+
model.eval()
|
| 679 |
+
B = len(prompts)
|
| 680 |
+
L = max(len(p) for p in prompts)
|
| 681 |
+
max_new_tokens = min(max_new_tokens, model.config.block_size - L)
|
| 682 |
+
idx = torch.full((B, L), pad_id, dtype=torch.long)
|
| 683 |
+
valid = torch.zeros((B, L), dtype=torch.bool)
|
| 684 |
+
for i, p in enumerate(prompts):
|
| 685 |
+
idx[i, L - len(p):] = torch.tensor(p, dtype=torch.long)
|
| 686 |
+
valid[i, L - len(p):] = True
|
| 687 |
+
idx, valid = idx.to(device), valid.to(device)
|
| 688 |
+
pos = (valid.long().cumsum(1) - 1).clamp(min=0)
|
| 689 |
+
causal = torch.tril(torch.ones(L, L, dtype=torch.bool, device=device))
|
| 690 |
+
eye = torch.eye(L, dtype=torch.bool, device=device)
|
| 691 |
+
# key must be valid (not left padding); always allow self-attention so pad rows never go NaN
|
| 692 |
+
mask = (causal[None, None] & valid[:, None, None, :]) | eye[None, None]
|
| 693 |
+
cache = KVCache(model.config.n_layer)
|
| 694 |
+
with autocast_ctx(device, amp):
|
| 695 |
+
logits, _, _ = model(idx, pos=pos, attn_mask=mask, cache=cache, last_only=True)
|
| 696 |
+
next_pos = pos[:, -1] + 1
|
| 697 |
+
finished = torch.zeros(B, dtype=torch.bool, device=device)
|
| 698 |
+
outs = []
|
| 699 |
+
for _ in range(max_new_tokens):
|
| 700 |
+
lg = logits[:, -1, :].float()
|
| 701 |
+
if temperature and temperature > 0:
|
| 702 |
+
lg = lg / temperature
|
| 703 |
+
if top_k:
|
| 704 |
+
v, _ = torch.topk(lg, min(top_k, lg.size(-1)))
|
| 705 |
+
lg[lg < v[:, [-1]]] = -float("inf")
|
| 706 |
+
nxt = torch.multinomial(F.softmax(lg, -1), 1, generator=generator).squeeze(1)
|
| 707 |
+
else:
|
| 708 |
+
nxt = lg.argmax(-1)
|
| 709 |
+
nxt = torch.where(finished, torch.full_like(nxt, pad_id), nxt)
|
| 710 |
+
outs.append(nxt)
|
| 711 |
+
if eos_id is not None:
|
| 712 |
+
finished |= nxt == eos_id
|
| 713 |
+
if bool(finished.all()):
|
| 714 |
+
break
|
| 715 |
+
valid = torch.cat([valid, torch.ones(B, 1, dtype=torch.bool, device=device)], 1)
|
| 716 |
+
with autocast_ctx(device, amp):
|
| 717 |
+
logits, _, _ = model(nxt[:, None], pos=next_pos[:, None], attn_mask=valid[:, None, None, :],
|
| 718 |
+
cache=cache, last_only=True)
|
| 719 |
+
next_pos = next_pos + 1
|
| 720 |
+
if not outs:
|
| 721 |
+
return [[] for _ in range(B)]
|
| 722 |
+
gen = torch.stack(outs, 1).tolist()
|
| 723 |
+
res = []
|
| 724 |
+
for row in gen:
|
| 725 |
+
if eos_id is not None and eos_id in row:
|
| 726 |
+
row = row[:row.index(eos_id)]
|
| 727 |
+
res.append(row)
|
| 728 |
+
return res
|
| 729 |
+
|
| 730 |
+
|
| 731 |
+
@torch.no_grad()
|
| 732 |
+
def generate_sorted(model, prompts, max_new_tokens, eos_id, pad_id=0, batch_size=64,
|
| 733 |
+
device=None, amp=None, progress=False, **kw):
|
| 734 |
+
"""Sort prompts by length for efficient batching, restore the original order."""
|
| 735 |
+
order = sorted(range(len(prompts)), key=lambda i: len(prompts[i]))
|
| 736 |
+
out = [None] * len(prompts)
|
| 737 |
+
t0 = time.time()
|
| 738 |
+
for bi, s in enumerate(range(0, len(order), batch_size)):
|
| 739 |
+
ids = order[s:s + batch_size]
|
| 740 |
+
res = generate(model, [prompts[i] for i in ids], max_new_tokens, eos_id, pad_id,
|
| 741 |
+
device=device, amp=amp, **kw)
|
| 742 |
+
for i, r in zip(ids, res):
|
| 743 |
+
out[i] = r
|
| 744 |
+
if progress and bi % 20 == 0:
|
| 745 |
+
print(f" generated {min(s+batch_size, len(order))}/{len(order)} ({time.time()-t0:.0f}s)")
|
| 746 |
+
return out
|
| 747 |
+
|
| 748 |
+
|
| 749 |
+
# -----------------------------------------------------------------------------
|
| 750 |
+
# HAP-E split (Part 2) - shared by the tokenizer notebook and the LM runs
|
| 751 |
+
# -----------------------------------------------------------------------------
|
| 752 |
+
def hape_split(doc_ids, seed=0, val_frac=0.05, test_frac=0.05):
|
| 753 |
+
"""Deterministic split by base document id. Returns dict base -> 'train'|'val'|'test'."""
|
| 754 |
+
bases = sorted({d.split("@")[0] for d in doc_ids})
|
| 755 |
+
rng = np.random.default_rng(seed)
|
| 756 |
+
perm = rng.permutation(len(bases))
|
| 757 |
+
n_val, n_test = int(len(bases) * val_frac), int(len(bases) * test_frac)
|
| 758 |
+
split = {}
|
| 759 |
+
for rank, i in enumerate(perm):
|
| 760 |
+
split[bases[i]] = "val" if rank < n_val else ("test" if rank < n_val + n_test else "train")
|
| 761 |
+
return split
|
| 762 |
+
|
| 763 |
+
|
| 764 |
+
# -----------------------------------------------------------------------------
|
| 765 |
+
# LR schedule
|
| 766 |
+
# -----------------------------------------------------------------------------
|
| 767 |
+
def lr_factor(step, total_steps, warmup_steps, min_ratio=0.1):
|
| 768 |
+
"""Linear warmup then cosine decay to min_ratio."""
|
| 769 |
+
if step < warmup_steps:
|
| 770 |
+
return (step + 1) / max(1, warmup_steps)
|
| 771 |
+
prog = (step - warmup_steps) / max(1, total_steps - warmup_steps)
|
| 772 |
+
prog = min(max(prog, 0.0), 1.0)
|
| 773 |
+
return min_ratio + (1 - min_ratio) * 0.5 * (1 + math.cos(math.pi * prog))
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
def set_lr(optimizer, factor):
|
| 777 |
+
for g in optimizer.param_groups:
|
| 778 |
+
if "base_lr" not in g:
|
| 779 |
+
g["base_lr"] = g["lr"]
|
| 780 |
+
g["lr"] = g["base_lr"] * factor
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
# -----------------------------------------------------------------------------
|
| 784 |
+
# run several jobs at once, one per GPU (e.g. Kaggle "GPU T4 x2")
|
| 785 |
+
# -----------------------------------------------------------------------------
|
| 786 |
+
def launch_parallel(jobs, poll_s=180, tail=3):
|
| 787 |
+
"""jobs: list of (name, python_code). Job i runs in its own process on GPU i.
|
| 788 |
+
Output goes to <name>.log; the last lines of every log are printed every poll_s seconds."""
|
| 789 |
+
import subprocess
|
| 790 |
+
get_hf_token() # puts HF_TOKEN into os.environ for the children
|
| 791 |
+
n_gpu = max(torch.cuda.device_count(), 1)
|
| 792 |
+
assert len(jobs) <= n_gpu, f"{len(jobs)} jobs but only {n_gpu} GPU(s)"
|
| 793 |
+
procs = []
|
| 794 |
+
for gpu, (name, code) in enumerate(jobs):
|
| 795 |
+
env = dict(os.environ, CUDA_VISIBLE_DEVICES=str(gpu), PYTHONUNBUFFERED="1")
|
| 796 |
+
logf = open(f"{name}.log", "w")
|
| 797 |
+
procs.append((name, subprocess.Popen([sys.executable, "-u", "-c", code], env=env,
|
| 798 |
+
stdout=logf, stderr=subprocess.STDOUT), logf))
|
| 799 |
+
print(f"started {name} on GPU {gpu} (log: {name}.log)")
|
| 800 |
+
while True:
|
| 801 |
+
time.sleep(poll_s)
|
| 802 |
+
alive = False
|
| 803 |
+
for name, p, _ in procs:
|
| 804 |
+
alive |= p.poll() is None
|
| 805 |
+
try:
|
| 806 |
+
lines = open(f"{name}.log").read().splitlines()[-tail:]
|
| 807 |
+
except Exception:
|
| 808 |
+
lines = []
|
| 809 |
+
print(f"--- {name} ({'running' if p.poll() is None else 'exit ' + str(p.returncode)}) ---")
|
| 810 |
+
for l in lines:
|
| 811 |
+
print(" ", l[:200])
|
| 812 |
+
if not alive:
|
| 813 |
+
break
|
| 814 |
+
for _, _, f in procs:
|
| 815 |
+
f.close()
|
| 816 |
+
codes = {name: p.returncode for name, p, _ in procs}
|
| 817 |
+
print("exit codes:", codes)
|
| 818 |
+
return codes
|
| 819 |
+
|
| 820 |
+
|
| 821 |
+
# -----------------------------------------------------------------------------
|
| 822 |
+
# Plot style (validated categorical palette, fixed order)
|
| 823 |
+
# -----------------------------------------------------------------------------
|
| 824 |
+
PALETTE = ["#2a78d6", "#eb6834", "#1baf7a", "#eda100", "#e87ba4", "#008300", "#4a3aa7", "#e34948"]
|
| 825 |
+
|
| 826 |
+
|
| 827 |
+
def setup_plot_style():
|
| 828 |
+
import matplotlib as mpl
|
| 829 |
+
mpl.rcParams.update({
|
| 830 |
+
"figure.dpi": 110, "savefig.dpi": 150, "savefig.bbox": "tight",
|
| 831 |
+
"axes.spines.top": False, "axes.spines.right": False,
|
| 832 |
+
"axes.grid": True, "grid.color": "#e4e3df", "grid.linewidth": 0.8,
|
| 833 |
+
"axes.edgecolor": "#8a8984", "axes.labelcolor": "#2b2a27",
|
| 834 |
+
"xtick.color": "#52514e", "ytick.color": "#52514e",
|
| 835 |
+
"axes.prop_cycle": mpl.cycler(color=PALETTE),
|
| 836 |
+
"lines.linewidth": 2.0, "legend.frameon": False, "font.size": 10,
|
| 837 |
+
})
|
decoding.py
ADDED
|
@@ -0,0 +1,558 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# =============================================================================
|
| 2 |
+
# decoding.py - Part 3: decoding strategies implemented from scratch on top of
|
| 3 |
+
# EleutherAI/pythia-160m. Only model.forward() (i.e. model(...)) is used -
|
| 4 |
+
# never model.generate().
|
| 5 |
+
#
|
| 6 |
+
# greedy, beam search (width 1/2/4/...), top-k sampling, top-p (nucleus) sampling
|
| 7 |
+
#
|
| 8 |
+
# Evaluated on hamishivi/ROCStories (test split): prompt = first sentence,
|
| 9 |
+
# reference = the remaining four sentences.
|
| 10 |
+
# =============================================================================
|
| 11 |
+
import os, re, math, time, json, string
|
| 12 |
+
from collections import Counter
|
| 13 |
+
import numpy as np
|
| 14 |
+
import torch
|
| 15 |
+
import torch.nn.functional as F
|
| 16 |
+
|
| 17 |
+
DECODING_DEFAULTS = dict(
|
| 18 |
+
model_name="EleutherAI/pythia-160m",
|
| 19 |
+
dataset="hamishivi/ROCStories", split="test", n_samples=1000, seed=0,
|
| 20 |
+
max_new_tokens=70, batch_size=32, beam_batch_size=8, dtype="float32",
|
| 21 |
+
length_penalty=1.0,
|
| 22 |
+
configs=[
|
| 23 |
+
{"name": "greedy", "strategy": "greedy"},
|
| 24 |
+
{"name": "beam_w1", "strategy": "beam", "width": 1},
|
| 25 |
+
{"name": "beam_w2", "strategy": "beam", "width": 2},
|
| 26 |
+
{"name": "beam_w4", "strategy": "beam", "width": 4},
|
| 27 |
+
{"name": "topk_k5", "strategy": "top_k", "k": 5},
|
| 28 |
+
{"name": "topk_k20", "strategy": "top_k", "k": 20},
|
| 29 |
+
{"name": "topk_k50", "strategy": "top_k", "k": 50},
|
| 30 |
+
{"name": "topk_k50_t0.7", "strategy": "top_k", "k": 50, "temperature": 0.7},
|
| 31 |
+
{"name": "topp_p0.5", "strategy": "top_p", "p": 0.5},
|
| 32 |
+
{"name": "topp_p0.8", "strategy": "top_p", "p": 0.8},
|
| 33 |
+
{"name": "topp_p0.95", "strategy": "top_p", "p": 0.95},
|
| 34 |
+
{"name": "topp_p0.9_t0.7", "strategy": "top_p", "p": 0.9, "temperature": 0.7},
|
| 35 |
+
],
|
| 36 |
+
timing_widths=[1, 2, 4, 8], timing_samples=100,
|
| 37 |
+
judge_model="EleutherAI/pythia-410m", # external LM for an extra perplexity column (None to skip)
|
| 38 |
+
use_bertscore=True,
|
| 39 |
+
out_dir="/kaggle/working/outputs/decoding" if os.path.isdir("/kaggle/working") else "outputs/decoding",
|
| 40 |
+
hf_user=None, repo_name="anlp-a2-decoding", push_to_hub=True, private=False,
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# -----------------------------------------------------------------------------
|
| 45 |
+
# model wrapper: one forward step with KV cache
|
| 46 |
+
# -----------------------------------------------------------------------------
|
| 47 |
+
def load_lm(name, device, dtype="float32"):
|
| 48 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 49 |
+
tok = AutoTokenizer.from_pretrained(name)
|
| 50 |
+
dt = {"float32": torch.float32, "float16": torch.float16, "bfloat16": torch.bfloat16}[dtype]
|
| 51 |
+
try:
|
| 52 |
+
model = AutoModelForCausalLM.from_pretrained(name, dtype=dt)
|
| 53 |
+
except TypeError:
|
| 54 |
+
model = AutoModelForCausalLM.from_pretrained(name, torch_dtype=dt)
|
| 55 |
+
model.to(device).eval()
|
| 56 |
+
if tok.pad_token_id is None:
|
| 57 |
+
tok.pad_token = tok.eos_token
|
| 58 |
+
return model, tok
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def reorder_cache(past, idx):
|
| 62 |
+
"""Select rows (beams) of a KV cache - works for legacy tuples and Cache objects."""
|
| 63 |
+
if past is None:
|
| 64 |
+
return None
|
| 65 |
+
if isinstance(past, (tuple, list)):
|
| 66 |
+
return tuple(tuple(t.index_select(0, idx) for t in layer) for layer in past)
|
| 67 |
+
if hasattr(past, "reorder_cache"):
|
| 68 |
+
past.reorder_cache(idx)
|
| 69 |
+
return past
|
| 70 |
+
if hasattr(past, "layers"): # transformers >= 4.56 DynamicCache
|
| 71 |
+
for layer in past.layers:
|
| 72 |
+
layer.keys = layer.keys.index_select(0, idx)
|
| 73 |
+
layer.values = layer.values.index_select(0, idx)
|
| 74 |
+
return past
|
| 75 |
+
if hasattr(past, "key_cache"):
|
| 76 |
+
for i in range(len(past.key_cache)):
|
| 77 |
+
past.key_cache[i] = past.key_cache[i].index_select(0, idx)
|
| 78 |
+
past.value_cache[i] = past.value_cache[i].index_select(0, idx)
|
| 79 |
+
return past
|
| 80 |
+
raise TypeError(f"cannot reorder cache of type {type(past)}")
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
@torch.no_grad()
|
| 84 |
+
def forward_step(model, input_ids, attention_mask, position_ids, past):
|
| 85 |
+
out = model(input_ids=input_ids, attention_mask=attention_mask, position_ids=position_ids,
|
| 86 |
+
past_key_values=past, use_cache=True)
|
| 87 |
+
return out.logits[:, -1, :].float(), out.past_key_values
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def left_pad(prompts, pad_id, device):
|
| 91 |
+
L = max(len(p) for p in prompts)
|
| 92 |
+
ids = torch.full((len(prompts), L), pad_id, dtype=torch.long)
|
| 93 |
+
mask = torch.zeros((len(prompts), L), dtype=torch.long)
|
| 94 |
+
for i, p in enumerate(prompts):
|
| 95 |
+
ids[i, L - len(p):] = torch.tensor(p)
|
| 96 |
+
mask[i, L - len(p):] = 1
|
| 97 |
+
pos = (mask.cumsum(1) - 1).clamp(min=0)
|
| 98 |
+
return ids.to(device), mask.to(device), pos.to(device)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# -----------------------------------------------------------------------------
|
| 102 |
+
# logit processors
|
| 103 |
+
# -----------------------------------------------------------------------------
|
| 104 |
+
def top_k_filter(logits, k):
|
| 105 |
+
k = min(k, logits.size(-1))
|
| 106 |
+
kth = torch.topk(logits, k, dim=-1).values[:, -1:]
|
| 107 |
+
return logits.masked_fill(logits < kth, float("-inf"))
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def top_p_filter(logits, p):
|
| 111 |
+
"""Keep the smallest set of tokens whose cumulative probability >= p (always >= 1 token)."""
|
| 112 |
+
sorted_logits, sorted_idx = torch.sort(logits, descending=True, dim=-1)
|
| 113 |
+
probs = F.softmax(sorted_logits, dim=-1)
|
| 114 |
+
cum = probs.cumsum(-1)
|
| 115 |
+
remove = (cum - probs) >= p # mass *before* this token already reaches p
|
| 116 |
+
remove[:, 0] = False
|
| 117 |
+
sorted_logits = sorted_logits.masked_fill(remove, float("-inf"))
|
| 118 |
+
return torch.full_like(logits, float("-inf")).scatter(-1, sorted_idx, sorted_logits)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
# -----------------------------------------------------------------------------
|
| 122 |
+
# greedy / top-k / top-p (batched)
|
| 123 |
+
# -----------------------------------------------------------------------------
|
| 124 |
+
@torch.no_grad()
|
| 125 |
+
def sample_decode(model, prompts, max_new_tokens, eos_id, pad_id, strategy="greedy", k=None, p=None,
|
| 126 |
+
temperature=1.0, generator=None):
|
| 127 |
+
"""Returns (list of generated id lists, list of sum log-prob under the *unmodified*
|
| 128 |
+
model distribution, list of lengths)."""
|
| 129 |
+
device = next(model.parameters()).device
|
| 130 |
+
B = len(prompts)
|
| 131 |
+
ids, mask, pos = left_pad(prompts, pad_id, device)
|
| 132 |
+
logits, past = forward_step(model, ids, mask, pos, None)
|
| 133 |
+
next_pos = pos[:, -1:] + 1
|
| 134 |
+
finished = torch.zeros(B, dtype=torch.bool, device=device)
|
| 135 |
+
out, lp_sum, lengths = [], torch.zeros(B, device=device), torch.zeros(B, dtype=torch.long, device=device)
|
| 136 |
+
for _ in range(max_new_tokens):
|
| 137 |
+
logp = F.log_softmax(logits, -1)
|
| 138 |
+
if strategy == "greedy":
|
| 139 |
+
nxt = logits.argmax(-1)
|
| 140 |
+
else:
|
| 141 |
+
lg = logits / max(temperature, 1e-6)
|
| 142 |
+
if strategy == "top_k":
|
| 143 |
+
lg = top_k_filter(lg, k)
|
| 144 |
+
elif strategy == "top_p":
|
| 145 |
+
lg = top_p_filter(lg, p)
|
| 146 |
+
nxt = torch.multinomial(F.softmax(lg, -1), 1, generator=generator).squeeze(1)
|
| 147 |
+
nxt = torch.where(finished, torch.full_like(nxt, pad_id), nxt)
|
| 148 |
+
lp_sum += torch.where(finished, torch.zeros_like(lp_sum), logp.gather(1, nxt[:, None]).squeeze(1))
|
| 149 |
+
lengths += (~finished).long()
|
| 150 |
+
out.append(nxt)
|
| 151 |
+
finished |= nxt == eos_id
|
| 152 |
+
if bool(finished.all()):
|
| 153 |
+
break
|
| 154 |
+
mask = torch.cat([mask, torch.ones(B, 1, dtype=mask.dtype, device=device)], 1)
|
| 155 |
+
logits, past = forward_step(model, nxt[:, None], mask, next_pos, past)
|
| 156 |
+
next_pos = next_pos + 1
|
| 157 |
+
gen = torch.stack(out, 1).tolist() if out else [[] for _ in range(B)]
|
| 158 |
+
res = []
|
| 159 |
+
for row in gen:
|
| 160 |
+
if eos_id in row:
|
| 161 |
+
row = row[:row.index(eos_id)]
|
| 162 |
+
res.append(row)
|
| 163 |
+
return res, lp_sum.tolist(), lengths.tolist()
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
# -----------------------------------------------------------------------------
|
| 167 |
+
# beam search (batched over prompts, width W per prompt)
|
| 168 |
+
# -----------------------------------------------------------------------------
|
| 169 |
+
@torch.no_grad()
|
| 170 |
+
def beam_search(model, prompts, width, max_new_tokens, eos_id, pad_id, length_penalty=1.0):
|
| 171 |
+
"""Standard beam search with a KV cache.
|
| 172 |
+
* each step: scores(B,W) + log p(B,W,V) -> top 2W candidates per prompt
|
| 173 |
+
* candidates ending in EOS become finished hypotheses (score / len^alpha)
|
| 174 |
+
* a prompt is done once it has W finished hypotheses (early stopping)
|
| 175 |
+
* at max length, open beams are added to the finished pool.
|
| 176 |
+
Returns (ids, sum log-prob, length) of the best hypothesis per prompt."""
|
| 177 |
+
device = next(model.parameters()).device
|
| 178 |
+
B, W = len(prompts), width
|
| 179 |
+
rep = [p for p in prompts for _ in range(W)]
|
| 180 |
+
ids, mask, pos = left_pad(rep, pad_id, device)
|
| 181 |
+
logits, past = forward_step(model, ids, mask, pos, None)
|
| 182 |
+
V = logits.size(-1)
|
| 183 |
+
next_pos = pos[:, -1:] + 1
|
| 184 |
+
beam_scores = torch.zeros(B, W, device=device)
|
| 185 |
+
beam_scores[:, 1:] = float("-inf") # all beams identical at t=0 -> only expand beam 0
|
| 186 |
+
seqs = torch.zeros(B * W, 0, dtype=torch.long, device=device)
|
| 187 |
+
finished = [[] for _ in range(B)] # (normalised score, raw score, token list)
|
| 188 |
+
done = [False] * B
|
| 189 |
+
for t in range(max_new_tokens):
|
| 190 |
+
logp = F.log_softmax(logits, -1).view(B, W, V)
|
| 191 |
+
cand = (beam_scores.unsqueeze(-1) + logp).view(B, W * V)
|
| 192 |
+
top_s, top_i = cand.topk(2 * W, dim=-1)
|
| 193 |
+
top_s_l, top_i_l = top_s.tolist(), top_i.tolist()
|
| 194 |
+
new_scores = torch.zeros(B, W, device=device)
|
| 195 |
+
new_beam = torch.zeros(B, W, dtype=torch.long)
|
| 196 |
+
new_tok = torch.full((B, W), pad_id, dtype=torch.long)
|
| 197 |
+
seqs_l = None
|
| 198 |
+
for b in range(B):
|
| 199 |
+
if done[b]:
|
| 200 |
+
new_scores[b] = float("-inf"); new_scores[b, 0] = 0.0
|
| 201 |
+
continue
|
| 202 |
+
j = 0
|
| 203 |
+
for r in range(2 * W):
|
| 204 |
+
s, ci = top_s_l[b][r], top_i_l[b][r]
|
| 205 |
+
bi, ti = ci // V, ci % V
|
| 206 |
+
if s == float("-inf"):
|
| 207 |
+
break
|
| 208 |
+
if ti == eos_id:
|
| 209 |
+
if r < W:
|
| 210 |
+
if seqs_l is None:
|
| 211 |
+
seqs_l = seqs.tolist()
|
| 212 |
+
toks = seqs_l[b * W + bi]
|
| 213 |
+
n = len(toks) + 1
|
| 214 |
+
finished[b].append((s / (n ** length_penalty), s, toks, n))
|
| 215 |
+
continue
|
| 216 |
+
new_scores[b, j] = s; new_beam[b, j] = bi; new_tok[b, j] = ti
|
| 217 |
+
j += 1
|
| 218 |
+
if j == W:
|
| 219 |
+
break
|
| 220 |
+
while j < W: # not enough live candidates
|
| 221 |
+
new_scores[b, j] = float("-inf"); j += 1
|
| 222 |
+
if len(finished[b]) >= W:
|
| 223 |
+
done[b] = True
|
| 224 |
+
if all(done):
|
| 225 |
+
break
|
| 226 |
+
gidx = (torch.arange(B).unsqueeze(1) * W + new_beam).view(-1).to(device)
|
| 227 |
+
seqs = torch.cat([seqs.index_select(0, gidx), new_tok.view(-1, 1).to(device)], 1)
|
| 228 |
+
beam_scores = new_scores
|
| 229 |
+
past = reorder_cache(past, gidx)
|
| 230 |
+
mask = torch.cat([mask.index_select(0, gidx), torch.ones(B * W, 1, dtype=mask.dtype, device=device)], 1)
|
| 231 |
+
next_pos = next_pos.index_select(0, gidx)
|
| 232 |
+
logits, past = forward_step(model, new_tok.view(-1, 1).to(device), mask, next_pos, past)
|
| 233 |
+
next_pos = next_pos + 1
|
| 234 |
+
seqs_l = seqs.tolist(); sc = beam_scores.tolist()
|
| 235 |
+
res, lps, lens = [], [], []
|
| 236 |
+
for b in range(B):
|
| 237 |
+
if not done[b]:
|
| 238 |
+
for w in range(W):
|
| 239 |
+
if sc[b][w] > float("-inf"):
|
| 240 |
+
toks = seqs_l[b * W + w]
|
| 241 |
+
n = max(len(toks), 1)
|
| 242 |
+
finished[b].append((sc[b][w] / (n ** length_penalty), sc[b][w], toks, n))
|
| 243 |
+
best = max(finished[b], key=lambda z: z[0])
|
| 244 |
+
res.append(best[2]); lps.append(best[1]); lens.append(best[3])
|
| 245 |
+
return res, lps, lens
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
# -----------------------------------------------------------------------------
|
| 249 |
+
# metrics
|
| 250 |
+
# -----------------------------------------------------------------------------
|
| 251 |
+
_PUNCT = re.compile(f"[{re.escape(string.punctuation)}]")
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def norm_words(s):
|
| 255 |
+
return _PUNCT.sub(" ", s.lower()).split()
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def clean_generation(text, max_sentences=4):
|
| 259 |
+
"""Post-processing applied before scoring: cut at the first newline (Pythia tends to
|
| 260 |
+
drift into unrelated text after a line break) and keep at most 4 sentences
|
| 261 |
+
(ROCStories continuations are exactly 4 sentences)."""
|
| 262 |
+
text = text.lstrip()
|
| 263 |
+
text = text.split("\n")[0]
|
| 264 |
+
ends = [m.end() for m in re.finditer(r"[.!?](?=\s|$)", text)]
|
| 265 |
+
if len(ends) >= max_sentences:
|
| 266 |
+
text = text[:ends[max_sentences - 1]]
|
| 267 |
+
return " " + text.strip()
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def token_prf_acc(gen, ref):
|
| 271 |
+
g, r = norm_words(gen), norm_words(ref)
|
| 272 |
+
common = Counter(g) & Counter(r)
|
| 273 |
+
ov = sum(common.values())
|
| 274 |
+
P = ov / len(g) if g else 0.0
|
| 275 |
+
R = ov / len(r) if r else 0.0
|
| 276 |
+
F1 = 2 * P * R / (P + R) if P + R > 0 else 0.0
|
| 277 |
+
acc = sum(1 for i in range(len(r)) if i < len(g) and g[i] == r[i]) / len(r) if r else 0.0
|
| 278 |
+
return P, R, F1, acc
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def distinct_n(texts, n):
|
| 282 |
+
grams, total = set(), 0
|
| 283 |
+
for t in texts:
|
| 284 |
+
w = norm_words(t)
|
| 285 |
+
ng = [tuple(w[i:i + n]) for i in range(len(w) - n + 1)]
|
| 286 |
+
grams.update(ng); total += len(ng)
|
| 287 |
+
return len(grams) / max(total, 1)
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def repetition_rate(text, n=4):
|
| 291 |
+
w = norm_words(text)
|
| 292 |
+
ng = [tuple(w[i:i + n]) for i in range(len(w) - n + 1)]
|
| 293 |
+
return 1 - len(set(ng)) / len(ng) if ng else 0.0
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
@torch.no_grad()
|
| 297 |
+
def continuation_ppl(model, prompt_ids, cont_ids, pad_id, batch_size=32):
|
| 298 |
+
"""Per-sample perplexity of cont given prompt (teacher forced)."""
|
| 299 |
+
device = next(model.parameters()).device
|
| 300 |
+
out = []
|
| 301 |
+
for s in range(0, len(prompt_ids), batch_size):
|
| 302 |
+
P = prompt_ids[s:s + batch_size]; C = cont_ids[s:s + batch_size]
|
| 303 |
+
seqs = [p + c for p, c in zip(P, C)]
|
| 304 |
+
L = max(len(x) for x in seqs)
|
| 305 |
+
ids = torch.full((len(seqs), L), pad_id, dtype=torch.long)
|
| 306 |
+
att = torch.zeros((len(seqs), L), dtype=torch.long)
|
| 307 |
+
lab = torch.full((len(seqs), L), -100, dtype=torch.long)
|
| 308 |
+
for i, (p, c) in enumerate(zip(P, C)):
|
| 309 |
+
x = p + c
|
| 310 |
+
ids[i, :len(x)] = torch.tensor(x); att[i, :len(x)] = 1
|
| 311 |
+
lab[i, len(p):len(x)] = torch.tensor(c) if c else lab[i, len(p):len(x)]
|
| 312 |
+
ids, att, lab = ids.to(device), att.to(device), lab.to(device)
|
| 313 |
+
logits = model(input_ids=ids, attention_mask=att).logits.float()
|
| 314 |
+
lp = F.cross_entropy(logits[:, :-1].reshape(-1, logits.size(-1)), lab[:, 1:].reshape(-1),
|
| 315 |
+
ignore_index=-100, reduction="none").view(len(seqs), -1)
|
| 316 |
+
n = (lab[:, 1:] != -100).sum(1).clamp(min=1)
|
| 317 |
+
out += torch.exp(lp.sum(1) / n).tolist()
|
| 318 |
+
return out
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
def score_config(gens, refs, self_lp, self_len):
|
| 322 |
+
import sacrebleu
|
| 323 |
+
prf = np.array([token_prf_acc(g, r) for g, r in zip(gens, refs)])
|
| 324 |
+
ppl_self = [math.exp(-lp / max(n, 1)) for lp, n in zip(self_lp, self_len)]
|
| 325 |
+
return {
|
| 326 |
+
"precision": float(prf[:, 0].mean()), "recall": float(prf[:, 1].mean()),
|
| 327 |
+
"f1": float(prf[:, 2].mean()), "accuracy": float(prf[:, 3].mean()),
|
| 328 |
+
"bleu": sacrebleu.corpus_bleu(gens, [refs]).score,
|
| 329 |
+
"self_ppl_mean": float(np.mean(ppl_self)), "self_ppl_median": float(np.median(ppl_self)),
|
| 330 |
+
"distinct_1": distinct_n(gens, 1), "distinct_2": distinct_n(gens, 2),
|
| 331 |
+
"rep_4gram": float(np.mean([repetition_rate(g) for g in gens])),
|
| 332 |
+
"avg_words": float(np.mean([len(norm_words(g)) for g in gens])),
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
# -----------------------------------------------------------------------------
|
| 337 |
+
# driver
|
| 338 |
+
# -----------------------------------------------------------------------------
|
| 339 |
+
def run_config(model, tok, prompts, conf, cfg, seed=0):
|
| 340 |
+
device = next(model.parameters()).device
|
| 341 |
+
eos, pad = tok.eos_token_id, tok.pad_token_id
|
| 342 |
+
gen_ids, lps, lens = [None] * len(prompts), [None] * len(prompts), [None] * len(prompts)
|
| 343 |
+
order = sorted(range(len(prompts)), key=lambda i: len(prompts[i]))
|
| 344 |
+
g = torch.Generator(device=device); g.manual_seed(seed)
|
| 345 |
+
bs = cfg["beam_batch_size"] if conf["strategy"] == "beam" else cfg["batch_size"]
|
| 346 |
+
if device.type == "cuda": torch.cuda.synchronize()
|
| 347 |
+
t0 = time.time()
|
| 348 |
+
for s in range(0, len(order), bs):
|
| 349 |
+
idx = order[s:s + bs]
|
| 350 |
+
P = [prompts[i] for i in idx]
|
| 351 |
+
if conf["strategy"] == "beam":
|
| 352 |
+
r, lp, ln = beam_search(model, P, conf["width"], cfg["max_new_tokens"], eos, pad, cfg["length_penalty"])
|
| 353 |
+
else:
|
| 354 |
+
r, lp, ln = sample_decode(model, P, cfg["max_new_tokens"], eos, pad, conf["strategy"],
|
| 355 |
+
conf.get("k"), conf.get("p"), conf.get("temperature", 1.0), g)
|
| 356 |
+
for i, a, b, c in zip(idx, r, lp, ln):
|
| 357 |
+
gen_ids[i], lps[i], lens[i] = a, b, c
|
| 358 |
+
if device.type == "cuda": torch.cuda.synchronize()
|
| 359 |
+
return gen_ids, lps, lens, time.time() - t0
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
def beam_timing(model, tok, prompts, widths, max_new_tokens):
|
| 363 |
+
"""Wall time of beam search with batch size 1 (one prompt at a time) for each width.
|
| 364 |
+
Two modes: 'natural' (stops early once W hypotheses hit EOS) and 'fixed' (EOS disabled,
|
| 365 |
+
always max_new_tokens steps) - the fixed mode isolates the per-step cost as a function of W."""
|
| 366 |
+
device = next(model.parameters()).device
|
| 367 |
+
res = []
|
| 368 |
+
beam_search(model, prompts[:2], 2, 5, tok.eos_token_id, tok.pad_token_id) # warm-up
|
| 369 |
+
for mode, eos in (("natural", tok.eos_token_id), ("fixed", -1)):
|
| 370 |
+
for w in widths:
|
| 371 |
+
times, steps = [], []
|
| 372 |
+
for p in prompts:
|
| 373 |
+
if device.type == "cuda": torch.cuda.synchronize()
|
| 374 |
+
t0 = time.time()
|
| 375 |
+
r, _, ln = beam_search(model, [p], w, max_new_tokens, eos, tok.pad_token_id)
|
| 376 |
+
if device.type == "cuda": torch.cuda.synchronize()
|
| 377 |
+
times.append(time.time() - t0); steps.append(max(len(r[0]), 1))
|
| 378 |
+
rec = {"mode": mode, "width": w, "mean_s_per_prompt": float(np.mean(times)), "std_s": float(np.std(times)),
|
| 379 |
+
"mean_ms_per_token": float(np.mean([t / s for t, s in zip(times, steps)]) * 1e3),
|
| 380 |
+
"mean_output_tokens": float(np.mean(steps)), "total_s": float(np.sum(times)),
|
| 381 |
+
"n_prompts": len(prompts)}
|
| 382 |
+
res.append(rec)
|
| 383 |
+
print(f" [{mode}] width {w}: {rec['mean_s_per_prompt']*1e3:.1f} ms/prompt, "
|
| 384 |
+
f"{rec['mean_ms_per_token']:.2f} ms/token, {rec['mean_output_tokens']:.1f} tokens")
|
| 385 |
+
return res
|
| 386 |
+
|
| 387 |
+
|
| 388 |
+
def run_decoding_eval(user_cfg=None):
|
| 389 |
+
import sys
|
| 390 |
+
sys.path.insert(0, ".")
|
| 391 |
+
from common import get_hf_token, hf_login, hf_resolve_user, hf_push_folder, save_json
|
| 392 |
+
cfg = dict(DECODING_DEFAULTS); cfg.update(user_cfg or {})
|
| 393 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 394 |
+
os.makedirs(cfg["out_dir"], exist_ok=True)
|
| 395 |
+
torch.manual_seed(cfg["seed"])
|
| 396 |
+
|
| 397 |
+
token = get_hf_token(); hf_login(token)
|
| 398 |
+
model, tok = load_lm(cfg["model_name"], device, cfg["dtype"])
|
| 399 |
+
print(f"loaded {cfg['model_name']} on {device}; eos={tok.eos_token_id} pad={tok.pad_token_id}")
|
| 400 |
+
|
| 401 |
+
if cfg.get("dataset_override") is not None:
|
| 402 |
+
rows = cfg["dataset_override"]
|
| 403 |
+
else:
|
| 404 |
+
from datasets import load_dataset
|
| 405 |
+
rows = load_dataset(cfg["dataset"], split=cfg["split"])
|
| 406 |
+
prompts_txt = list(rows["prompt"]); refs_txt = list(rows["continuation"])
|
| 407 |
+
keep = [i for i, r in enumerate(refs_txt) if r and r.strip()]
|
| 408 |
+
rng = np.random.default_rng(cfg["seed"])
|
| 409 |
+
keep = sorted(rng.choice(keep, min(cfg["n_samples"], len(keep)), replace=False).tolist())
|
| 410 |
+
prompts_txt = [prompts_txt[i] for i in keep]; refs_txt = [refs_txt[i] for i in keep]
|
| 411 |
+
refs_txt = [" " + r.strip() for r in refs_txt]
|
| 412 |
+
prompts = [tok(p)["input_ids"] for p in prompts_txt]
|
| 413 |
+
print(f"{len(prompts)} test prompts")
|
| 414 |
+
|
| 415 |
+
# reference perplexity (independent of the decoding strategy)
|
| 416 |
+
ref_ids = [tok(r)["input_ids"] for r in refs_txt]
|
| 417 |
+
ref_ppl = continuation_ppl(model, prompts, ref_ids, tok.pad_token_id)
|
| 418 |
+
summary = {"reference_ppl_mean": float(np.mean(ref_ppl)), "reference_ppl_median": float(np.median(ref_ppl)),
|
| 419 |
+
"n_samples": len(prompts), "model": cfg["model_name"], "max_new_tokens": cfg["max_new_tokens"]}
|
| 420 |
+
print(f"reference continuation ppl: mean {summary['reference_ppl_mean']:.2f}, "
|
| 421 |
+
f"median {summary['reference_ppl_median']:.2f}")
|
| 422 |
+
|
| 423 |
+
results, generations = [], {"prompt": prompts_txt, "reference": refs_txt}
|
| 424 |
+
for conf in cfg["configs"]:
|
| 425 |
+
print(f"== {conf['name']} ==")
|
| 426 |
+
ids, lps, lens, dt = run_config(model, tok, prompts, conf, cfg, cfg["seed"])
|
| 427 |
+
raw = [tok.decode(x, skip_special_tokens=True) for x in ids]
|
| 428 |
+
gens = [clean_generation(t) for t in raw]
|
| 429 |
+
m = score_config(gens, refs_txt, lps, lens)
|
| 430 |
+
m.update({"name": conf["name"], "strategy": conf["strategy"], "params": conf,
|
| 431 |
+
"time_s": dt, "ms_per_prompt": dt / len(prompts) * 1e3,
|
| 432 |
+
"gen_tokens_mean": float(np.mean([len(x) for x in ids]))})
|
| 433 |
+
results.append(m)
|
| 434 |
+
generations[conf["name"]] = gens
|
| 435 |
+
generations[conf["name"] + "__raw"] = raw
|
| 436 |
+
print(f" P {m['precision']:.3f} R {m['recall']:.3f} F1 {m['f1']:.3f} Acc {m['accuracy']:.3f} "
|
| 437 |
+
f"BLEU {m['bleu']:.2f} self-ppl {m['self_ppl_median']:.2f} dist-2 {m['distinct_2']:.3f} "
|
| 438 |
+
f"rep4 {m['rep_4gram']:.3f} time {dt:.1f}s")
|
| 439 |
+
|
| 440 |
+
# sanity: beam width 1 must equal greedy
|
| 441 |
+
if "greedy" in generations and "beam_w1" in generations:
|
| 442 |
+
same = np.mean([a == b for a, b in zip(generations["greedy__raw"], generations["beam_w1__raw"])])
|
| 443 |
+
summary["beam_w1_equals_greedy_frac"] = float(same)
|
| 444 |
+
print(f"beam(w=1) identical to greedy on {same*100:.1f}% of prompts")
|
| 445 |
+
|
| 446 |
+
# external judge perplexity
|
| 447 |
+
if cfg["judge_model"]:
|
| 448 |
+
try:
|
| 449 |
+
judge, _ = load_lm(cfg["judge_model"], device, cfg["dtype"])
|
| 450 |
+
for m in results:
|
| 451 |
+
gen_ids = [tok(g)["input_ids"] for g in generations[m["name"]]]
|
| 452 |
+
pp = continuation_ppl(judge, prompts, gen_ids, tok.pad_token_id)
|
| 453 |
+
m["judge_ppl_median"] = float(np.median(pp)); m["judge_ppl_mean"] = float(np.mean(pp))
|
| 454 |
+
jr = continuation_ppl(judge, prompts, ref_ids, tok.pad_token_id)
|
| 455 |
+
summary["reference_judge_ppl_median"] = float(np.median(jr))
|
| 456 |
+
del judge
|
| 457 |
+
except Exception as e:
|
| 458 |
+
print("[judge] skipped:", e)
|
| 459 |
+
|
| 460 |
+
if cfg["use_bertscore"]:
|
| 461 |
+
try:
|
| 462 |
+
from bert_score import score as bscore
|
| 463 |
+
for m in results:
|
| 464 |
+
P, R, F1 = bscore(generations[m["name"]], refs_txt, lang="en", verbose=False,
|
| 465 |
+
device=str(device), batch_size=64)
|
| 466 |
+
m["bertscore_p"], m["bertscore_r"], m["bertscore_f1"] = (float(P.mean()), float(R.mean()),
|
| 467 |
+
float(F1.mean()))
|
| 468 |
+
except Exception as e:
|
| 469 |
+
print("[bertscore] skipped:", e)
|
| 470 |
+
|
| 471 |
+
print("beam-search timing (batch size 1):")
|
| 472 |
+
timing = beam_timing(model, tok, prompts[:cfg["timing_samples"]], cfg["timing_widths"], cfg["max_new_tokens"])
|
| 473 |
+
|
| 474 |
+
save_json({"summary": summary, "results": results, "beam_timing": timing, "config":
|
| 475 |
+
{k: v for k, v in cfg.items() if k != "dataset_override"}},
|
| 476 |
+
os.path.join(cfg["out_dir"], "decoding_results.json"))
|
| 477 |
+
save_json(generations, os.path.join(cfg["out_dir"], "generations.json"))
|
| 478 |
+
shutil_copy_code(cfg["out_dir"])
|
| 479 |
+
user = hf_resolve_user(cfg["hf_user"], token)
|
| 480 |
+
if cfg["push_to_hub"] and user:
|
| 481 |
+
hf_push_folder(cfg["out_dir"], f"{user}/{cfg['repo_name']}", token, cfg["private"], "decoding results")
|
| 482 |
+
print(f"pushed to https://huggingface.co/{user}/{cfg['repo_name']}")
|
| 483 |
+
return summary, results, timing, generations
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
def shutil_copy_code(out_dir):
|
| 487 |
+
import shutil
|
| 488 |
+
for f in ("decoding.py", "common.py"):
|
| 489 |
+
if os.path.exists(f):
|
| 490 |
+
shutil.copy(f, os.path.join(out_dir, f))
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
# -----------------------------------------------------------------------------
|
| 494 |
+
# plots / tables for the write-up
|
| 495 |
+
# -----------------------------------------------------------------------------
|
| 496 |
+
PALETTE = ["#2a78d6", "#eb6834", "#1baf7a", "#eda100", "#e87ba4", "#008300", "#4a3aa7", "#e34948"]
|
| 497 |
+
STRATEGY_COLOR = {"greedy": PALETTE[0], "beam": PALETTE[6], "top_k": PALETTE[1], "top_p": PALETTE[2]}
|
| 498 |
+
|
| 499 |
+
|
| 500 |
+
def decoding_report(res_json_path, out_dir):
|
| 501 |
+
import pandas as pd
|
| 502 |
+
import matplotlib.pyplot as plt
|
| 503 |
+
from common import setup_plot_style
|
| 504 |
+
setup_plot_style()
|
| 505 |
+
R = json.load(open(res_json_path))
|
| 506 |
+
df = pd.DataFrame(R["results"])
|
| 507 |
+
cols = ["name", "accuracy", "precision", "recall", "f1", "bleu", "self_ppl_median", "judge_ppl_median",
|
| 508 |
+
"bertscore_f1", "distinct_2", "rep_4gram", "avg_words", "ms_per_prompt"]
|
| 509 |
+
table = df[[c for c in cols if c in df.columns]].copy()
|
| 510 |
+
table.to_csv(os.path.join(out_dir, "decoding_table.csv"), index=False)
|
| 511 |
+
colors = [STRATEGY_COLOR[s] for s in df["strategy"]]
|
| 512 |
+
|
| 513 |
+
metrics = [("f1", "token F1"), ("accuracy", "positional accuracy"), ("bleu", "BLEU"),
|
| 514 |
+
("self_ppl_median", "self perplexity (median)"), ("distinct_2", "distinct-2"),
|
| 515 |
+
("rep_4gram", "repeated 4-gram rate")]
|
| 516 |
+
fig, axes = plt.subplots(2, 3, figsize=(15, 7.5), constrained_layout=True)
|
| 517 |
+
for ax, (k, lab) in zip(axes.flat, metrics):
|
| 518 |
+
ax.bar(range(len(df)), df[k], color=colors, width=0.7)
|
| 519 |
+
ax.set_xticks(range(len(df))); ax.set_xticklabels(df["name"], rotation=60, ha="right", fontsize=8)
|
| 520 |
+
ax.set_title(lab); ax.grid(axis="x", visible=False)
|
| 521 |
+
handles = [plt.Rectangle((0, 0), 1, 1, color=c) for c in STRATEGY_COLOR.values()]
|
| 522 |
+
fig.legend(handles, STRATEGY_COLOR.keys(), loc="upper right", ncol=4)
|
| 523 |
+
fig.savefig(os.path.join(out_dir, "decoding_metrics.png"))
|
| 524 |
+
|
| 525 |
+
# quality vs diversity
|
| 526 |
+
fig2, ax = plt.subplots(figsize=(6.5, 4.5), constrained_layout=True)
|
| 527 |
+
for _, r in df.iterrows():
|
| 528 |
+
ax.scatter(r["distinct_2"], r["f1"], color=STRATEGY_COLOR[r["strategy"]], s=60, zorder=3,
|
| 529 |
+
edgecolor="white", linewidth=1.5)
|
| 530 |
+
ax.annotate(r["name"], (r["distinct_2"], r["f1"]), fontsize=7, xytext=(4, 3), textcoords="offset points")
|
| 531 |
+
ax.set_xlabel("distinct-2 (diversity)"); ax.set_ylabel("token F1 vs reference")
|
| 532 |
+
ax.set_title("quality / diversity trade-off")
|
| 533 |
+
fig2.savefig(os.path.join(out_dir, "quality_vs_diversity.png"))
|
| 534 |
+
|
| 535 |
+
# beam timing
|
| 536 |
+
tm = pd.DataFrame(R["beam_timing"])
|
| 537 |
+
fig3, axes3 = plt.subplots(1, 2, figsize=(11, 3.8), constrained_layout=True)
|
| 538 |
+
for i, (mode, g) in enumerate(tm.groupby("mode", sort=False)):
|
| 539 |
+
axes3[0].plot(g["width"], g["mean_s_per_prompt"] * 1e3, marker="o", label=mode, color=PALETTE[i])
|
| 540 |
+
axes3[1].plot(g["width"], g["mean_ms_per_token"], marker="o", label=mode, color=PALETTE[i])
|
| 541 |
+
for ax, lab in zip(axes3, ["ms per prompt", "ms per generated token"]):
|
| 542 |
+
ax.set_xlabel("beam width"); ax.set_ylabel(lab); ax.set_xticks(sorted(tm["width"].unique())); ax.legend()
|
| 543 |
+
axes3[0].set_title("beam search wall time (batch size 1)")
|
| 544 |
+
axes3[1].set_title("per-step cost")
|
| 545 |
+
fig3.savefig(os.path.join(out_dir, "beam_timing.png"))
|
| 546 |
+
return table, tm
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def show_examples(gen_json_path, n=5, names=None, seed=0):
|
| 550 |
+
G = json.load(open(gen_json_path))
|
| 551 |
+
names = names or [k for k in G if k not in ("prompt", "reference") and not k.endswith("__raw")]
|
| 552 |
+
rng = np.random.default_rng(seed)
|
| 553 |
+
for i in rng.choice(len(G["prompt"]), n, replace=False):
|
| 554 |
+
print("=" * 100)
|
| 555 |
+
print("PROMPT :", G["prompt"][i])
|
| 556 |
+
print("REFERENCE:", G["reference"][i].strip())
|
| 557 |
+
for k in names:
|
| 558 |
+
print(f"{k:>16s}: {G[k][i].strip()}")
|
decoding_results.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
| 1 |
{
|
| 2 |
"summary": {
|
| 3 |
-
"reference_ppl_mean": 27.
|
| 4 |
-
"reference_ppl_median": 24.
|
| 5 |
"n_samples": 1000,
|
| 6 |
"model": "EleutherAI/pythia-160m",
|
| 7 |
"max_new_tokens": 70,
|
| 8 |
-
"beam_w1_equals_greedy_frac": 0.
|
| 9 |
-
"reference_judge_ppl_median": 16.
|
| 10 |
},
|
| 11 |
"results": [
|
| 12 |
{
|
| 13 |
-
"precision": 0.
|
| 14 |
"recall": 0.10761634910100995,
|
| 15 |
-
"f1": 0.
|
| 16 |
-
"accuracy": 0.
|
| 17 |
-
"bleu": 0.
|
| 18 |
-
"self_ppl_mean": 2.
|
| 19 |
-
"self_ppl_median": 1.
|
| 20 |
-
"distinct_1": 0.
|
| 21 |
-
"distinct_2": 0.
|
| 22 |
"rep_4gram": 0.3296551592928797,
|
| 23 |
-
"avg_words": 27.
|
| 24 |
"name": "greedy",
|
| 25 |
"strategy": "greedy",
|
| 26 |
"params": {
|
| 27 |
"name": "greedy",
|
| 28 |
"strategy": "greedy"
|
| 29 |
},
|
| 30 |
-
"time_s":
|
| 31 |
-
"ms_per_prompt":
|
| 32 |
"gen_tokens_mean": 69.995,
|
| 33 |
-
"judge_ppl_median": 3.
|
| 34 |
-
"judge_ppl_mean": 3.
|
| 35 |
-
"bertscore_p": 0.
|
| 36 |
-
"bertscore_r": 0.
|
| 37 |
-
"bertscore_f1": 0.
|
| 38 |
},
|
| 39 |
{
|
| 40 |
"precision": 0.1568385962211188,
|
|
@@ -42,8 +42,8 @@
|
|
| 42 |
"f1": 0.11688205526981743,
|
| 43 |
"accuracy": 0.013886833130142854,
|
| 44 |
"bleu": 0.4603869452185167,
|
| 45 |
-
"self_ppl_mean": 2.
|
| 46 |
-
"self_ppl_median": 1.
|
| 47 |
"distinct_1": 0.03780348102435239,
|
| 48 |
"distinct_2": 0.11810751697939449,
|
| 49 |
"rep_4gram": 0.3296463873630552,
|
|
@@ -55,11 +55,11 @@
|
|
| 55 |
"strategy": "beam",
|
| 56 |
"width": 1
|
| 57 |
},
|
| 58 |
-
"time_s":
|
| 59 |
-
"ms_per_prompt":
|
| 60 |
"gen_tokens_mean": 69.995,
|
| 61 |
-
"judge_ppl_median": 3.
|
| 62 |
-
"judge_ppl_mean": 3.
|
| 63 |
"bertscore_p": 0.8486897945404053,
|
| 64 |
"bertscore_r": 0.8463218808174133,
|
| 65 |
"bertscore_f1": 0.8473787903785706
|
|
@@ -70,8 +70,8 @@
|
|
| 70 |
"f1": 0.11012341441029258,
|
| 71 |
"accuracy": 0.010045733414015445,
|
| 72 |
"bleu": 0.29556628142570907,
|
| 73 |
-
"self_ppl_mean": 1.
|
| 74 |
-
"self_ppl_median": 1.
|
| 75 |
"distinct_1": 0.045782342657342656,
|
| 76 |
"distinct_2": 0.13661581137309292,
|
| 77 |
"rep_4gram": 0.20882754144393487,
|
|
@@ -83,27 +83,27 @@
|
|
| 83 |
"strategy": "beam",
|
| 84 |
"width": 2
|
| 85 |
},
|
| 86 |
-
"time_s":
|
| 87 |
-
"ms_per_prompt":
|
| 88 |
"gen_tokens_mean": 69.827,
|
| 89 |
-
"judge_ppl_median": 4.
|
| 90 |
-
"judge_ppl_mean": 5.
|
| 91 |
"bertscore_p": 0.8609820604324341,
|
| 92 |
-
"bertscore_r": 0.
|
| 93 |
"bertscore_f1": 0.8535703420639038
|
| 94 |
},
|
| 95 |
{
|
| 96 |
-
"precision": 0.
|
| 97 |
"recall": 0.07404912467040367,
|
| 98 |
-
"f1": 0.
|
| 99 |
"accuracy": 0.008065531697039307,
|
| 100 |
-
"bleu": 0.
|
| 101 |
-
"self_ppl_mean": 1.
|
| 102 |
-
"self_ppl_median": 1.
|
| 103 |
-
"distinct_1": 0.
|
| 104 |
-
"distinct_2": 0.
|
| 105 |
-
"rep_4gram": 0.
|
| 106 |
-
"avg_words": 18.
|
| 107 |
"name": "beam_w4",
|
| 108 |
"strategy": "beam",
|
| 109 |
"params": {
|
|
@@ -111,27 +111,27 @@
|
|
| 111 |
"strategy": "beam",
|
| 112 |
"width": 4
|
| 113 |
},
|
| 114 |
-
"time_s":
|
| 115 |
-
"ms_per_prompt":
|
| 116 |
"gen_tokens_mean": 69.253,
|
| 117 |
-
"judge_ppl_median": 3.
|
| 118 |
-
"judge_ppl_mean": 549.
|
| 119 |
-
"bertscore_p": 0.
|
| 120 |
-
"bertscore_r": 0.
|
| 121 |
-
"bertscore_f1": 0.
|
| 122 |
},
|
| 123 |
{
|
| 124 |
-
"precision": 0.
|
| 125 |
-
"recall": 0.
|
| 126 |
-
"f1": 0.
|
| 127 |
-
"accuracy": 0.
|
| 128 |
-
"bleu": 0.
|
| 129 |
-
"self_ppl_mean": 5.
|
| 130 |
-
"self_ppl_median": 5.
|
| 131 |
-
"distinct_1": 0.
|
| 132 |
-
"distinct_2": 0.
|
| 133 |
-
"rep_4gram": 0.
|
| 134 |
-
"avg_words": 31.
|
| 135 |
"name": "topk_k5",
|
| 136 |
"strategy": "top_k",
|
| 137 |
"params": {
|
|
@@ -139,27 +139,27 @@
|
|
| 139 |
"strategy": "top_k",
|
| 140 |
"k": 5
|
| 141 |
},
|
| 142 |
-
"time_s":
|
| 143 |
-
"ms_per_prompt":
|
| 144 |
-
"gen_tokens_mean": 69.
|
| 145 |
-
"judge_ppl_median": 8.
|
| 146 |
-
"judge_ppl_mean":
|
| 147 |
-
"bertscore_p": 0.
|
| 148 |
-
"bertscore_r": 0.
|
| 149 |
-
"bertscore_f1": 0.
|
| 150 |
},
|
| 151 |
{
|
| 152 |
-
"precision": 0.
|
| 153 |
-
"recall": 0.
|
| 154 |
-
"f1": 0.
|
| 155 |
-
"accuracy": 0.
|
| 156 |
-
"bleu": 0.
|
| 157 |
-
"self_ppl_mean": 10.
|
| 158 |
-
"self_ppl_median":
|
| 159 |
-
"distinct_1": 0.
|
| 160 |
-
"distinct_2": 0.
|
| 161 |
-
"rep_4gram": 0.
|
| 162 |
-
"avg_words":
|
| 163 |
"name": "topk_k20",
|
| 164 |
"strategy": "top_k",
|
| 165 |
"params": {
|
|
@@ -167,24 +167,24 @@
|
|
| 167 |
"strategy": "top_k",
|
| 168 |
"k": 20
|
| 169 |
},
|
| 170 |
-
"time_s":
|
| 171 |
-
"ms_per_prompt":
|
| 172 |
-
"gen_tokens_mean": 69.
|
| 173 |
-
"judge_ppl_median": 14.
|
| 174 |
-
"judge_ppl_mean":
|
| 175 |
},
|
| 176 |
{
|
| 177 |
-
"precision": 0.
|
| 178 |
-
"recall": 0.
|
| 179 |
-
"f1": 0.
|
| 180 |
-
"accuracy": 0.
|
| 181 |
-
"bleu": 0.
|
| 182 |
-
"self_ppl_mean":
|
| 183 |
-
"self_ppl_median": 13.
|
| 184 |
-
"distinct_1": 0.
|
| 185 |
-
"distinct_2": 0.
|
| 186 |
-
"rep_4gram": 0.
|
| 187 |
-
"avg_words": 35.
|
| 188 |
"name": "topk_k50",
|
| 189 |
"strategy": "top_k",
|
| 190 |
"params": {
|
|
@@ -192,24 +192,24 @@
|
|
| 192 |
"strategy": "top_k",
|
| 193 |
"k": 50
|
| 194 |
},
|
| 195 |
-
"time_s":
|
| 196 |
-
"ms_per_prompt":
|
| 197 |
-
"gen_tokens_mean": 68.
|
| 198 |
-
"judge_ppl_median":
|
| 199 |
-
"judge_ppl_mean":
|
| 200 |
},
|
| 201 |
{
|
| 202 |
-
"precision": 0.
|
| 203 |
-
"recall": 0.
|
| 204 |
-
"f1": 0.
|
| 205 |
-
"accuracy": 0.
|
| 206 |
-
"bleu": 0.
|
| 207 |
-
"self_ppl_mean": 7.
|
| 208 |
-
"self_ppl_median": 6.
|
| 209 |
-
"distinct_1": 0.
|
| 210 |
-
"distinct_2": 0.
|
| 211 |
-
"rep_4gram": 0.
|
| 212 |
-
"avg_words":
|
| 213 |
"name": "topk_k50_t0.7",
|
| 214 |
"strategy": "top_k",
|
| 215 |
"params": {
|
|
@@ -218,24 +218,24 @@
|
|
| 218 |
"k": 50,
|
| 219 |
"temperature": 0.7
|
| 220 |
},
|
| 221 |
-
"time_s":
|
| 222 |
-
"ms_per_prompt":
|
| 223 |
-
"gen_tokens_mean": 69.
|
| 224 |
-
"judge_ppl_median": 10.
|
| 225 |
-
"judge_ppl_mean":
|
| 226 |
},
|
| 227 |
{
|
| 228 |
-
"precision": 0.
|
| 229 |
-
"recall": 0.
|
| 230 |
-
"f1": 0.
|
| 231 |
-
"accuracy": 0.
|
| 232 |
-
"bleu": 0.
|
| 233 |
-
"self_ppl_mean": 6.
|
| 234 |
-
"self_ppl_median": 5.
|
| 235 |
-
"distinct_1": 0.
|
| 236 |
-
"distinct_2": 0.
|
| 237 |
-
"rep_4gram": 0.
|
| 238 |
-
"avg_words":
|
| 239 |
"name": "topp_p0.5",
|
| 240 |
"strategy": "top_p",
|
| 241 |
"params": {
|
|
@@ -243,24 +243,24 @@
|
|
| 243 |
"strategy": "top_p",
|
| 244 |
"p": 0.5
|
| 245 |
},
|
| 246 |
-
"time_s":
|
| 247 |
-
"ms_per_prompt":
|
| 248 |
-
"gen_tokens_mean": 69.
|
| 249 |
-
"judge_ppl_median": 9.
|
| 250 |
-
"judge_ppl_mean":
|
| 251 |
},
|
| 252 |
{
|
| 253 |
-
"precision": 0.
|
| 254 |
-
"recall": 0.
|
| 255 |
-
"f1": 0.
|
| 256 |
-
"accuracy": 0.
|
| 257 |
-
"bleu": 0.
|
| 258 |
-
"self_ppl_mean":
|
| 259 |
-
"self_ppl_median": 14.
|
| 260 |
-
"distinct_1": 0.
|
| 261 |
-
"distinct_2": 0.
|
| 262 |
-
"rep_4gram": 0.
|
| 263 |
-
"avg_words":
|
| 264 |
"name": "topp_p0.8",
|
| 265 |
"strategy": "top_p",
|
| 266 |
"params": {
|
|
@@ -268,24 +268,24 @@
|
|
| 268 |
"strategy": "top_p",
|
| 269 |
"p": 0.8
|
| 270 |
},
|
| 271 |
-
"time_s":
|
| 272 |
-
"ms_per_prompt":
|
| 273 |
-
"gen_tokens_mean": 69.
|
| 274 |
-
"judge_ppl_median": 23.
|
| 275 |
-
"judge_ppl_mean":
|
| 276 |
},
|
| 277 |
{
|
| 278 |
-
"precision": 0.
|
| 279 |
-
"recall": 0.
|
| 280 |
-
"f1": 0.
|
| 281 |
-
"accuracy": 0.
|
| 282 |
-
"bleu": 0.
|
| 283 |
-
"self_ppl_mean":
|
| 284 |
-
"self_ppl_median":
|
| 285 |
-
"distinct_1": 0.
|
| 286 |
-
"distinct_2": 0.
|
| 287 |
-
"rep_4gram": 0.
|
| 288 |
-
"avg_words":
|
| 289 |
"name": "topp_p0.95",
|
| 290 |
"strategy": "top_p",
|
| 291 |
"params": {
|
|
@@ -293,24 +293,24 @@
|
|
| 293 |
"strategy": "top_p",
|
| 294 |
"p": 0.95
|
| 295 |
},
|
| 296 |
-
"time_s":
|
| 297 |
-
"ms_per_prompt":
|
| 298 |
-
"gen_tokens_mean": 68.
|
| 299 |
-
"judge_ppl_median":
|
| 300 |
-
"judge_ppl_mean":
|
| 301 |
},
|
| 302 |
{
|
| 303 |
-
"precision": 0.
|
| 304 |
-
"recall": 0.
|
| 305 |
-
"f1": 0.
|
| 306 |
-
"accuracy": 0.
|
| 307 |
-
"bleu": 0.
|
| 308 |
-
"self_ppl_mean": 5.
|
| 309 |
-
"self_ppl_median": 5.
|
| 310 |
-
"distinct_1": 0.
|
| 311 |
-
"distinct_2": 0.
|
| 312 |
-
"rep_4gram": 0.
|
| 313 |
-
"avg_words":
|
| 314 |
"name": "topp_p0.9_t0.7",
|
| 315 |
"strategy": "top_p",
|
| 316 |
"params": {
|
|
@@ -319,92 +319,92 @@
|
|
| 319 |
"p": 0.9,
|
| 320 |
"temperature": 0.7
|
| 321 |
},
|
| 322 |
-
"time_s":
|
| 323 |
-
"ms_per_prompt":
|
| 324 |
-
"gen_tokens_mean": 69.
|
| 325 |
-
"judge_ppl_median": 9.
|
| 326 |
-
"judge_ppl_mean":
|
| 327 |
}
|
| 328 |
],
|
| 329 |
"beam_timing": [
|
| 330 |
{
|
| 331 |
"mode": "natural",
|
| 332 |
"width": 1,
|
| 333 |
-
"mean_s_per_prompt": 0.
|
| 334 |
-
"std_s": 0.
|
| 335 |
-
"mean_ms_per_token":
|
| 336 |
"mean_output_tokens": 70.0,
|
| 337 |
-
"total_s":
|
| 338 |
"n_prompts": 100
|
| 339 |
},
|
| 340 |
{
|
| 341 |
"mode": "natural",
|
| 342 |
"width": 2,
|
| 343 |
-
"mean_s_per_prompt": 0.
|
| 344 |
-
"std_s": 0.
|
| 345 |
-
"mean_ms_per_token":
|
| 346 |
"mean_output_tokens": 69.86,
|
| 347 |
-
"total_s":
|
| 348 |
"n_prompts": 100
|
| 349 |
},
|
| 350 |
{
|
| 351 |
"mode": "natural",
|
| 352 |
"width": 4,
|
| 353 |
-
"mean_s_per_prompt": 0.
|
| 354 |
-
"std_s": 0.
|
| 355 |
-
"mean_ms_per_token":
|
| 356 |
"mean_output_tokens": 69.59,
|
| 357 |
-
"total_s":
|
| 358 |
"n_prompts": 100
|
| 359 |
},
|
| 360 |
{
|
| 361 |
"mode": "natural",
|
| 362 |
"width": 8,
|
| 363 |
-
"mean_s_per_prompt": 0.
|
| 364 |
-
"std_s": 0.
|
| 365 |
-
"mean_ms_per_token":
|
| 366 |
"mean_output_tokens": 69.34,
|
| 367 |
-
"total_s":
|
| 368 |
"n_prompts": 100
|
| 369 |
},
|
| 370 |
{
|
| 371 |
"mode": "fixed",
|
| 372 |
"width": 1,
|
| 373 |
-
"mean_s_per_prompt": 0.
|
| 374 |
-
"std_s": 0.
|
| 375 |
-
"mean_ms_per_token":
|
| 376 |
"mean_output_tokens": 70.0,
|
| 377 |
-
"total_s":
|
| 378 |
"n_prompts": 100
|
| 379 |
},
|
| 380 |
{
|
| 381 |
"mode": "fixed",
|
| 382 |
"width": 2,
|
| 383 |
-
"mean_s_per_prompt": 0.
|
| 384 |
-
"std_s": 0.
|
| 385 |
-
"mean_ms_per_token":
|
| 386 |
"mean_output_tokens": 70.0,
|
| 387 |
-
"total_s":
|
| 388 |
"n_prompts": 100
|
| 389 |
},
|
| 390 |
{
|
| 391 |
"mode": "fixed",
|
| 392 |
"width": 4,
|
| 393 |
-
"mean_s_per_prompt": 0.
|
| 394 |
-
"std_s": 0.
|
| 395 |
-
"mean_ms_per_token":
|
| 396 |
"mean_output_tokens": 70.0,
|
| 397 |
-
"total_s":
|
| 398 |
"n_prompts": 100
|
| 399 |
},
|
| 400 |
{
|
| 401 |
"mode": "fixed",
|
| 402 |
"width": 8,
|
| 403 |
-
"mean_s_per_prompt": 0.
|
| 404 |
-
"std_s": 0.
|
| 405 |
-
"mean_ms_per_token":
|
| 406 |
"mean_output_tokens": 70.0,
|
| 407 |
-
"total_s":
|
| 408 |
"n_prompts": 100
|
| 409 |
}
|
| 410 |
],
|
|
@@ -491,13 +491,10 @@
|
|
| 491 |
"timing_samples": 100,
|
| 492 |
"judge_model": "EleutherAI/pythia-410m",
|
| 493 |
"use_bertscore": true,
|
| 494 |
-
"out_dir": "/
|
| 495 |
"hf_user": null,
|
| 496 |
"repo_name": "anlp-a2-decoding",
|
| 497 |
"push_to_hub": true,
|
| 498 |
-
"private": false
|
| 499 |
-
"wandb": true,
|
| 500 |
-
"wandb_project": "anlp-a2",
|
| 501 |
-
"wandb_entity": null
|
| 502 |
}
|
| 503 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"summary": {
|
| 3 |
+
"reference_ppl_mean": 27.426984312057495,
|
| 4 |
+
"reference_ppl_median": 24.0395565032959,
|
| 5 |
"n_samples": 1000,
|
| 6 |
"model": "EleutherAI/pythia-160m",
|
| 7 |
"max_new_tokens": 70,
|
| 8 |
+
"beam_w1_equals_greedy_frac": 0.997,
|
| 9 |
+
"reference_judge_ppl_median": 16.601248741149902
|
| 10 |
},
|
| 11 |
"results": [
|
| 12 |
{
|
| 13 |
+
"precision": 0.156788215552466,
|
| 14 |
"recall": 0.10761634910100995,
|
| 15 |
+
"f1": 0.11682790615891263,
|
| 16 |
+
"accuracy": 0.013836985105826744,
|
| 17 |
+
"bleu": 0.45975591061692944,
|
| 18 |
+
"self_ppl_mean": 2.129623557711418,
|
| 19 |
+
"self_ppl_median": 1.9777633712182454,
|
| 20 |
+
"distinct_1": 0.037811864720014784,
|
| 21 |
+
"distinct_2": 0.11828823642295144,
|
| 22 |
"rep_4gram": 0.3296551592928797,
|
| 23 |
+
"avg_words": 27.055,
|
| 24 |
"name": "greedy",
|
| 25 |
"strategy": "greedy",
|
| 26 |
"params": {
|
| 27 |
"name": "greedy",
|
| 28 |
"strategy": "greedy"
|
| 29 |
},
|
| 30 |
+
"time_s": 26.33022141456604,
|
| 31 |
+
"ms_per_prompt": 26.33022141456604,
|
| 32 |
"gen_tokens_mean": 69.995,
|
| 33 |
+
"judge_ppl_median": 3.7136934995651245,
|
| 34 |
+
"judge_ppl_mean": 3.8431873861551287,
|
| 35 |
+
"bertscore_p": 0.8487190008163452,
|
| 36 |
+
"bertscore_r": 0.8463276028633118,
|
| 37 |
+
"bertscore_f1": 0.847396731376648
|
| 38 |
},
|
| 39 |
{
|
| 40 |
"precision": 0.1568385962211188,
|
|
|
|
| 42 |
"f1": 0.11688205526981743,
|
| 43 |
"accuracy": 0.013886833130142854,
|
| 44 |
"bleu": 0.4603869452185167,
|
| 45 |
+
"self_ppl_mean": 2.1293727944369447,
|
| 46 |
+
"self_ppl_median": 1.977726615504968,
|
| 47 |
"distinct_1": 0.03780348102435239,
|
| 48 |
"distinct_2": 0.11810751697939449,
|
| 49 |
"rep_4gram": 0.3296463873630552,
|
|
|
|
| 55 |
"strategy": "beam",
|
| 56 |
"width": 1
|
| 57 |
},
|
| 58 |
+
"time_s": 110.271555185318,
|
| 59 |
+
"ms_per_prompt": 110.271555185318,
|
| 60 |
"gen_tokens_mean": 69.995,
|
| 61 |
+
"judge_ppl_median": 3.7136934995651245,
|
| 62 |
+
"judge_ppl_mean": 3.839161422610283,
|
| 63 |
"bertscore_p": 0.8486897945404053,
|
| 64 |
"bertscore_r": 0.8463218808174133,
|
| 65 |
"bertscore_f1": 0.8473787903785706
|
|
|
|
| 70 |
"f1": 0.11012341441029258,
|
| 71 |
"accuracy": 0.010045733414015445,
|
| 72 |
"bleu": 0.29556628142570907,
|
| 73 |
+
"self_ppl_mean": 1.8974243870210339,
|
| 74 |
+
"self_ppl_median": 1.8302103567597376,
|
| 75 |
"distinct_1": 0.045782342657342656,
|
| 76 |
"distinct_2": 0.13661581137309292,
|
| 77 |
"rep_4gram": 0.20882754144393487,
|
|
|
|
| 83 |
"strategy": "beam",
|
| 84 |
"width": 2
|
| 85 |
},
|
| 86 |
+
"time_s": 107.95216870307922,
|
| 87 |
+
"ms_per_prompt": 107.95216870307922,
|
| 88 |
"gen_tokens_mean": 69.827,
|
| 89 |
+
"judge_ppl_median": 4.08447003364563,
|
| 90 |
+
"judge_ppl_mean": 5.812772500276566,
|
| 91 |
"bertscore_p": 0.8609820604324341,
|
| 92 |
+
"bertscore_r": 0.8465735912322998,
|
| 93 |
"bertscore_f1": 0.8535703420639038
|
| 94 |
},
|
| 95 |
{
|
| 96 |
+
"precision": 0.1976862812247924,
|
| 97 |
"recall": 0.07404912467040367,
|
| 98 |
+
"f1": 0.09568651928951545,
|
| 99 |
"accuracy": 0.008065531697039307,
|
| 100 |
+
"bleu": 0.340259807839598,
|
| 101 |
+
"self_ppl_mean": 1.7576852720858818,
|
| 102 |
+
"self_ppl_median": 1.739890666494589,
|
| 103 |
+
"distinct_1": 0.040265558374264585,
|
| 104 |
+
"distinct_2": 0.11690534603754207,
|
| 105 |
+
"rep_4gram": 0.23782374503889867,
|
| 106 |
+
"avg_words": 18.527,
|
| 107 |
"name": "beam_w4",
|
| 108 |
"strategy": "beam",
|
| 109 |
"params": {
|
|
|
|
| 111 |
"strategy": "beam",
|
| 112 |
"width": 4
|
| 113 |
},
|
| 114 |
+
"time_s": 118.95717024803162,
|
| 115 |
+
"ms_per_prompt": 118.95717024803162,
|
| 116 |
"gen_tokens_mean": 69.253,
|
| 117 |
+
"judge_ppl_median": 3.7220958471298218,
|
| 118 |
+
"judge_ppl_mean": 549.211596192956,
|
| 119 |
+
"bertscore_p": 0.8594744801521301,
|
| 120 |
+
"bertscore_r": 0.8445523977279663,
|
| 121 |
+
"bertscore_f1": 0.851769208908081
|
| 122 |
},
|
| 123 |
{
|
| 124 |
+
"precision": 0.20828856855773425,
|
| 125 |
+
"recall": 0.16455016427602215,
|
| 126 |
+
"f1": 0.16573516044843375,
|
| 127 |
+
"accuracy": 0.015756478767379786,
|
| 128 |
+
"bleu": 0.5589188575413241,
|
| 129 |
+
"self_ppl_mean": 5.8339501863641905,
|
| 130 |
+
"self_ppl_median": 5.838575948334771,
|
| 131 |
+
"distinct_1": 0.07212438521339044,
|
| 132 |
+
"distinct_2": 0.35802064558413893,
|
| 133 |
+
"rep_4gram": 0.028893427447938293,
|
| 134 |
+
"avg_words": 31.515,
|
| 135 |
"name": "topk_k5",
|
| 136 |
"strategy": "top_k",
|
| 137 |
"params": {
|
|
|
|
| 139 |
"strategy": "top_k",
|
| 140 |
"k": 5
|
| 141 |
},
|
| 142 |
+
"time_s": 28.06767702102661,
|
| 143 |
+
"ms_per_prompt": 28.06767702102661,
|
| 144 |
+
"gen_tokens_mean": 69.697,
|
| 145 |
+
"judge_ppl_median": 8.458185195922852,
|
| 146 |
+
"judge_ppl_mean": 9.329122072458267,
|
| 147 |
+
"bertscore_p": 0.8579514026641846,
|
| 148 |
+
"bertscore_r": 0.8530383706092834,
|
| 149 |
+
"bertscore_f1": 0.8553735613822937
|
| 150 |
},
|
| 151 |
{
|
| 152 |
+
"precision": 0.1919000986912784,
|
| 153 |
+
"recall": 0.1684283187083047,
|
| 154 |
+
"f1": 0.1622514196784391,
|
| 155 |
+
"accuracy": 0.013794441209097598,
|
| 156 |
+
"bleu": 0.44804585179427503,
|
| 157 |
+
"self_ppl_mean": 10.859201539564154,
|
| 158 |
+
"self_ppl_median": 9.966973243847942,
|
| 159 |
+
"distinct_1": 0.09244218671549662,
|
| 160 |
+
"distinct_2": 0.4732998630762209,
|
| 161 |
+
"rep_4gram": 0.004260111395545372,
|
| 162 |
+
"avg_words": 33.859,
|
| 163 |
"name": "topk_k20",
|
| 164 |
"strategy": "top_k",
|
| 165 |
"params": {
|
|
|
|
| 167 |
"strategy": "top_k",
|
| 168 |
"k": 20
|
| 169 |
},
|
| 170 |
+
"time_s": 27.953922510147095,
|
| 171 |
+
"ms_per_prompt": 27.953922510147095,
|
| 172 |
+
"gen_tokens_mean": 69.165,
|
| 173 |
+
"judge_ppl_median": 14.761709213256836,
|
| 174 |
+
"judge_ppl_mean": 50.361770061254504
|
| 175 |
},
|
| 176 |
{
|
| 177 |
+
"precision": 0.17549255996014995,
|
| 178 |
+
"recall": 0.16199041954465634,
|
| 179 |
+
"f1": 0.15203213911919755,
|
| 180 |
+
"accuracy": 0.011857919480724241,
|
| 181 |
+
"bleu": 0.44096547944277925,
|
| 182 |
+
"self_ppl_mean": 15.653030294977679,
|
| 183 |
+
"self_ppl_median": 13.604209219791796,
|
| 184 |
+
"distinct_1": 0.106938636169668,
|
| 185 |
+
"distinct_2": 0.5367388758782201,
|
| 186 |
+
"rep_4gram": 0.002577424448111978,
|
| 187 |
+
"avg_words": 35.151,
|
| 188 |
"name": "topk_k50",
|
| 189 |
"strategy": "top_k",
|
| 190 |
"params": {
|
|
|
|
| 192 |
"strategy": "top_k",
|
| 193 |
"k": 50
|
| 194 |
},
|
| 195 |
+
"time_s": 27.92880129814148,
|
| 196 |
+
"ms_per_prompt": 27.92880129814148,
|
| 197 |
+
"gen_tokens_mean": 68.635,
|
| 198 |
+
"judge_ppl_median": 20.48440647125244,
|
| 199 |
+
"judge_ppl_mean": 72.74511349225044
|
| 200 |
},
|
| 201 |
{
|
| 202 |
+
"precision": 0.20069336987864045,
|
| 203 |
+
"recall": 0.14639978279849664,
|
| 204 |
+
"f1": 0.1519355828806502,
|
| 205 |
+
"accuracy": 0.01273002667646736,
|
| 206 |
+
"bleu": 0.5404882348932311,
|
| 207 |
+
"self_ppl_mean": 7.576500820452772,
|
| 208 |
+
"self_ppl_median": 6.75727633465444,
|
| 209 |
+
"distinct_1": 0.09244264507422402,
|
| 210 |
+
"distinct_2": 0.43183742591024554,
|
| 211 |
+
"rep_4gram": 0.021025283581782708,
|
| 212 |
+
"avg_words": 28.158,
|
| 213 |
"name": "topk_k50_t0.7",
|
| 214 |
"strategy": "top_k",
|
| 215 |
"params": {
|
|
|
|
| 218 |
"k": 50,
|
| 219 |
"temperature": 0.7
|
| 220 |
},
|
| 221 |
+
"time_s": 27.997068405151367,
|
| 222 |
+
"ms_per_prompt": 27.997068405151367,
|
| 223 |
+
"gen_tokens_mean": 69.563,
|
| 224 |
+
"judge_ppl_median": 10.548301219940186,
|
| 225 |
+
"judge_ppl_mean": 1104.2365723810196
|
| 226 |
},
|
| 227 |
{
|
| 228 |
+
"precision": 0.21224675405441254,
|
| 229 |
+
"recall": 0.14685590502611967,
|
| 230 |
+
"f1": 0.15687408460192412,
|
| 231 |
+
"accuracy": 0.013971389777601836,
|
| 232 |
+
"bleu": 0.5397175501288309,
|
| 233 |
+
"self_ppl_mean": 6.038022332522205,
|
| 234 |
+
"self_ppl_median": 5.858416877967823,
|
| 235 |
+
"distinct_1": 0.1009201217053411,
|
| 236 |
+
"distinct_2": 0.4334855403348554,
|
| 237 |
+
"rep_4gram": 0.02484618782785406,
|
| 238 |
+
"avg_words": 27.279,
|
| 239 |
"name": "topp_p0.5",
|
| 240 |
"strategy": "top_p",
|
| 241 |
"params": {
|
|
|
|
| 243 |
"strategy": "top_p",
|
| 244 |
"p": 0.5
|
| 245 |
},
|
| 246 |
+
"time_s": 31.63517665863037,
|
| 247 |
+
"ms_per_prompt": 31.635176658630375,
|
| 248 |
+
"gen_tokens_mean": 69.823,
|
| 249 |
+
"judge_ppl_median": 9.4617280960083,
|
| 250 |
+
"judge_ppl_mean": 1095.229723884821
|
| 251 |
},
|
| 252 |
{
|
| 253 |
+
"precision": 0.1754558860783798,
|
| 254 |
+
"recall": 0.15128935460540213,
|
| 255 |
+
"f1": 0.14627172467982152,
|
| 256 |
+
"accuracy": 0.010996779233892341,
|
| 257 |
+
"bleu": 0.3233499868741911,
|
| 258 |
+
"self_ppl_mean": 17.14533789994608,
|
| 259 |
+
"self_ppl_median": 14.304176726370176,
|
| 260 |
+
"distinct_1": 0.13880592419250545,
|
| 261 |
+
"distinct_2": 0.5860382392174299,
|
| 262 |
+
"rep_4gram": 0.003378257483535917,
|
| 263 |
+
"avg_words": 32.477,
|
| 264 |
"name": "topp_p0.8",
|
| 265 |
"strategy": "top_p",
|
| 266 |
"params": {
|
|
|
|
| 268 |
"strategy": "top_p",
|
| 269 |
"p": 0.8
|
| 270 |
},
|
| 271 |
+
"time_s": 31.48725962638855,
|
| 272 |
+
"ms_per_prompt": 31.48725962638855,
|
| 273 |
+
"gen_tokens_mean": 69.009,
|
| 274 |
+
"judge_ppl_median": 23.211604118347168,
|
| 275 |
+
"judge_ppl_mean": 74.37143414640427
|
| 276 |
},
|
| 277 |
{
|
| 278 |
+
"precision": 0.15602106748659775,
|
| 279 |
+
"recall": 0.14042348676499086,
|
| 280 |
+
"f1": 0.13287360175699992,
|
| 281 |
+
"accuracy": 0.00936425787467936,
|
| 282 |
+
"bleu": 0.16536685767069867,
|
| 283 |
+
"self_ppl_mean": 39.594243798258624,
|
| 284 |
+
"self_ppl_median": 33.30959383748847,
|
| 285 |
+
"distinct_1": 0.18891279361056262,
|
| 286 |
+
"distinct_2": 0.701587687076895,
|
| 287 |
+
"rep_4gram": 0.0007256760411977545,
|
| 288 |
+
"avg_words": 33.931,
|
| 289 |
"name": "topp_p0.95",
|
| 290 |
"strategy": "top_p",
|
| 291 |
"params": {
|
|
|
|
| 293 |
"strategy": "top_p",
|
| 294 |
"p": 0.95
|
| 295 |
},
|
| 296 |
+
"time_s": 31.551427125930786,
|
| 297 |
+
"ms_per_prompt": 31.551427125930786,
|
| 298 |
+
"gen_tokens_mean": 68.636,
|
| 299 |
+
"judge_ppl_median": 54.274309158325195,
|
| 300 |
+
"judge_ppl_mean": 297.4285540444851
|
| 301 |
},
|
| 302 |
{
|
| 303 |
+
"precision": 0.19970724391003492,
|
| 304 |
+
"recall": 0.14364941747564147,
|
| 305 |
+
"f1": 0.15108641777377704,
|
| 306 |
+
"accuracy": 0.01395932104782926,
|
| 307 |
+
"bleu": 0.5577671411688147,
|
| 308 |
+
"self_ppl_mean": 5.73871449144444,
|
| 309 |
+
"self_ppl_median": 5.589571006013263,
|
| 310 |
+
"distinct_1": 0.09601266733841946,
|
| 311 |
+
"distinct_2": 0.408413901228116,
|
| 312 |
+
"rep_4gram": 0.034714608915333796,
|
| 313 |
+
"avg_words": 27.788,
|
| 314 |
"name": "topp_p0.9_t0.7",
|
| 315 |
"strategy": "top_p",
|
| 316 |
"params": {
|
|
|
|
| 319 |
"p": 0.9,
|
| 320 |
"temperature": 0.7
|
| 321 |
},
|
| 322 |
+
"time_s": 31.56927514076233,
|
| 323 |
+
"ms_per_prompt": 31.569275140762326,
|
| 324 |
+
"gen_tokens_mean": 69.865,
|
| 325 |
+
"judge_ppl_median": 9.213471412658691,
|
| 326 |
+
"judge_ppl_mean": 1094.454825058937
|
| 327 |
}
|
| 328 |
],
|
| 329 |
"beam_timing": [
|
| 330 |
{
|
| 331 |
"mode": "natural",
|
| 332 |
"width": 1,
|
| 333 |
+
"mean_s_per_prompt": 0.781981463432312,
|
| 334 |
+
"std_s": 0.01558768772931337,
|
| 335 |
+
"mean_ms_per_token": 11.171163763318747,
|
| 336 |
"mean_output_tokens": 70.0,
|
| 337 |
+
"total_s": 78.1981463432312,
|
| 338 |
"n_prompts": 100
|
| 339 |
},
|
| 340 |
{
|
| 341 |
"mode": "natural",
|
| 342 |
"width": 2,
|
| 343 |
+
"mean_s_per_prompt": 0.793917977809906,
|
| 344 |
+
"std_s": 0.022438927991426688,
|
| 345 |
+
"mean_ms_per_token": 11.364886324126998,
|
| 346 |
"mean_output_tokens": 69.86,
|
| 347 |
+
"total_s": 79.3917977809906,
|
| 348 |
"n_prompts": 100
|
| 349 |
},
|
| 350 |
{
|
| 351 |
"mode": "natural",
|
| 352 |
"width": 4,
|
| 353 |
+
"mean_s_per_prompt": 0.8327497005462646,
|
| 354 |
+
"std_s": 0.033384079158313755,
|
| 355 |
+
"mean_ms_per_token": 11.970075382877122,
|
| 356 |
"mean_output_tokens": 69.59,
|
| 357 |
+
"total_s": 83.27497005462646,
|
| 358 |
"n_prompts": 100
|
| 359 |
},
|
| 360 |
{
|
| 361 |
"mode": "natural",
|
| 362 |
"width": 8,
|
| 363 |
+
"mean_s_per_prompt": 0.8716441249847412,
|
| 364 |
+
"std_s": 0.043158742726592765,
|
| 365 |
+
"mean_ms_per_token": 12.592297802702353,
|
| 366 |
"mean_output_tokens": 69.34,
|
| 367 |
+
"total_s": 87.16441249847412,
|
| 368 |
"n_prompts": 100
|
| 369 |
},
|
| 370 |
{
|
| 371 |
"mode": "fixed",
|
| 372 |
"width": 1,
|
| 373 |
+
"mean_s_per_prompt": 0.7738243556022644,
|
| 374 |
+
"std_s": 0.01421080819544866,
|
| 375 |
+
"mean_ms_per_token": 11.054633651460922,
|
| 376 |
"mean_output_tokens": 70.0,
|
| 377 |
+
"total_s": 77.38243556022644,
|
| 378 |
"n_prompts": 100
|
| 379 |
},
|
| 380 |
{
|
| 381 |
"mode": "fixed",
|
| 382 |
"width": 2,
|
| 383 |
+
"mean_s_per_prompt": 0.7971447992324829,
|
| 384 |
+
"std_s": 0.02233234077874458,
|
| 385 |
+
"mean_ms_per_token": 11.387782846178329,
|
| 386 |
"mean_output_tokens": 70.0,
|
| 387 |
+
"total_s": 79.71447992324829,
|
| 388 |
"n_prompts": 100
|
| 389 |
},
|
| 390 |
{
|
| 391 |
"mode": "fixed",
|
| 392 |
"width": 4,
|
| 393 |
+
"mean_s_per_prompt": 0.8367985081672669,
|
| 394 |
+
"std_s": 0.013029678554817858,
|
| 395 |
+
"mean_ms_per_token": 11.954264402389526,
|
| 396 |
"mean_output_tokens": 70.0,
|
| 397 |
+
"total_s": 83.67985081672668,
|
| 398 |
"n_prompts": 100
|
| 399 |
},
|
| 400 |
{
|
| 401 |
"mode": "fixed",
|
| 402 |
"width": 8,
|
| 403 |
+
"mean_s_per_prompt": 0.8789880871772766,
|
| 404 |
+
"std_s": 0.012277801042479799,
|
| 405 |
+
"mean_ms_per_token": 12.556972673961095,
|
| 406 |
"mean_output_tokens": 70.0,
|
| 407 |
+
"total_s": 87.89880871772766,
|
| 408 |
"n_prompts": 100
|
| 409 |
}
|
| 410 |
],
|
|
|
|
| 491 |
"timing_samples": 100,
|
| 492 |
"judge_model": "EleutherAI/pythia-410m",
|
| 493 |
"use_bertscore": true,
|
| 494 |
+
"out_dir": "/kaggle/working/outputs/decoding",
|
| 495 |
"hf_user": null,
|
| 496 |
"repo_name": "anlp-a2-decoding",
|
| 497 |
"push_to_hub": true,
|
| 498 |
+
"private": false
|
|
|
|
|
|
|
|
|
|
| 499 |
}
|
| 500 |
}
|
generations.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|