From 2f221a4f421bbe700028a814e729dc932b64369a Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Tue, 8 Apr 2025 22:54:09 +0200 Subject: [PATCH 1/4] [Util] add more common input preproc options to exec_qonnx --- src/qonnx/util/exec_qonnx.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/qonnx/util/exec_qonnx.py b/src/qonnx/util/exec_qonnx.py index 5c059281..345060f1 100644 --- a/src/qonnx/util/exec_qonnx.py +++ b/src/qonnx/util/exec_qonnx.py @@ -62,6 +62,9 @@ def exec_qonnx( output_mode: output_mode_options = OUTPUT_MODE_NAME, argmax_verify_npy: str = None, save_modified_model: str = None, + input_to_nchw=False, + input_to_nhwc=False, + input_cast2float=False, input_pix2float=False, input_zerocenter=False, maxiters: int = None, @@ -82,6 +85,9 @@ def exec_qonnx( :param argmax_verify_npy: If specified, take argmax of output and compare to this file for top-1 accuracy measurement :param save_modified_model: If specified, save the modified model (after batchsize changes or exposed intermediate tensors) with this filename + :param input_to_nchw: If specified, convert input tensors to NCHW format + :param input_to_nhwc: If specified, convert input tensors to NHWC format + :param input_cast2float: If specified, apply simple cast to float32 for input :param input_pix2float: If specified, do uint8 [0,255] -> fp32 [0,1] mapping for input :param input_zerocenter: If specified together with pix2float, do uint8 [0,255] -> fp32 [-1,+1] mapping for input :param maxiters: If specified, limit maximum number of iterations (batches) to be processed @@ -158,8 +164,14 @@ def exec_qonnx( idict[inp.name] = (inp_data[inp_ind][iter] / 255.0).astype(np.float32) if input_zerocenter: idict[inp.name] = (2 * idict[inp.name] - 1.0).astype(np.float32) + elif input_cast2float: + idict[inp.name] = inp_data[inp_ind][iter].astype(np.float32) else: idict[inp.name] = inp_data[inp_ind][iter] + if input_to_nhwc: + idict[inp.name] = np.transpose(idict[inp.name], (0, 2, 3, 1)) + if input_to_nchw: + idict[inp.name] = np.transpose(idict[inp.name], (0, 3, 1, 2)) if n_custom_nodes > 0: # run node-by-node in qonnx odict = execute_onnx(model, idict) From 4a9e7834695a9f3c6325a6f85d59857e0d915e81 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Sun, 20 Apr 2025 19:21:12 +0100 Subject: [PATCH 2/4] [Util] add early stop option to qonnx_exec --- src/qonnx/util/exec_qonnx.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qonnx/util/exec_qonnx.py b/src/qonnx/util/exec_qonnx.py index 345060f1..b115c970 100644 --- a/src/qonnx/util/exec_qonnx.py +++ b/src/qonnx/util/exec_qonnx.py @@ -68,7 +68,8 @@ def exec_qonnx( input_pix2float=False, input_zerocenter=False, maxiters: int = None, - output_nosave=False + output_nosave=False, + early_exit_acc_ratio=None ): """Execute a given QONNX model by initializing its inputs from .npy files, and write outputs as .npy files. @@ -92,6 +93,7 @@ def exec_qonnx( :param input_zerocenter: If specified together with pix2float, do uint8 [0,255] -> fp32 [-1,+1] mapping for input :param maxiters: If specified, limit maximum number of iterations (batches) to be processed :param output_nosave: If specified, do not save output tensors to files + :param early_exit_acc_ratio: If specified as a float number between 0 and 1, early exit if any batch accuracy falls under """ assert output_mode in output_modes, "Unrecognized output mode" @@ -202,6 +204,9 @@ def exec_qonnx( "Batch [%d/%d]: ok %d nok %d accuracy %f (overall ok %d nok %d accuracy %f)" % (iter + 1, n_dset_iters, ok_batch, nok_batch, accuracy_batch, ok, nok, accuracy_overall) ) + if early_exit_acc_ratio is not None and accuracy_batch < early_exit_acc_ratio: + return (ok, nok) + return (ok, nok) def main(): From fc8da46326d8ccee0e24c4d6832b067744e286d9 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Sat, 3 May 2025 16:32:17 +0200 Subject: [PATCH 3/4] [Util] allow overriding executor fxn in exec_qonnx --- src/qonnx/util/exec_qonnx.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/qonnx/util/exec_qonnx.py b/src/qonnx/util/exec_qonnx.py index b115c970..8a599963 100644 --- a/src/qonnx/util/exec_qonnx.py +++ b/src/qonnx/util/exec_qonnx.py @@ -69,7 +69,8 @@ def exec_qonnx( input_zerocenter=False, maxiters: int = None, output_nosave=False, - early_exit_acc_ratio=None + early_exit_acc_ratio=None, + override_exec_onnx=None ): """Execute a given QONNX model by initializing its inputs from .npy files, and write outputs as .npy files. @@ -94,6 +95,7 @@ def exec_qonnx( :param maxiters: If specified, limit maximum number of iterations (batches) to be processed :param output_nosave: If specified, do not save output tensors to files :param early_exit_acc_ratio: If specified as a float number between 0 and 1, early exit if any batch accuracy falls under + :param override_exec_onnx: If specified, use this function to execute the model instead of qonnx """ assert output_mode in output_modes, "Unrecognized output mode" @@ -174,14 +176,18 @@ def exec_qonnx( idict[inp.name] = np.transpose(idict[inp.name], (0, 2, 3, 1)) if input_to_nchw: idict[inp.name] = np.transpose(idict[inp.name], (0, 3, 1, 2)) - if n_custom_nodes > 0: - # run node-by-node in qonnx - odict = execute_onnx(model, idict) + if override_exec_onnx is not None: + # run using specified custom execution function + odict = override_exec_onnx(model, idict) else: - # run using onnxruntime - sess = rt.InferenceSession(model.model.SerializeToString()) - output_list = sess.run(None, idict) - odict = {outp.name: output_list[oind] for oind, outp in enumerate(model.graph.output)} + if n_custom_nodes > 0: + # run node-by-node in qonnx + odict = execute_onnx(model, idict) + else: + # run using onnxruntime + sess = rt.InferenceSession(model.model.SerializeToString()) + output_list = sess.run(None, idict) + odict = {outp.name: output_list[oind] for oind, outp in enumerate(model.graph.output)} if not output_nosave: for out_ind, outp in enumerate(model.graph.output): # save generated outputs From 2476c30ebf0a3a660799fcd82f19d8003c01e5e4 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Wed, 7 May 2025 17:29:16 +0100 Subject: [PATCH 4/4] [Util] separate qonnx-exec argmax and validation options --- src/qonnx/util/exec_qonnx.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/qonnx/util/exec_qonnx.py b/src/qonnx/util/exec_qonnx.py index 8a599963..0503cd9a 100644 --- a/src/qonnx/util/exec_qonnx.py +++ b/src/qonnx/util/exec_qonnx.py @@ -60,7 +60,8 @@ def exec_qonnx( expose_intermediates: str = None, output_prefix: str = "out_", output_mode: output_mode_options = OUTPUT_MODE_NAME, - argmax_verify_npy: str = None, + verify_npy: str = None, + verify_argmax=False, save_modified_model: str = None, input_to_nchw=False, input_to_nhwc=False, @@ -84,7 +85,8 @@ def exec_qonnx( Matched patterns will expose intermediate outputs as top-level outputs. :param output_prefix: Prefix for the generated output files. :param output_mode: Naming mode for generated output files. - :param argmax_verify_npy: If specified, take argmax of output and compare to this file for top-1 accuracy measurement + :param verify_npy: If specified, compare output to this file for top-1 accuracy measurement + :param verify_argmax: If specified, take argmax of output before comparing to verify_npy :param save_modified_model: If specified, save the modified model (after batchsize changes or exposed intermediate tensors) with this filename :param input_to_nchw: If specified, convert input tensors to NCHW format @@ -142,8 +144,8 @@ def exec_qonnx( inp = inp.reshape(n_dset_iters, bsize, *inp.shape[1:]) inp_data_reshaped.append(inp) inp_data = inp_data_reshaped - if argmax_verify_npy is not None: - labels = np.load(argmax_verify_npy) + if verify_npy is not None: + labels = np.load(verify_npy) assert labels.shape[0] == dset_size, "Label size must match dataset size" labels = labels.reshape(n_dset_iters, bsize, *labels.shape[1:]) else: @@ -160,7 +162,7 @@ def exec_qonnx( for iter in pbar: iter_suffix = "_batch%d" % iter idict = {} - if not argmax_verify_npy: + if not verify_npy: pbar.set_description("Batch [%d/%d]: running" % (iter + 1, n_dset_iters)) # supply inputs and execute for inp_ind, inp in enumerate(model.graph.input): @@ -196,10 +198,11 @@ def exec_qonnx( elif output_mode == OUTPUT_MODE_NAME: oname = outp.name np.save(output_prefix + oname + iter_suffix + ".npy", odict[outp.name]) - if argmax_verify_npy: + if verify_npy: # measure accuracy for output ret = odict[model.graph.output[0].name] - ret = np.argmax(ret, axis=-1) + if verify_argmax: + ret = np.argmax(ret, axis=-1) ok_batch = np.count_nonzero(ret == labels[iter]) nok_batch = bsize - ok_batch ok += ok_batch