feat: Implement ONNX model inference for BEN2, Depth Anything 3, and MoGe

- Added `ben2_onnx.py` for BEN2 ONNX inference with preprocessing.
- Introduced `da3_onnx.py` for Depth Anything 3 inference, including camera projection calculations.
- Created `moge_onnx.py` for MoGe-2 ONNX inference and post-processing.
- Implemented shared ONNX Runtime session helpers in `onnx_runtime.py`.
- Added model synchronization script `sync_models.py` for downloading and verifying ONNX models.
- Developed unit tests for BEN2, Depth Anything 3, and MoGe ONNX models to ensure functionality.
- Updated `vendor.lock.toml` to remove unused artifacts.
This commit is contained in:
2026-08-14 10:27:09 +08:00
parent 13fab9ce88
commit 2ad30bf4a3
41 changed files with 1569 additions and 2109 deletions

View File

@@ -66,57 +66,6 @@ class WorkerTest(unittest.TestCase):
self.worker.check_cancelled(lambda: False)
def test_select_device_supports_mps_and_auto_fallback(self):
mps_torch = SimpleNamespace(
cuda=SimpleNamespace(is_available=lambda: False),
backends=SimpleNamespace(
mps=SimpleNamespace(is_available=lambda: True),
),
)
mps_torch.device = lambda device_type: SimpleNamespace(
type=device_type
)
self.assertEqual(
self.worker.select_device("mps", mps_torch).type,
"mps",
)
self.assertEqual(
self.worker.select_device("auto", mps_torch).type,
"mps",
)
self.assertEqual(
self.worker.select_device("cpu", mps_torch).type,
"cpu",
)
cuda_torch = SimpleNamespace(
cuda=SimpleNamespace(is_available=lambda: True),
)
cuda_torch.device = lambda device_type: SimpleNamespace(
type=device_type
)
self.assertEqual(
self.worker.select_device("auto", cuda_torch).type,
"cuda",
)
cpu_only_torch = SimpleNamespace(
cuda=SimpleNamespace(is_available=lambda: False),
backends=SimpleNamespace(
mps=SimpleNamespace(is_available=lambda: False),
),
)
cpu_only_torch.device = lambda device_type: SimpleNamespace(
type=device_type
)
self.assertEqual(
self.worker.select_device("auto", cpu_only_torch).type,
"cpu",
)
with self.assertRaisesRegex(RuntimeError, "MPS was requested"):
self.worker.select_device("mps", cpu_only_torch)
def test_reconstruct_parser_accepts_background_model_directory(self):
args = self.worker.parser().parse_args(
[
@@ -436,12 +385,6 @@ class WorkerTest(unittest.TestCase):
with self.assertRaisesRegex(RuntimeError, "Unsupported input type"):
self.worker.prepare_input(input_path, 16, directory)
def test_moge_runtime_disables_unsupported_xformers_attention(self):
with patch.dict(os.environ, {}, clear=True):
self.worker.prepare_moge_runtime()
self.assertEqual(os.environ["XFORMERS_DISABLED"], "1")
def test_download_model_uses_actual_request_without_preflight(self):
calls = []
fake_hugging_face = ModuleType("huggingface_hub")
@@ -605,8 +548,11 @@ class WorkerTest(unittest.TestCase):
)
fake_torch.device = lambda device_type: SimpleNamespace(type=device_type)
fake_torch.inference_mode = nullcontext
fake_ben2 = ModuleType("ben2")
fake_ben2.BEN_Base = FakeModel
fake_ben2 = ModuleType("ben2_onnx")
fake_ben2.create_session = lambda _model_dir, _device: object()
fake_ben2.infer = lambda _model, image: (
inference_options.append((image, {})) or FakeImage()
)
fake_pil = ModuleType("PIL")
fake_pil.Image = SimpleNamespace(open=lambda _path: FakeImage())
@@ -614,7 +560,7 @@ class WorkerTest(unittest.TestCase):
sys.modules,
{
"torch": fake_torch,
"ben2": fake_ben2,
"ben2_onnx": fake_ben2,
"PIL": fake_pil,
},
):
@@ -635,7 +581,7 @@ class WorkerTest(unittest.TestCase):
self.assertEqual(
inference_options[0][1],
{"refine_foreground": False},
{},
)
self.assertEqual(
save_options[0],
@@ -690,8 +636,11 @@ class WorkerTest(unittest.TestCase):
)
fake_torch.device = lambda device_type: SimpleNamespace(type=device_type)
fake_torch.inference_mode = nullcontext
fake_ben2 = ModuleType("ben2")
fake_ben2.BEN_Base = FakeModel
fake_ben2 = ModuleType("ben2_onnx")
fake_ben2.create_session = lambda _model_dir, _device: object()
fake_ben2.infer = lambda _model, image: (
inference_options.append((image, {})) or FakeImage()
)
fake_pil = ModuleType("PIL")
fake_pil.Image = SimpleNamespace(open=lambda _path: FakeImage())
@@ -699,7 +648,7 @@ class WorkerTest(unittest.TestCase):
sys.modules,
{
"torch": fake_torch,
"ben2": fake_ben2,
"ben2_onnx": fake_ben2,
"PIL": fake_pil,
},
):
@@ -734,7 +683,7 @@ class WorkerTest(unittest.TestCase):
self.assertEqual(len(inference_options), 2)
for _image, options in inference_options:
self.assertEqual(options, {"refine_foreground": False})
self.assertEqual(options, {})
def test_remove_background_parser_accepts_video_frames(self):
args = self.worker.parser().parse_args(
@@ -813,64 +762,25 @@ class WorkerTest(unittest.TestCase):
def test_uses_da3_export_parameters_for_formats_and_debug_mesh(self):
inference_options = []
export_calls = []
mesh_calls = []
class FakeModel:
@classmethod
def from_pretrained(cls, model_dir):
if model_dir != "model":
raise AssertionError(f"Unexpected model directory: {model_dir}")
return cls()
def to(self, device):
if device.type != "cpu":
raise AssertionError(f"Unexpected device: {device.type}")
return self
def eval(self):
return None
def inference(self, images, **options):
inference_options.append((images, options))
return SimpleNamespace(
depth=np.full((1, 2, 2), 2.0, dtype=np.float32),
)
def fake_export(prediction, export_format, export_dir, **options):
export_calls.append((prediction, export_format, export_dir, options))
output_directory = Path(export_dir)
if export_format == "glb":
(output_directory / "scene.glb").touch()
elif export_format == "gs_ply":
ply_directory = output_directory / "gs_ply"
ply_directory.mkdir()
(ply_directory / "0000.ply").touch()
elif export_format == "depth_vis":
depth_directory = output_directory / "depth_vis"
depth_directory.mkdir()
(depth_directory / "0000.jpg").touch()
else:
mini_directory = output_directory / "exports" / "mini_npz"
mini_directory.mkdir(parents=True)
np.savez_compressed(
mini_directory / "results.npz",
depth=np.zeros((14, 14)),
)
fake_torch = ModuleType("torch")
fake_torch.device = lambda device_type: SimpleNamespace(
type=device_type,
prediction = SimpleNamespace(
depth=np.full((1, 2, 2), 2.0, dtype=np.float32),
conf=np.ones((1, 2, 2), dtype=np.float32),
extrinsics=np.eye(4, dtype=np.float32)[None, :3],
intrinsics=np.eye(3, dtype=np.float32)[None],
processed_images=np.zeros((1, 2, 2, 3), dtype=np.uint8),
)
fake_torch.inference_mode = nullcontext
fake_api = ModuleType("depth_anything_3.api")
fake_api.DepthAnything3 = FakeModel
fake_export_module = ModuleType("depth_anything_3.utils.export")
fake_export_module.export = fake_export
fake_utils = ModuleType("depth_anything_3.utils")
fake_utils.__path__ = []
fake_package = ModuleType("depth_anything_3")
fake_package.__path__ = []
fake_da3 = ModuleType("da3_onnx")
fake_da3.create_session = lambda _model_dir, _device: object()
def fake_infer(_session, images, **options):
inference_options.append((images, options))
return prediction
fake_da3.infer = fake_infer
fake_runtime = ModuleType("onnx_runtime")
fake_runtime.provider_label = lambda _session: "CPU"
def fake_mesh_export(
prediction,
@@ -893,6 +803,20 @@ class WorkerTest(unittest.TestCase):
output_path.touch()
return output_path
def fake_point_cloud(_prediction, output_directory, *_args):
(Path(output_directory) / "scene.glb").touch()
def fake_depth_preview(_prediction, output_directory):
target = Path(output_directory) / "depth_vis"
target.mkdir()
(target / "0000.jpg").touch()
def fake_mini_npz(_prediction, output_directory):
np.savez_compressed(
Path(output_directory) / "results.npz",
depth=np.zeros((1, 2, 2)),
)
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
input_path = root / "input.png"
@@ -900,20 +824,28 @@ class WorkerTest(unittest.TestCase):
with patch.dict(
sys.modules,
{
"torch": fake_torch,
"depth_anything_3": fake_package,
"depth_anything_3.api": fake_api,
"depth_anything_3.utils": fake_utils,
"depth_anything_3.utils.export": fake_export_module,
"da3_onnx": fake_da3,
"onnx_runtime": fake_runtime,
},
), patch.object(
self.worker,
"export_textured_mesh_glb",
side_effect=fake_mesh_export,
), patch.object(
self.worker,
"export_da3_point_cloud",
side_effect=fake_point_cloud,
), patch.object(
self.worker,
"export_da3_depth_preview",
side_effect=fake_depth_preview,
), patch.object(
self.worker,
"export_da3_mini_npz",
side_effect=fake_mini_npz,
):
debug_formats = (
"glb",
"gs_ply",
"depth_vis",
"mini_npz",
"mesh",
@@ -945,15 +877,11 @@ class WorkerTest(unittest.TestCase):
self.assertEqual(status["progress"], 1.0)
self.assertIn(export_format, status["message"])
result_directory = Path(args.output_dir)
if export_format == "gs_ply":
self.assertTrue((result_directory / "0000.ply").is_file())
self.assertFalse((result_directory / "gs_ply").exists())
if export_format == "depth_vis":
self.assertTrue((result_directory / "0000.jpg").is_file())
self.assertFalse((result_directory / "depth_vis").exists())
self.assertEqual(len(inference_options), 5)
self.assertEqual(len(export_calls), 4)
self.assertEqual(len(inference_options), 4)
self.assertEqual(len(mesh_calls), 1)
for images, options in inference_options:
self.assertEqual(images, [str(input_path)])
@@ -964,82 +892,21 @@ class WorkerTest(unittest.TestCase):
)
self.assertTrue(options["use_ray_pose"])
self.assertEqual(options["ref_view_strategy"], "middle")
for (
_prediction,
export_format,
_export_dir,
options,
) in export_calls:
np.testing.assert_array_equal(
_prediction.depth,
np.full((1, 2, 2), 2.0, dtype=np.float32),
)
if export_format == "glb":
self.assertEqual(
options,
{
"glb": {
"conf_thresh_percentile": 35.0,
"num_max_points": 12345,
"show_cameras": False,
"export_depth_vis": False,
}
},
)
elif export_format == "gs_ply":
self.assertEqual(
options,
{"gs_ply": {"gs_views_interval": 2}},
)
else:
self.assertEqual(options, {})
self.assertEqual(mesh_calls[0][1], [input_path])
self.assertEqual(mesh_calls[0][2:], (35.0, True, 0.2))
infer_gs_values = [options["infer_gs"] for _, options in inference_options]
self.assertEqual(
infer_gs_values,
[False, True, False, False, False],
)
def test_reconstruct_copies_frames_for_multi_frame_input(self):
class FakeModel:
@classmethod
def from_pretrained(cls, model_dir):
return cls()
def to(self, device):
return self
def eval(self):
return None
def inference(self, images, **options):
return SimpleNamespace(
depth=np.full((2, 2, 2), 2.0, dtype=np.float32),
)
def fake_export(prediction, export_format, export_dir, **options):
mini_directory = Path(export_dir) / "exports" / "mini_npz"
mini_directory.mkdir(parents=True)
np.savez_compressed(
mini_directory / "results.npz",
depth=np.zeros((2, 14, 14)),
)
fake_torch = ModuleType("torch")
fake_torch.device = lambda device_type: SimpleNamespace(
type=device_type,
fake_da3 = ModuleType("da3_onnx")
fake_da3.create_session = lambda _model_dir, _device: object()
fake_da3.infer = lambda *_args, **_kwargs: SimpleNamespace(
depth=np.full((2, 2, 2), 2.0, dtype=np.float32),
conf=np.ones((2, 2, 2), dtype=np.float32),
extrinsics=np.repeat(np.eye(4, dtype=np.float32)[None, :3], 2, axis=0),
intrinsics=np.repeat(np.eye(3, dtype=np.float32)[None], 2, axis=0),
processed_images=np.zeros((2, 2, 2, 3), dtype=np.uint8),
)
fake_torch.inference_mode = nullcontext
fake_api = ModuleType("depth_anything_3.api")
fake_api.DepthAnything3 = FakeModel
fake_export_module = ModuleType("depth_anything_3.utils.export")
fake_export_module.export = fake_export
fake_utils = ModuleType("depth_anything_3.utils")
fake_utils.__path__ = []
fake_package = ModuleType("depth_anything_3")
fake_package.__path__ = []
fake_runtime = ModuleType("onnx_runtime")
fake_runtime.provider_label = lambda _session: "CPU"
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
@@ -1050,11 +917,8 @@ class WorkerTest(unittest.TestCase):
with patch.dict(
sys.modules,
{
"torch": fake_torch,
"depth_anything_3": fake_package,
"depth_anything_3.api": fake_api,
"depth_anything_3.utils": fake_utils,
"depth_anything_3.utils.export": fake_export_module,
"da3_onnx": fake_da3,
"onnx_runtime": fake_runtime,
},
):
args = SimpleNamespace(