modelconv 0.5.3__tar.gz → 0.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. {modelconv-0.5.3 → modelconv-0.5.4}/PKG-INFO +2 -1
  2. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/PKG-INFO +2 -1
  3. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/SOURCES.txt +2 -2
  4. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/requires.txt +1 -0
  5. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/__init__.py +1 -1
  6. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/base_exporter.py +19 -1
  7. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc3/exporter.py +1 -0
  8. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/analyze.py +21 -17
  9. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/benchmark.py +113 -157
  10. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/exporter.py +1 -0
  11. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/__init__.py +12 -4
  12. modelconv-0.5.4/modelconverter/utils/device_handlers.py +357 -0
  13. modelconv-0.5.3/modelconverter/utils/adb_monitor.py → modelconv-0.5.4/modelconverter/utils/device_monitors.py +23 -17
  14. {modelconv-0.5.3 → modelconv-0.5.4}/requirements-analysis.txt +1 -0
  15. modelconv-0.5.4/tests/test_benchmark/conftest.py +93 -0
  16. modelconv-0.5.4/tests/test_benchmark/test_benchmark_regression.py +279 -0
  17. modelconv-0.5.3/modelconverter/utils/adb_handler.py +0 -83
  18. modelconv-0.5.3/tests/test_benchmark/conftest.py +0 -36
  19. modelconv-0.5.3/tests/test_benchmark/test_benchmark_regression.py +0 -74
  20. {modelconv-0.5.3 → modelconv-0.5.4}/LICENSE +0 -0
  21. {modelconv-0.5.3 → modelconv-0.5.4}/README.md +0 -0
  22. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/dependency_links.txt +0 -0
  23. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/entry_points.txt +0 -0
  24. {modelconv-0.5.3 → modelconv-0.5.4}/modelconv.egg-info/top_level.txt +0 -0
  25. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/__main__.py +0 -0
  26. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/cli/__init__.py +0 -0
  27. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/cli/utils.py +0 -0
  28. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/__init__.py +0 -0
  29. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/base_analyze.py +0 -0
  30. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/base_benchmark.py +0 -0
  31. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/base_inferer.py +0 -0
  32. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/base_visualize.py +0 -0
  33. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/getters.py +0 -0
  34. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/hailo/__init__.py +0 -0
  35. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/hailo/exporter.py +0 -0
  36. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/hailo/inferer.py +0 -0
  37. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/hailo/requirements.txt +0 -0
  38. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/multistage_exporter.py +0 -0
  39. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc2/__init__.py +0 -0
  40. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc2/benchmark.py +0 -0
  41. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc2/exporter.py +0 -0
  42. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc2/inferer.py +0 -0
  43. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc2/requirements.txt +0 -0
  44. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc3/__init__.py +0 -0
  45. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc3/benchmark.py +0 -0
  46. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc3/inferer.py +0 -0
  47. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc3/requirements.txt +0 -0
  48. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/__init__.py +0 -0
  49. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/inferer.py +0 -0
  50. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/requirements.txt +0 -0
  51. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/packages/rvc4/visualize.py +0 -0
  52. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/calibration_data.py +0 -0
  53. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/config.py +0 -0
  54. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/constants.py +0 -0
  55. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/docker_utils.py +0 -0
  56. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/environ.py +0 -0
  57. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/exceptions.py +0 -0
  58. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/filesystem_utils.py +0 -0
  59. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/general.py +0 -0
  60. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/hub_requests.py +0 -0
  61. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/hubai_utils.py +0 -0
  62. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/image.py +0 -0
  63. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/layout.py +0 -0
  64. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/metadata.py +0 -0
  65. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/nn_archive.py +0 -0
  66. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/onnx_compatibility.py +0 -0
  67. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/onnx_tools.py +0 -0
  68. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/progress_handler.py +0 -0
  69. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/subprocess.py +0 -0
  70. {modelconv-0.5.3 → modelconv-0.5.4}/modelconverter/utils/types.py +0 -0
  71. {modelconv-0.5.3 → modelconv-0.5.4}/pyproject.toml +0 -0
  72. {modelconv-0.5.3 → modelconv-0.5.4}/requirements-bench.txt +0 -0
  73. {modelconv-0.5.3 → modelconv-0.5.4}/requirements-dev.txt +0 -0
  74. {modelconv-0.5.3 → modelconv-0.5.4}/requirements.txt +0 -0
  75. {modelconv-0.5.3 → modelconv-0.5.4}/setup.cfg +0 -0
  76. {modelconv-0.5.3 → modelconv-0.5.4}/tests/__init__.py +0 -0
  77. {modelconv-0.5.3 → modelconv-0.5.4}/tests/conftest.py +0 -0
  78. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_benchmark/__init__.py +0 -0
  79. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/__init__.py +0 -0
  80. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/common.py +0 -0
  81. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/metrics/__init__.py +0 -0
  82. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/metrics/base_metric.py +0 -0
  83. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/metrics/mnist_metric.py +0 -0
  84. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/metrics/resnet_metric.py +0 -0
  85. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/metrics/yolov6_metric.py +0 -0
  86. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/onnx_inferer.py +0 -0
  87. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/test_cross_format_export.py +0 -0
  88. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/test_hailo.py +0 -0
  89. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/test_rvc2.py +0 -0
  90. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/test_rvc3.py +0 -0
  91. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_packages/test_rvc4.py +0 -0
  92. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/__init__.py +0 -0
  93. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/conftest.py +0 -0
  94. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_config.py +0 -0
  95. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_filesystem.py +0 -0
  96. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_image.py +0 -0
  97. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_layout.py +0 -0
  98. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_modifier.py +0 -0
  99. {modelconv-0.5.3 → modelconv-0.5.4}/tests/test_utils/test_onnx_compatibility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelconv
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Converter for neural models into various formats.
5
5
  Author-email: Luxonis <support@luxonis.com>
6
6
  Maintainer-email: Luxonis <support@luxonis.com>
@@ -33,6 +33,7 @@ Requires-Dist: depthai~=3.0; extra == "bench"
33
33
  Provides-Extra: analysis
34
34
  Requires-Dist: polars; extra == "analysis"
35
35
  Requires-Dist: plotly; extra == "analysis"
36
+ Requires-Dist: depthai~=3.0; extra == "analysis"
36
37
  Provides-Extra: dev
37
38
  Requires-Dist: pre-commit==3.2.1; extra == "dev"
38
39
  Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelconv
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Converter for neural models into various formats.
5
5
  Author-email: Luxonis <support@luxonis.com>
6
6
  Maintainer-email: Luxonis <support@luxonis.com>
@@ -33,6 +33,7 @@ Requires-Dist: depthai~=3.0; extra == "bench"
33
33
  Provides-Extra: analysis
34
34
  Requires-Dist: polars; extra == "analysis"
35
35
  Requires-Dist: plotly; extra == "analysis"
36
+ Requires-Dist: depthai~=3.0; extra == "analysis"
36
37
  Provides-Extra: dev
37
38
  Requires-Dist: pre-commit==3.2.1; extra == "dev"
38
39
  Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
@@ -45,11 +45,11 @@ modelconverter/packages/rvc4/inferer.py
45
45
  modelconverter/packages/rvc4/requirements.txt
46
46
  modelconverter/packages/rvc4/visualize.py
47
47
  modelconverter/utils/__init__.py
48
- modelconverter/utils/adb_handler.py
49
- modelconverter/utils/adb_monitor.py
50
48
  modelconverter/utils/calibration_data.py
51
49
  modelconverter/utils/config.py
52
50
  modelconverter/utils/constants.py
51
+ modelconverter/utils/device_handlers.py
52
+ modelconverter/utils/device_monitors.py
53
53
  modelconverter/utils/docker_utils.py
54
54
  modelconverter/utils/environ.py
55
55
  modelconverter/utils/exceptions.py
@@ -14,6 +14,7 @@ psutil
14
14
  [analysis]
15
15
  polars
16
16
  plotly
17
+ depthai~=3.0
17
18
 
18
19
  [bench]
19
20
  depthai~=3.0
@@ -4,7 +4,7 @@ from typing import Final
4
4
  from luxonis_ml.utils import PUT_FILE_REGISTRY
5
5
  from pydantic_extra_types.semantic_version import SemanticVersion
6
6
 
7
- __version__: Final[str] = "0.5.3"
7
+ __version__: Final[str] = "0.5.4"
8
8
  __semver__: Final[SemanticVersion] = SemanticVersion.parse(__version__)
9
9
 
10
10
 
@@ -5,6 +5,7 @@ from importlib.metadata import version
5
5
  from pathlib import Path
6
6
  from typing import Any
7
7
 
8
+ import cv2
8
9
  import numpy as np
9
10
  from loguru import logger
10
11
 
@@ -225,7 +226,24 @@ class Exporter(ABC):
225
226
  arr = np.clip(arr, calib.min_value, calib.max_value)
226
227
 
227
228
  arr = arr.astype(calib.data_type.as_numpy_dtype())
228
- np.save(dest / f"{i}.npy", arr)
229
+ if len(arr.shape) in {2, 3} or (
230
+ len(arr.shape) in {3, 4} and arr.shape[0] == 1
231
+ ):
232
+ layout = inp.layout
233
+ if arr.shape[0] == 1 and len(arr.shape) > 2:
234
+ arr = arr.squeeze(0)
235
+ if layout is not None:
236
+ layout = layout[1:]
237
+
238
+ if layout is not None and "C" in layout:
239
+ channel_dim = layout.index("C")
240
+ if channel_dim == 0 and len(arr.shape) == 3:
241
+ arr = arr.transpose(1, 2, 0)
242
+ elif arr.shape[0] in {1, 3}: # type: ignore
243
+ arr = arr.transpose(1, 2, 0)
244
+ cv2.imwrite(str(dest / f"{i}.png"), arr)
245
+ else:
246
+ np.save(dest / f"{i}.npy", arr)
229
247
 
230
248
  self.inputs[name].calibration = ImageCalibrationConfig(path=dest)
231
249
 
@@ -31,6 +31,7 @@ class RVC3Exporter(RVC2Exporter):
31
31
  self.mo_args = config.rvc3.mo_args
32
32
  self.compile_tool_args = config.rvc3.compile_tool_args
33
33
  self.device = "VPUX.3400"
34
+ self.reverse_input_channels = False
34
35
  self._device_specific_buildinfo = {}
35
36
 
36
37
  def export(self) -> Path:
@@ -14,7 +14,7 @@ from PIL import Image
14
14
 
15
15
  from modelconverter.packages.base_analyze import Analyzer
16
16
  from modelconverter.packages.rvc4.benchmark import get_device_info
17
- from modelconverter.utils import AdbHandler, constants, subprocess_run
17
+ from modelconverter.utils import constants, create_handler, subprocess_run
18
18
 
19
19
 
20
20
  class RVC4Analyzer(Analyzer):
@@ -27,7 +27,7 @@ class RVC4Analyzer(Analyzer):
27
27
  ):
28
28
  super().__init__(dlc_model_path, image_dirs)
29
29
  _, device_adb_id = get_device_info(device_ip, device_id)
30
- self.adb = AdbHandler(device_adb_id)
30
+ self.handler = create_handler(device_ip, device_adb_id)
31
31
 
32
32
  def analyze_layer_outputs(self, onnx_model_path: Path) -> None:
33
33
  input_matcher = self._prepare_input_matcher()
@@ -76,8 +76,8 @@ class RVC4Analyzer(Analyzer):
76
76
  self, input_matcher: dict[str, dict[str, str]], type: type = np.uint8
77
77
  ) -> dict[str, str]:
78
78
  logger.info("Preparing raw inputs for RVC4 analysis.")
79
- self.adb.shell(f"rm -rf /data/modelconverter/{self.model_name}")
80
- self.adb.shell(
79
+ self.handler.shell(f"rm -rf /data/modelconverter/{self.model_name}")
80
+ self.handler.shell(
81
81
  f"mkdir -p /data/modelconverter/{self.model_name}/inputs"
82
82
  )
83
83
 
@@ -109,7 +109,7 @@ class RVC4Analyzer(Analyzer):
109
109
 
110
110
  with tempfile.NamedTemporaryFile() as f:
111
111
  raw_image.tofile(f)
112
- self.adb.push(
112
+ self.handler.push(
113
113
  f.name,
114
114
  f"/data/modelconverter/{self.model_name}/inputs/{input_name}_{img_name}.raw",
115
115
  )
@@ -122,7 +122,7 @@ class RVC4Analyzer(Analyzer):
122
122
  with tempfile.NamedTemporaryFile() as f:
123
123
  f.write(input_list.encode())
124
124
  f.flush()
125
- self.adb.push(
125
+ self.handler.push(
126
126
  f.name,
127
127
  f"/data/modelconverter/{self.model_name}/input_list.txt",
128
128
  )
@@ -133,8 +133,12 @@ class RVC4Analyzer(Analyzer):
133
133
  return dlc_matcher
134
134
 
135
135
  def _add_outputs_to_all_layers(self, onnx_file_path: str) -> Path:
136
- if Path(onnx_file_path.replace(".onnx", "-all-layers.onnx")).exists():
137
- Path(onnx_file_path.replace(".onnx", "-all-layers.onnx")).unlink()
136
+ onnx_path = Path(onnx_file_path)
137
+ all_output_path = onnx_path.with_name(
138
+ f"{onnx_path.stem}-all-layers{onnx_path.suffix}"
139
+ )
140
+ if all_output_path.exists():
141
+ all_output_path.unlink()
138
142
 
139
143
  model = onnx.load(onnx_file_path)
140
144
  onnx.checker.check_model(model)
@@ -152,10 +156,10 @@ class RVC4Analyzer(Analyzer):
152
156
 
153
157
  for output in orig_graph_output:
154
158
  graph.output.append(output)
155
- all_output_name = onnx_file_path.replace(".onnx", "-all-layers.onnx")
156
- onnx.save(model, all_output_name)
159
+ all_output_path.parent.mkdir(parents=True, exist_ok=True)
160
+ onnx.save(model, all_output_path)
157
161
 
158
- return Path(all_output_name)
162
+ return all_output_path
159
163
 
160
164
  def transpose_to_match(
161
165
  self, src: np.ndarray, target_shape: tuple[int, ...]
@@ -321,14 +325,14 @@ class RVC4Analyzer(Analyzer):
321
325
  def _run_dlc(self, command: str) -> str:
322
326
  logger.info("Inferencing DLC model on device.")
323
327
  try:
324
- self.adb.push(
328
+ self.handler.push(
325
329
  str(self.dlc_model_path),
326
330
  f"/data/modelconverter/{self.model_name}/{self.model_name}.dlc",
327
331
  )
328
- self.adb.shell(
332
+ self.handler.shell(
329
333
  f"rm -rf /data/modelconverter/{self.model_name}/output"
330
334
  )
331
- self.adb.shell(
335
+ self.handler.shell(
332
336
  f"cd /data/modelconverter/{self.model_name} && {command}"
333
337
  )
334
338
 
@@ -337,7 +341,7 @@ class RVC4Analyzer(Analyzer):
337
341
  shutil.rmtree(target_dir / "output")
338
342
 
339
343
  target_dir.mkdir(parents=True, exist_ok=True)
340
- self.adb.pull(
344
+ self.handler.pull(
341
345
  f"/data/modelconverter/{self.model_name}/output",
342
346
  f"{target_dir}/output",
343
347
  )
@@ -397,7 +401,7 @@ class RVC4Analyzer(Analyzer):
397
401
 
398
402
  logger.info("Running DLC model to analyze layer cycles.")
399
403
  output_dir = self._run_dlc(
400
- f"snpe-net-run --container {self.model_name}.dlc --input_list input_list.txt --use_dsp --use_native_input_files --use_native_output_files --perf_profile balanced --userbuffer_tf8"
404
+ f"snpe-net-run --container {self.model_name}.dlc --input_list input_list.txt --use_dsp --use_native_input_files --use_native_output_files --perf_profile balanced --userbuffer_auto"
401
405
  )
402
406
 
403
407
  csv_path = Path(output_dir + "/layer_stats.csv")
@@ -456,7 +460,7 @@ class RVC4Analyzer(Analyzer):
456
460
 
457
461
  # cleanup
458
462
  def _cleanup_dlc_outputs(self) -> None:
459
- self.adb.shell(f"rm -rf /data/modelconverter/{self.model_name}")
463
+ self.handler.shell(f"rm -rf /data/modelconverter/{self.model_name}")
460
464
 
461
465
  output_dir = Path(
462
466
  f"{constants.OUTPUTS_DIR!s}/analysis/{self.model_name}/output"
@@ -4,9 +4,9 @@ import re
4
4
  import shutil
5
5
  import tempfile
6
6
  from collections.abc import Iterable
7
- from contextlib import suppress
7
+ from dataclasses import dataclass
8
8
  from pathlib import Path
9
- from typing import Final, cast
9
+ from typing import Final
10
10
 
11
11
  import depthai as dai
12
12
  import numpy as np
@@ -19,9 +19,9 @@ from modelconverter.packages.base_benchmark import (
19
19
  Configuration,
20
20
  )
21
21
  from modelconverter.utils import (
22
- AdbHandler,
23
- AdbMonitorDSP,
24
- AdbMonitorPower,
22
+ MonitorDSP,
23
+ MonitorPower,
24
+ create_handler,
25
25
  create_progress_handler,
26
26
  environ,
27
27
  subprocess_run,
@@ -45,6 +45,26 @@ RUNTIMES: dict[str, str] = {
45
45
  "cpu": "use_cpu",
46
46
  }
47
47
 
48
+ DLC_TO_DAI_DATA_TYPE: Final[dict[str, dai.TensorInfo.DataType]] = {
49
+ "Float_32": dai.TensorInfo.DataType.FP32,
50
+ "Float_16": dai.TensorInfo.DataType.FP16,
51
+ "Float_64": dai.TensorInfo.DataType.FP64,
52
+ "Int_8": dai.TensorInfo.DataType.I8,
53
+ "Int_32": dai.TensorInfo.DataType.INT,
54
+ # DAI does not currently expose a 16-bit fixed-point/int tensor type.
55
+ # Until it does, keep uFxp_16 on the closest supported 16-bit path.
56
+ "uFxp_16": dai.TensorInfo.DataType.FP16,
57
+ "uFxp_8": dai.TensorInfo.DataType.U8F,
58
+ }
59
+
60
+
61
+ @dataclass(frozen=True)
62
+ class InputSpec:
63
+ name: str
64
+ shape: list[int]
65
+ dlc_dtype: str
66
+ dai_dtype: dai.TensorInfo.DataType
67
+
48
68
 
49
69
  class RVC4Benchmark(Benchmark):
50
70
  @property
@@ -80,15 +100,29 @@ class RVC4Benchmark(Benchmark):
80
100
  for threads in [1, 2]
81
101
  ]
82
102
 
83
- def _get_input_sizes(
103
+ def _get_dlc_input_specs(
84
104
  self, model_path: str | Path | None = None
85
- ) -> tuple[dict[str, list[int]], dict[str, str]]:
105
+ ) -> list[InputSpec]:
106
+ """Retrieve normalized input specs from a DLC or NNArchive."""
107
+ model_path = self.model_path if model_path is None else model_path
108
+
109
+ if str(model_path).endswith(".tar.xz"):
110
+ with tempfile.TemporaryDirectory() as tmp_dir:
111
+ shutil.unpack_archive(model_path, tmp_dir)
112
+ dlc_files = list(Path(tmp_dir).rglob("*.dlc"))
113
+ if not dlc_files:
114
+ raise ValueError("No .dlc file found in the archive.")
115
+ return self._get_dlc_input_specs(dlc_files[0])
116
+
117
+ if not str(model_path).endswith(".dlc"):
118
+ raise ValueError("Expected .dlc, or .tar.xz model format.")
119
+
86
120
  csv_path = Path("info.csv")
87
121
  subprocess_run(
88
122
  [
89
123
  "snpe-dlc-info",
90
124
  "-i",
91
- self.model_path if model_path is None else model_path,
125
+ model_path,
92
126
  "-s",
93
127
  csv_path,
94
128
  ],
@@ -110,146 +144,70 @@ class RVC4Benchmark(Benchmark):
110
144
  )
111
145
 
112
146
  rows = df.rows(named=True)
113
- sizes = {row["Input Name"]: row["Dimensions"] for row in rows}
114
- data_types = {row["Input Name"]: row["Type"] for row in rows}
147
+ data_types = [str(row["Type"]) for row in rows]
148
+ unsupported_types = sorted(set(data_types) - set(DLC_TO_DAI_DATA_TYPE))
149
+ if unsupported_types:
150
+ raise ValueError(
151
+ f"Unsupported data types {unsupported_types}. Expected one of: {sorted(DLC_TO_DAI_DATA_TYPE)}."
152
+ )
115
153
 
116
- return sizes, data_types
154
+ return [
155
+ InputSpec(
156
+ name=str(row["Input Name"]),
157
+ shape=list(row["Dimensions"]),
158
+ dlc_dtype=str(row["Type"]),
159
+ dai_dtype=DLC_TO_DAI_DATA_TYPE[str(row["Type"])],
160
+ )
161
+ for row in rows
162
+ ]
117
163
 
118
- def _prepare_raw_inputs(self, num_images: int) -> None:
119
- input_sizes, data_types = self._get_input_sizes()
164
+ def _prepare_raw_inputs(
165
+ self, input_specs: list[InputSpec], num_images: int
166
+ ) -> None:
120
167
  input_list = ""
121
- self.adb.shell(
168
+ self.handler.shell(
122
169
  f"mkdir -p /data/modelconverter/{self.model_name}/inputs"
123
170
  )
124
171
  for i in range(num_images):
125
- for name, size in input_sizes.items():
126
- if data_types[name] == "Float_32":
127
- numpy_type = np.float32
128
- elif data_types[name] in ["uFxp_16", "Float_16"]:
129
- numpy_type = np.float16
130
- elif data_types[name] == "uFxp_8":
131
- numpy_type = np.uint8
132
- else:
133
- raise ValueError(
134
- f"Unsupported data type {data_types[name]} for input {name}."
135
- )
136
- img = cast(np.ndarray, np.random.rand(*size)).astype(
137
- numpy_type
138
- )
172
+ for spec in input_specs:
173
+ input_data = self._create_random_input(spec)
139
174
  with tempfile.NamedTemporaryFile() as f:
140
- img.tofile(f)
141
- self.adb.push(
175
+ input_data.tofile(f)
176
+ self.handler.push(
142
177
  f.name,
143
- f"/data/modelconverter/{self.model_name}/inputs/{name}_{i}.raw",
178
+ f"/data/modelconverter/{self.model_name}/inputs/{spec.name}_{i}.raw",
144
179
  )
145
180
 
146
- input_list += f"{name}:=/data/modelconverter/{self.model_name}/inputs/{name}_{i}.raw "
181
+ input_list += f"{spec.name}:=/data/modelconverter/{self.model_name}/inputs/{spec.name}_{i}.raw "
147
182
  input_list += "\n"
148
183
 
149
184
  with tempfile.NamedTemporaryFile() as f:
150
185
  f.write(input_list.encode())
151
- self.adb.push(
186
+ self.handler.push(
152
187
  f.name,
153
188
  f"/data/modelconverter/{self.model_name}/input_list.txt",
154
189
  )
155
190
 
156
- def _get_data_type_from_dlc(self) -> dai.TensorInfo.DataType:
157
- """Retrieve the data type of the dlc model info.
158
-
159
- If the model is in NNArchive format, decompress it and then
160
- retrieve the data type.
161
- """
162
-
163
- if str(self.model_path).endswith(".dlc"):
164
- _, data_types = self._get_input_sizes()
165
- elif str(self.model_path).endswith(".tar.xz"):
166
- with tempfile.TemporaryDirectory() as tmp_dir:
167
- shutil.unpack_archive(self.model_path, tmp_dir)
168
-
169
- dlc_files = list(Path(tmp_dir).rglob("*.dlc"))
170
- if not dlc_files:
171
- raise ValueError("No .dlc file found in the archive.")
172
- dlc_path = dlc_files[0]
173
-
174
- _, data_types = self._get_input_sizes(dlc_path)
175
- else:
176
- raise ValueError("Expected .dlc, or .tar.xz model format.")
177
-
178
- model_input = next(iter(data_types.values()))
179
- if model_input == "Float_32":
180
- return dai.TensorInfo.DataType.FP32
181
- if model_input in ["uFxp_16", "Float_16"]:
182
- return dai.TensorInfo.DataType.FP16
183
- if model_input == "uFxp_8":
184
- return dai.TensorInfo.DataType.U8F
185
- raise ValueError(
186
- f"Unsupported data type {model_input}. Expected Float_32, Float_16, or uFxp_8."
187
- )
188
-
189
- def _get_data_type(self) -> dai.TensorInfo.DataType:
190
- """Retrieve the data type of the model inputs. If the model is
191
- not a HubAI model, it defaults to dai.TensorInfo.DataType.U8F
192
- (INT8).
193
-
194
- @return: The data type of the model inputs.
195
- @rtype: dai.TensorInfo.DataType
196
- """
197
- from modelconverter.cli import Request, slug_to_id
198
-
199
- if not isinstance(
200
- self.model_path, str
201
- ) or not self.HUB_MODEL_PATTERN.match(self.model_path):
202
- return self._get_data_type_from_dlc()
203
-
204
- model_id = slug_to_id(self.model_name, "models")
205
- model_variant = self.model_path.split(":")[1]
206
-
207
- model_variants = []
208
- for is_public in [True, False]:
209
- with suppress(Exception):
210
- model_variants += Request.get(
211
- "modelVersions/",
212
- params={"model_id": model_id, "is_public": is_public},
213
- )
214
-
215
- model_version_id = None
216
- for version in model_variants:
217
- if version["variant_slug"] == model_variant:
218
- model_version_id = version["id"]
219
- break
220
-
221
- if not model_version_id:
222
- return dai.TensorInfo.DataType.U8F
223
-
224
- model_instances = []
225
- for is_public in [True, False]:
226
- with suppress(Exception):
227
- model_instances += Request.get(
228
- "modelInstances/",
229
- params={
230
- "model_id": model_id,
231
- "model_version_id": model_version_id,
232
- "is_public": is_public,
233
- },
234
- )
235
-
236
- model_precision_type = "INT8"
237
- for instance in model_instances:
238
- if instance["platforms"] == ["RVC4"] and (
239
- self.model_instance is None
240
- or instance["hash_short"] == self.model_instance
241
- ):
242
- model_precision_type = instance.get(
243
- "model_precision_type", "INT8"
244
- )
245
- break
246
-
247
- if model_precision_type == "FP16":
248
- return dai.TensorInfo.DataType.FP16
249
- if model_precision_type == "FP32":
250
- return dai.TensorInfo.DataType.FP32
251
-
252
- return dai.TensorInfo.DataType.U8F
191
+ @staticmethod
192
+ def _create_random_input(
193
+ spec: InputSpec,
194
+ ) -> np.ndarray:
195
+ if spec.dai_dtype == dai.TensorInfo.DataType.FP32:
196
+ return np.random.rand(*spec.shape).astype(np.float32)
197
+ if spec.dai_dtype == dai.TensorInfo.DataType.FP16:
198
+ return np.random.rand(*spec.shape).astype(np.float16)
199
+ if spec.dai_dtype == dai.TensorInfo.DataType.FP64:
200
+ return np.random.rand(*spec.shape).astype(np.float64)
201
+ if spec.dai_dtype == dai.TensorInfo.DataType.I8:
202
+ return np.random.randint(-128, 128, size=spec.shape, dtype=np.int8)
203
+ if spec.dai_dtype == dai.TensorInfo.DataType.INT:
204
+ # INT inputs are often token/index tensors; zero keeps synthetic
205
+ # benchmark inputs in a safe range.
206
+ return np.zeros(spec.shape, dtype=np.int32)
207
+ if spec.dai_dtype == dai.TensorInfo.DataType.U8F:
208
+ return np.random.randint(0, 256, size=spec.shape, dtype=np.uint8)
209
+
210
+ raise ValueError(f"Unsupported DAI data type {spec.dai_dtype}.")
253
211
 
254
212
  def benchmark(self, configuration: Configuration) -> BenchmarkResult:
255
213
  dai_benchmark = configuration.get("dai_benchmark")
@@ -260,18 +218,18 @@ class RVC4Benchmark(Benchmark):
260
218
  configuration.get("device_ip"), configuration.get("device_id")
261
219
  )
262
220
  if power_benchmark or dsp_benchmark or not dai_benchmark:
263
- self.adb = AdbHandler(device_adb_id)
221
+ self.handler = create_handler(device_ip, device_adb_id)
264
222
 
265
223
  configuration["device_ip"] = device_ip
266
224
 
267
225
  self.power_monitor = None
268
226
  if power_benchmark:
269
- self.power_monitor = AdbMonitorPower(self.adb)
227
+ self.power_monitor = MonitorPower(self.handler)
270
228
  self.power_monitor.start()
271
229
 
272
230
  self.dsp_monitor = None
273
231
  if dsp_benchmark:
274
- self.dsp_monitor = AdbMonitorDSP(self.adb)
232
+ self.dsp_monitor = MonitorDSP(self.handler)
275
233
  self.dsp_monitor.start()
276
234
 
277
235
  try:
@@ -315,7 +273,7 @@ class RVC4Benchmark(Benchmark):
315
273
  # so we don't delete the wrong directory
316
274
  assert self.model_name
317
275
 
318
- self.adb.shell(
276
+ self.handler.shell(
319
277
  f"rm -rf /data/modelconverter/{self.model_name}"
320
278
  )
321
279
 
@@ -345,7 +303,6 @@ class RVC4Benchmark(Benchmark):
345
303
  dlc_path = next(tmp_dir.rglob(dlc_model_name), None)
346
304
  if not dlc_path:
347
305
  raise ValueError("Could not find model.dlc in the archive.")
348
- self.model_path = dlc_path
349
306
  elif str(model_path).endswith(".dlc"):
350
307
  dlc_path = model_path
351
308
  else:
@@ -353,13 +310,14 @@ class RVC4Benchmark(Benchmark):
353
310
  "Unsupported model format. Supported formats: .dlc, or HubAI model slug."
354
311
  )
355
312
 
356
- self.adb.shell(f"mkdir -p /data/modelconverter/{self.model_name}")
357
- self.adb.push(
313
+ input_specs = self._get_dlc_input_specs(dlc_path)
314
+ self.handler.shell(f"mkdir -p /data/modelconverter/{self.model_name}")
315
+ self.handler.push(
358
316
  str(dlc_path), f"/data/modelconverter/{self.model_name}/model.dlc"
359
317
  )
360
- self._prepare_raw_inputs(num_images)
318
+ self._prepare_raw_inputs(input_specs, num_images)
361
319
 
362
- _, stdout, _ = self.adb.shell(
320
+ _, stdout, _ = self.handler.shell(
363
321
  # "source /data/modelconverter/source_me.sh && "
364
322
  "snpe-parallel-run "
365
323
  f"--container /data/modelconverter/{self.model_name}/model.dlc "
@@ -408,15 +366,17 @@ class RVC4Benchmark(Benchmark):
408
366
  )
409
367
 
410
368
  if isinstance(model_path, str):
411
- modelPath = dai.getModelFromZoo(
412
- dai.NNModelDescription(
413
- model_path,
414
- platform=device.getPlatformAsString(),
415
- ),
416
- apiKey=environ.HUBAI_API_KEY or "",
369
+ modelPath = Path(
370
+ dai.getModelFromZoo(
371
+ dai.NNModelDescription(
372
+ model_path,
373
+ platform=device.getPlatformAsString(),
374
+ ),
375
+ apiKey=environ.HUBAI_API_KEY or "",
376
+ )
417
377
  )
418
378
  elif str(model_path).endswith(".tar.xz"):
419
- modelPath = str(model_path)
379
+ modelPath = Path(model_path)
420
380
  elif str(model_path).endswith(".dlc"):
421
381
  raise ValueError(
422
382
  "DLC model format is not currently supported for dai-benchmark. Please use SNPE for DLC models."
@@ -426,19 +386,15 @@ class RVC4Benchmark(Benchmark):
426
386
  "Unsupported model format. Supported formats: .tar.xz, or HubAI model slug."
427
387
  )
428
388
 
429
- inputSizes = []
430
- inputNames = []
389
+ input_specs: list[InputSpec] = []
431
390
  if isinstance(model_path, str) or str(model_path).endswith(".tar.xz"):
432
- modelArhive = dai.NNArchive(modelPath) # type: ignore[arg-type]
433
- for input in modelArhive.getConfig().model.inputs:
434
- inputSizes.append(input.shape)
435
- inputNames.append(input.name)
391
+ model_archive = dai.NNArchive(modelPath) # type: ignore[arg-type]
392
+ input_specs = self._get_dlc_input_specs(modelPath)
436
393
 
437
- data_type = self._get_data_type()
438
394
  inputData = dai.NNData()
439
- for name, inputSize in zip(inputNames, inputSizes, strict=True):
440
- img = np.random.randint(0, 255, inputSize, np.uint8)
441
- inputData.addTensor(name, img, dataType=data_type)
395
+ for spec in input_specs:
396
+ input_data = self._create_random_input(spec)
397
+ inputData.addTensor(spec.name, input_data, dataType=spec.dai_dtype)
442
398
 
443
399
  with dai.Pipeline(device) as pipeline:
444
400
  benchmarkOut = pipeline.create(dai.node.BenchmarkOut)
@@ -449,7 +405,7 @@ class RVC4Benchmark(Benchmark):
449
405
  if isinstance(model_path, str) or str(model_path).endswith(
450
406
  ".tar.xz"
451
407
  ):
452
- neuralNetwork.setNNArchive(modelArhive)
408
+ neuralNetwork.setNNArchive(model_archive)
453
409
 
454
410
  neuralNetwork.setBackendProperties(
455
411
  {
@@ -187,6 +187,7 @@ class RVC4Exporter(Exporter):
187
187
  args.append("--override_params")
188
188
  elif self.quantization_mode == QuantizationMode.INT8_16_MIX:
189
189
  self._add_args(args, ["--act_bitwidth", "16"])
190
+ args.append("--override_params")
190
191
  elif self.encodings is not None:
191
192
  args.append("--override_params")
192
193
 
@@ -1,6 +1,11 @@
1
- from .adb_handler import AdbHandler
2
- from .adb_monitor import AdbMonitorDSP, AdbMonitorPower
3
1
  from .calibration_data import download_calibration_data
2
+ from .device_handlers import (
3
+ AdbHandler,
4
+ DeviceHandler,
5
+ SSHHandler,
6
+ create_handler,
7
+ )
8
+ from .device_monitors import MonitorDSP, MonitorPower
4
9
  from .docker_utils import (
5
10
  check_docker,
6
11
  docker_build,
@@ -46,16 +51,19 @@ from .subprocess import SubprocessHandle, subprocess_run
46
51
 
47
52
  __all__ = [
48
53
  "AdbHandler",
49
- "AdbMonitorDSP",
50
- "AdbMonitorPower",
54
+ "DeviceHandler",
51
55
  "Metadata",
52
56
  "ModelconverterException",
57
+ "MonitorDSP",
58
+ "MonitorPower",
53
59
  "ONNXModifier",
54
60
  "S3Exception",
61
+ "SSHHandler",
55
62
  "SubprocessException",
56
63
  "SubprocessHandle",
57
64
  "archive_from_model",
58
65
  "check_docker",
66
+ "create_handler",
59
67
  "create_progress_handler",
60
68
  "docker_build",
61
69
  "docker_exec",