code: def benchmark_model(m, devices, validate_outs=False):
      torch.manual_seed(1)
      global open_csv, CSV
      CSV = {"model": m}
  
      fn = fetch(MODELS[m])
      onnx_model = onnx.load(fn)
      output_names = [out.name for out in onnx_model.graph.output]
      excluded = {inp.name for inp in onnx_model.graph.initializer}
      input_shapes = {
          inp.name: tuple(
              x.dim_value if x.dim_value != 0 else 1
              for x in inp.type.tensor_type.shape.dim
          )
          for inp in onnx_model.graph.input
          if inp.name not in excluded
      }  # noqa: E501
      input_types = {
          inp.name: tensor_dtype_to_np_dtype(
              inp.type.tensor_type.elem_type
          )
          for inp in onnx_model.graph.input
          if inp.name not in excluded
      }
      # input_types = {k:v if v!=np.float16 else np.float32 for k,v in input_types.items()}  # cast
      np_inputs = {
          k: torch.randn(shp).numpy().astype(input_types[k])
          for k, shp in input_shapes.items()
      }
      assert (
          len(input_shapes) < 30
      ), f"too many input shapes {len(input_shapes)}"
  
      # print input names
      if DEBUG >= 2:
          print(
              [
                  inp.name
                  for inp in onnx_model.graph.input
                  if inp.name not in excluded
              ]
          )
  
      for device in devices:
          Device.DEFAULT = device
          inputs = {k: Tensor(inp) for k, inp in np_inputs.items()}
          tinygrad_model = get_run_onnx(onnx_model)
          benchmark(
              m,
              f"tinygrad_{device.lower()}_jitless",
              lambda: {
                  k: v.numpy()
                  for k, v in tinygrad_model(inputs).items()
              },
          )
  
          from tinygrad.jit import TinyJit
  
          tinygrad_jitted_model = TinyJit(
              lambda **kwargs: {
                  k: v.realize()
                  for k, v in tinygrad_model(kwargs).items()
              }
          )
          for _ in range(3):
              {
                  k: v.numpy()
                  for k, v in tinygrad_jitted_model(**inputs).items()
              }
          benchmark(
              m,
              f"tinygrad_{device.lower()}_jit",
              lambda: {
                  k: v.numpy()
                  for k, v in tinygrad_jitted_model(**inputs).items()
              },
          )  # noqa: F821
          del inputs, tinygrad_model, tinygrad_jitted_model
  
      # convert model to torch
      try:
          torch_model = convert(onnx_model)
      except Exception as e:
          # model conversion failed
          print(f"{m:16s}onnx2torch {type(e).__name__:>25}")
      else:
          torch_inputs = [torch.tensor(x) for x in np_inputs.values()]
          try:
              benchmark(
                  m, "torch_cpu", lambda: torch_model(*torch_inputs)
              )
          except Exception as e:
              print(f"{m:16s}torch_cpu {type(e).__name__:>25}")
  
          torch_device = "mps" if OSX else "cuda"
          torch_mps_model = torch_model.to(torch_device)
          torch_mps_inputs = [x.to(torch_device) for x in torch_inputs]
          try:
              benchmark(
                  m,
                  f"torch_{torch_device}",
                  lambda: torch_mps_model(*torch_mps_inputs),
              )
          except Exception as e:
              print(
                  f"{m:16s}torch_{torch_device} {type(e).__name__:>25}"
              )
  
      # bench onnxruntime
      ort_options = ort.SessionOptions()
      ort_options.graph_optimization_level = (
          ort.GraphOptimizationLevel.ORT_ENABLE_ALL
      )
      ort_options.log_severity_level = 3  # no warnings
      for backend in [
          "CPU",
          "CUDA" if not OSX else "CoreML",
      ]:  # https://onnxruntime.ai/docs/execution-providers/
          provider = backend + "ExecutionProvider"
          if provider not in ort.get_available_providers():
              continue
          ort_sess = ort.InferenceSession(
              str(fn), ort_options, [provider]
          )
          try:
              benchmark(
                  m,
                  f"onnxruntime_{backend.lower()}",
                  lambda: ort_sess.run(output_names, np_inputs),
              )
          except Exception as e:
              print(
                  f"{m:16s}onnxruntime_{backend.lower()} {type(e).__name__:>25}"
              )
          del ort_sess
  
      if validate_outs:
          rtol, atol = 2e-3, 2e-3  # tolerance for fp16 models
          inputs = {k: Tensor(inp) for k, inp in np_inputs.items()}
          tinygrad_model = get_run_onnx(onnx_model)
          tinygrad_out = tinygrad_model(inputs)
  
          ort_sess = ort.InferenceSession(
              str(fn), ort_options, ["CPUExecutionProvider"]
          )
          onnx_out = ort_sess.run(output_names, np_inputs)
          onnx_out = dict(
              [*[(name, x) for name, x in zip(output_names, onnx_out)]]
          )
  
          assert_allclose(tinygrad_out, onnx_out, rtol=rtol, atol=atol)
          print(
              f"{m:16s}outputs validated with rtol={rtol:.1e}, atol={atol:.1e}"
          )
  
      if open_csv is None:
          open_csv = csv.DictWriter(
              open("onnx_inference_speed.csv", "w", newline=""),
              fieldnames=list(CSV.keys()),
          )
          open_csv.writeheader()
      open_csv.writerow(CSV)
  
file_path: tinygrad/test/external/external_model_benchmark.py
imports: import csv, pathlib, time, numpy
  from os import getenv
  import torch
  import onnx
  from onnx.helper import tensor_dtype_to_np_dtype
  import onnxruntime
  from onnx2torch import convert
  from extra.onnx import get_run_onnx
  from tinygrad.helpers import OSX, DEBUG, fetch
  from tinygrad import Tensor, Device
label_desc: Use image node_id 2 for calling a global function with example usage: benchmark_model(m, devices, validate_outs) without return types