Skip to content

Commit c6b0792

Browse files
Big fix in cpu ternary multipliers and model inference output
1 parent c332422 commit c6b0792

29 files changed

Lines changed: 1712 additions & 2107 deletions

benchmarking/bit_1_58/bench_best_k.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ def bench_inference(fn, warmup=5, repeats=20):
7474

7575

7676
def bench_cpu(shapes, k_values, warmup, repeats):
77-
from multiplier.bit_1_58.cpu.rsr_v3_3_nonsquare import (
78-
RSRTernaryV3_3NonSquareMultiplier,
77+
from multiplier.bit_1_58.cpu.rsr_nonsquare import (
78+
RSRTernaryNonSquareMultiplier,
7979
)
8080

8181
rows = []
@@ -105,7 +105,7 @@ def bench_cpu(shapes, k_values, warmup, repeats):
105105
best_k, best_t = None, float("inf")
106106
for k in k_values:
107107
try:
108-
rsr = RSRTernaryV3_3NonSquareMultiplier(M, k)
108+
rsr = RSRTernaryNonSquareMultiplier(M, k)
109109
t_rsr = bench_inference(
110110
lambda: rsr(v),
111111
warmup=warmup,

benchmarking/bit_1_58/run_cpu_nonsquare.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
2121

22-
from multiplier.bit_1_58.pytorch import PytorchMultiplier
23-
from multiplier.bit_1_58.cpu.rsr_v3_3_nonsquare import RSRTernaryV3_3NonSquareMultiplier
22+
from multiplier.bit_1_58.pytorch import PytorchBF16Multiplier
23+
from multiplier.bit_1_58.cpu.rsr_nonsquare import RSRTernaryNonSquareMultiplier
2424

2525

2626
def bench_inference(multiplier, v, warmup=5, repeats=20):
@@ -49,15 +49,21 @@ def random_ternary(n_rows, n_cols):
4949
def main():
5050
# Non-square shapes: (n_rows, n_cols) — representative of neural network layers
5151
shapes = [
52+
# BitNet-b1.58-2B-4T
53+
(640, 2560),
54+
(2560, 2560),
55+
(2560, 6912),
56+
(6912, 2560),
57+
# Llama3-8B-1.58-100B-tokens
5258
(1024, 4096),
53-
(4096, 1024),
54-
(2048, 2048),
5559
(4096, 4096),
56-
(4096, 11008),
57-
(11008, 4096),
58-
(8192, 8192),
5960
(4096, 14336),
6061
(14336, 4096),
62+
# Falcon3-10B-Instruct-1.58bit
63+
(1024, 3072),
64+
(3072, 3072),
65+
(3072, 23040),
66+
(23040, 3072),
6167
]
6268
k_values = [4, 8, 12]
6369
repeats = 20
@@ -83,7 +89,7 @@ def main():
8389

8490
# Pytorch baseline (same for all k)
8591
try:
86-
m_pt = PytorchMultiplier(M)
92+
m_pt = PytorchBF16Multiplier(M)
8793
t_pytorch = bench_inference(m_pt, v, warmup=warmup, repeats=repeats)
8894
except Exception as e:
8995
print(f" [error pytorch: {e}]")
@@ -96,7 +102,7 @@ def main():
96102

97103
for k in k_values:
98104
try:
99-
m_rsr = RSRTernaryV3_3NonSquareMultiplier(M, k)
105+
m_rsr = RSRTernaryNonSquareMultiplier(M, k)
100106
t_rsr = bench_inference(m_rsr, v, warmup=warmup, repeats=repeats)
101107
except Exception as e:
102108
print(f" [error rsr_ternary_nonsquare k={k}: {e}]")

benchmarking/llms/bench_inference.py

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ def _timed_generate(model, tokenizer, prompt, max_new_tokens, use_chat_template)
2626
torch.cuda.synchronize() if torch.cuda.is_available() else None
2727
t0 = time.perf_counter()
2828
text = generate_text(
29-
model, tokenizer, prompt,
29+
model,
30+
tokenizer,
31+
prompt,
3032
max_new_tokens=max_new_tokens,
3133
use_chat_template=use_chat_template,
3234
)
@@ -35,7 +37,9 @@ def _timed_generate(model, tokenizer, prompt, max_new_tokens, use_chat_template)
3537
return text, elapsed
3638

3739

38-
def bench_one(label, load_fn, prompt, max_new_tokens, use_chat_template, warmup, repeats):
40+
def bench_one(
41+
label, load_fn, prompt, max_new_tokens, use_chat_template, warmup, repeats
42+
):
3943
print(f"\n{'='*60}")
4044
print(f" {label}")
4145
print(f"{'='*60}")
@@ -48,13 +52,17 @@ def bench_one(label, load_fn, prompt, max_new_tokens, use_chat_template, warmup,
4852

4953
# Warmup
5054
for i in range(warmup):
51-
text, dt = _timed_generate(model, tokenizer, prompt, max_new_tokens, use_chat_template)
55+
text, dt = _timed_generate(
56+
model, tokenizer, prompt, max_new_tokens, use_chat_template
57+
)
5258
print(f" Warmup {i+1}: {dt:.3f}s")
5359

5460
# Timed runs
5561
times = []
5662
for i in range(repeats):
57-
text, dt = _timed_generate(model, tokenizer, prompt, max_new_tokens, use_chat_template)
63+
text, dt = _timed_generate(
64+
model, tokenizer, prompt, max_new_tokens, use_chat_template
65+
)
5866
times.append(dt)
5967
n_tokens = len(tokenizer.encode(text))
6068
print(f" Run {i+1}: {dt:.3f}s ({n_tokens} tokens, {n_tokens/dt:.1f} tok/s)")
@@ -65,20 +73,37 @@ def bench_one(label, load_fn, prompt, max_new_tokens, use_chat_template, warmup,
6573
print(f" Output: {text[:200]}...")
6674

6775
import torch
76+
6877
del model, tokenizer
6978
if torch.cuda.is_available():
7079
torch.cuda.empty_cache()
71-
import gc; gc.collect()
80+
import gc
81+
82+
gc.collect()
83+
84+
return {
85+
"label": label,
86+
"avg_time": avg,
87+
"tok_per_s": n_tokens / avg,
88+
"n_tokens": n_tokens,
89+
}
7290

73-
return {"label": label, "avg_time": avg, "tok_per_s": n_tokens / avg, "n_tokens": n_tokens}
7491

92+
def _discover_model_dirs(model_dir, device):
93+
"""Find preprocessed model directories matching the given device suffix.
7594
76-
def _discover_model_dirs(parent_dir, device):
77-
"""Find preprocessed model subdirectories matching the given device suffix."""
78-
parent = Path(parent_dir)
95+
Accepts either a single preprocessed model directory or a parent directory
96+
containing multiple preprocessed model subdirectories.
97+
"""
98+
p = Path(model_dir)
7999
suffix = f"_{device}"
100+
# Single model directory: ends with the device suffix and has a config.
101+
if p.name.endswith(suffix) and (p / "rsr_config.json").exists():
102+
return [p]
103+
# Otherwise treat as parent directory containing multiple models.
80104
dirs = sorted(
81-
d for d in parent.iterdir()
105+
d
106+
for d in p.iterdir()
82107
if d.is_dir() and d.name.endswith(suffix) and (d / "rsr_config.json").exists()
83108
)
84109
return dirs
@@ -89,15 +114,26 @@ def main():
89114
description="Benchmark RSR vs HF ternary inference.",
90115
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
91116
)
92-
parser.add_argument("--model-dir", required=True,
93-
help="Parent directory containing preprocessed model subdirectories")
94-
parser.add_argument("--prompt", required=True)
117+
parser.add_argument(
118+
"--model-dir",
119+
required=True,
120+
help="Single preprocessed model directory or parent directory containing multiple",
121+
)
122+
parser.add_argument(
123+
"--prompt",
124+
required=False,
125+
default="Write the numbers from one to two hundred in words separated by commas only:",
126+
)
95127
parser.add_argument("--max-new-tokens", type=int, default=64)
96128
parser.add_argument("--warmup", type=int, default=1)
97129
parser.add_argument("--repeats", type=int, default=3)
98130
parser.add_argument("--no-chat-template", action="store_true")
99-
parser.add_argument("--device", required=True, choices=["cpu", "cuda"],
100-
help="Device to benchmark on (also selects model variants)")
131+
parser.add_argument(
132+
"--device",
133+
required=True,
134+
choices=["cpu", "cuda"],
135+
help="Device to benchmark on (also selects model variants)",
136+
)
101137
_ALL_HF_DTYPES = {
102138
"cpu": ["float32", "bfloat16"],
103139
"cuda": ["float32", "bfloat16"],
@@ -110,10 +146,13 @@ def main():
110146
+ [f"hf_{d}" for d in _ALL_HF_DTYPES["cuda"]]
111147
+ [f"hf_{d}" for d in _EXTRA_DTYPES]
112148
)
113-
parser.add_argument("--backends", nargs="+",
114-
default=None,
115-
choices=all_backend_names,
116-
help="Backends to benchmark (default: rsr + all HF dtypes for device)")
149+
parser.add_argument(
150+
"--backends",
151+
nargs="+",
152+
default=None,
153+
choices=all_backend_names,
154+
help="Backends to benchmark (default: rsr + all HF dtypes for device)",
155+
)
117156
args = parser.parse_args()
118157

119158
from integrations.hf.model_infer import load_preprocessed_model, load_hf_model
@@ -138,15 +177,23 @@ def main():
138177
if "rsr" in args.backends:
139178
md = str(model_dir)
140179
loaders["RSR"] = lambda md=md: load_preprocessed_model(
141-
md, device=args.device,
180+
md,
181+
device=args.device,
182+
dtype="bfloat16",
142183
)
143184
is_bf16_model = "bf16" in model_name or "bfloat16" in model_name
144-
hf_dtypes = ["bfloat16"] if is_bf16_model else _ALL_HF_DTYPES[args.device] + _EXTRA_DTYPES
185+
hf_dtypes = (
186+
["bfloat16"]
187+
if is_bf16_model
188+
else _ALL_HF_DTYPES[args.device] + _EXTRA_DTYPES
189+
)
145190
for dtype in hf_dtypes:
146191
if f"hf_{dtype}" in args.backends:
147192
md = str(model_dir)
148193
loaders[f"HF {dtype}"] = lambda md=md, dt=dtype: load_hf_model(
149-
md, device=args.device, dtype=dt,
194+
md,
195+
device=args.device,
196+
dtype=dt,
150197
)
151198
for label, load_fn in loaders.items():
152199
tasks.append((model_name, model_dir, label, load_fn))
@@ -155,24 +202,39 @@ def main():
155202
for i, (model_name, model_dir, label, load_fn) in enumerate(tasks):
156203
print(f"\n[{i+1}/{total}] {model_name} / {label}")
157204
try:
158-
r = bench_one(label, load_fn, args.prompt, args.max_new_tokens,
159-
use_chat, args.warmup, args.repeats)
205+
r = bench_one(
206+
label,
207+
load_fn,
208+
args.prompt,
209+
args.max_new_tokens,
210+
use_chat,
211+
args.warmup,
212+
args.repeats,
213+
)
160214
except Exception as exc:
161215
print(f" FAILED: {exc}")
162-
all_results.append({
163-
"model": model_name, "label": label,
164-
"avg_time": float("nan"), "tok_per_s": float("nan"),
165-
"n_tokens": 0, "error": str(exc),
166-
})
216+
all_results.append(
217+
{
218+
"model": model_name,
219+
"label": label,
220+
"avg_time": float("nan"),
221+
"tok_per_s": float("nan"),
222+
"n_tokens": 0,
223+
"error": str(exc),
224+
}
225+
)
167226
# Try to reset CUDA state; after a device-side assert the
168227
# context may be unrecoverable so we guard the cleanup too.
169228
import torch
229+
170230
try:
171231
if torch.cuda.is_available():
172232
torch.cuda.empty_cache()
173233
except Exception:
174234
pass
175-
import gc; gc.collect()
235+
import gc
236+
237+
gc.collect()
176238
continue
177239
r["model"] = model_name
178240
all_results.append(r)
@@ -187,7 +249,9 @@ def main():
187249
if "error" in r:
188250
print(f" {r['model']:<30} {r['label']:<15} {'FAILED':>10} {'—':>10}")
189251
else:
190-
print(f" {r['model']:<30} {r['label']:<15} {r['avg_time']:>9.3f}s {r['tok_per_s']:>9.1f}")
252+
print(
253+
f" {r['model']:<30} {r['label']:<15} {r['avg_time']:>9.3f}s {r['tok_per_s']:>9.1f}"
254+
)
191255

192256

193257
if __name__ == "__main__":

0 commit comments

Comments
 (0)