@@ -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
193257if __name__ == "__main__" :
0 commit comments