skypro1111 commited on
Commit
6781c62
·
verified ·
1 Parent(s): 4c4804a

скрипт заміру швидкості

Browse files
Files changed (1) hide show
  1. scripts/bench_tps.py +128 -0
scripts/bench_tps.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Швидкість декоду для трьох шляхів: transformers / onnxruntime / llama.cpp.
2
+
3
+ Міряємо ОДНЕ й те саме: генерацію одного рядка за раз (так модель і працює —
4
+ речення за реченням), greedy, без препроцесингу. Рахуємо згенеровані токени,
5
+ поділені на час саме генерації.
6
+
7
+ python bench_tps.py <тека_моделі> [--gguf-url http://127.0.0.1:8903]
8
+
9
+ llama.cpp не міряємо самі — беремо його власні timings, вони точніші за наш
10
+ секундомір навколо HTTP.
11
+ """
12
+ import argparse
13
+ import json
14
+ import time
15
+ import urllib.request
16
+
17
+ PROMPTS = [
18
+ "Зустріч о 08:05 у кабінеті 12.",
19
+ "Збитки оцінили в 7 000 000 000 доларів.",
20
+ "Пиши на support@shop.com.ua або дзвони 067 123 45 67.",
21
+ "Борг сягнув 2 625 414 042 726 гривень.",
22
+ "Марафон стартує 12 жовтня о 8:15, дистанції 5, 10 і 21,1 км.",
23
+ "У специфікації вказано роз'єм тип C та частоту 60 Гц.",
24
+ ]
25
+ WARMUP = 2
26
+
27
+
28
+ def run_hf(model_dir, device):
29
+ import torch
30
+ from transformers import AutoModelForCausalLM, AutoTokenizer
31
+ tok = AutoTokenizer.from_pretrained(model_dir)
32
+ model = AutoModelForCausalLM.from_pretrained(
33
+ model_dir, dtype=torch.bfloat16 if device == "cuda" else torch.float32)
34
+ model = model.to(device).eval()
35
+
36
+ def gen(text):
37
+ ids = tok.apply_chat_template([{"role": "user", "content": text}],
38
+ add_generation_prompt=True,
39
+ return_tensors="pt").to(device)
40
+ t0 = time.perf_counter()
41
+ with torch.inference_mode():
42
+ out = model.generate(ids, max_new_tokens=192, do_sample=False)
43
+ if device == "cuda":
44
+ torch.cuda.synchronize()
45
+ return out.shape[-1] - ids.shape[-1], time.perf_counter() - t0
46
+
47
+ return gen
48
+
49
+
50
+ def run_onnx(model_dir, provider="CPUExecutionProvider"):
51
+ from optimum.onnxruntime import ORTModelForCausalLM
52
+ from transformers import AutoTokenizer
53
+ import onnxruntime as ort
54
+ tok = AutoTokenizer.from_pretrained(model_dir)
55
+ # без явного provider optimum мовчки бере CPU, навіть коли CUDA доступна.
56
+ # io-binding на CUDA для цього графа падає (cudaErrorIllegalAddress на
57
+ # embed_tokens/Mul), тож на GPU його вимикаємо.
58
+ kw = {"provider": provider}
59
+ if provider != "CPUExecutionProvider":
60
+ kw["use_io_binding"] = False
61
+ model = ORTModelForCausalLM.from_pretrained(model_dir, subfolder="onnx", **kw)
62
+ prov = model.model.get_providers()[0] if hasattr(model, "model") else "?"
63
+ print(f" onnxruntime провайдер: {prov} "
64
+ f"(доступні: {ort.get_available_providers()})")
65
+
66
+ def gen(text):
67
+ ids = tok.apply_chat_template([{"role": "user", "content": text}],
68
+ add_generation_prompt=True,
69
+ return_tensors="pt")
70
+ t0 = time.perf_counter()
71
+ out = model.generate(ids, max_new_tokens=192, do_sample=False)
72
+ return out.shape[-1] - ids.shape[-1], time.perf_counter() - t0
73
+
74
+ return gen
75
+
76
+
77
+ def bench(name, gen):
78
+ for p in PROMPTS[:WARMUP]:
79
+ gen(p)
80
+ ntok = secs = 0
81
+ for p in PROMPTS:
82
+ n, s = gen(p)
83
+ ntok += n
84
+ secs += s
85
+ print(f" {name:24} {ntok/secs:7.1f} ток/с "
86
+ f"({ntok} токенів за {secs:.2f} с)")
87
+ return ntok / secs
88
+
89
+
90
+ def bench_gguf(url):
91
+ ntok = secs = 0
92
+ for p in PROMPTS:
93
+ body = {"messages": [{"role": "user", "content": p}],
94
+ "temperature": 0, "top_k": 1, "n_predict": 192,
95
+ "cache_prompt": False}
96
+ req = urllib.request.Request(f"{url}/v1/chat/completions",
97
+ data=json.dumps(body, ensure_ascii=False).encode(),
98
+ headers={"Content-Type": "application/json"})
99
+ with urllib.request.urlopen(req, timeout=120) as r:
100
+ d = json.loads(r.read())
101
+ t = d.get("timings") or d.get("usage", {})
102
+ ntok += t.get("predicted_n", 0)
103
+ secs += t.get("predicted_ms", 0) / 1000
104
+ print(f" {'llama.cpp (GGUF F16)':24} {ntok/secs:7.1f} ток/с "
105
+ f"({ntok} токенів за {secs:.2f} с)")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ ap = argparse.ArgumentParser()
110
+ ap.add_argument("model_dir")
111
+ ap.add_argument("--gguf-url", default=None)
112
+ ap.add_argument("--skip", default="", help="через кому: hf_cuda,hf_cpu,onnx")
113
+ args = ap.parse_args()
114
+ skip = set(args.skip.split(","))
115
+
116
+ print("\n=== швидкість декоду, один рядок за раз, greedy ===")
117
+ if "hf_cuda" not in skip:
118
+ bench("transformers (bf16, GPU)", run_hf(args.model_dir, "cuda"))
119
+ if "onnx_gpu" not in skip:
120
+ bench("onnxruntime (fp32, GPU)",
121
+ run_onnx(args.model_dir, "CUDAExecutionProvider"))
122
+ if "onnx" not in skip:
123
+ bench("onnxruntime (fp32, CPU)", run_onnx(args.model_dir))
124
+ if "hf_cpu" not in skip:
125
+ bench("transformers (fp32, CPU)", run_hf(args.model_dir, "cpu"))
126
+ if args.gguf_url:
127
+ bench_gguf(args.gguf_url)
128
+ print("BENCH_DONE")