Files
AnyImage/tests/ai/test_model_moge2_onnx.py
nan 198fcbf55b
Some checks failed
Test / test (push) Has been cancelled
Initial public release
2026-09-19 21:31:36 +08:00

209 lines
6.9 KiB
Python

from tests.support.paths import PROJECT_ROOT
import importlib.util
import sys
import unittest
from pathlib import Path
from types import ModuleType
from unittest.mock import patch
import numpy as np
def load_module():
anyimage = ModuleType("anyimage")
anyimage.__path__ = [str(PROJECT_ROOT / "src" / "anyimage")]
server = ModuleType("anyimage.server")
server.__path__ = [str(PROJECT_ROOT / "src" / "anyimage" / "server")]
models = ModuleType("anyimage.server.models")
models.__path__ = [
str(PROJECT_ROOT / "src" / "anyimage" / "server" / "models")
]
specification = importlib.util.spec_from_file_location(
"anyimage.server.models.onnx_moge2",
PROJECT_ROOT
/ "src"
/ "anyimage"
/ "server"
/ "models"
/ "onnx_moge2.py",
)
module = importlib.util.module_from_spec(specification)
with patch.dict(
sys.modules,
{
"anyimage": anyimage,
"anyimage.server": server,
"anyimage.server.models": models,
},
):
specification.loader.exec_module(module)
return module
class FakeInput:
def __init__(self, name):
self.name = name
class FakeSession:
def __init__(self, outputs):
self.outputs = outputs
self.calls = []
def run(self, names, inputs):
self.calls.append((names, inputs))
return [self.outputs[name] for name in names]
def get_providers(self):
return ["CPUExecutionProvider"]
def get_outputs(self):
return [FakeInput(name) for name in self.outputs]
class Moge2OnnxTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.moge = load_module()
def test_coreml_session_requires_static_input_partitions(self):
calls = []
fake_runtime = ModuleType("onnxruntime")
fake_runtime.get_available_providers = lambda: [
"CoreMLExecutionProvider",
"CPUExecutionProvider",
]
fake_runtime.InferenceSession = lambda path, providers: calls.append(
(path, providers)
)
with patch.dict(sys.modules, {"onnxruntime": fake_runtime}):
self.moge.create_session("moge-model", "coreml")
self.assertEqual(
calls[0][0],
str(Path("moge-model") / "model.onnx"),
)
self.assertEqual(
calls[0][1],
[
(
"CoreMLExecutionProvider",
{"RequireStaticInputShapes": "1"},
),
"CPUExecutionProvider",
],
)
def test_infer_uses_dynamic_token_input_and_numpy_postprocess(self):
height, width = 8, 12
raw = {
"points": np.zeros((1, height, width, 3), dtype=np.float32),
"normal": np.zeros((1, height, width, 3), dtype=np.float32),
"mask": np.ones((1, height, width), dtype=np.float32),
"scale": np.ones((1,), dtype=np.float32),
}
raw["points"][..., 2] = 1.0
raw["normal"][..., 2] = 1.0
session = FakeSession(raw)
expected = {
"points": np.zeros((height, width, 3), dtype=np.float32),
"depth": np.ones((height, width), dtype=np.float32),
"normal": raw["normal"][0],
"mask": np.ones((height, width), dtype=bool),
"intrinsics": np.eye(3, dtype=np.float32),
}
with patch.object(self.moge, "postprocess", return_value=expected):
result = self.moge.infer(
session,
np.zeros((height, width, 3), dtype=np.float32),
resolution_level=9,
)
self.assertIs(result, expected)
names, inputs = session.calls[0]
self.assertEqual(names, ["points", "normal", "mask", "scale"])
self.assertEqual(inputs["image"].shape, (1, 3, height, width))
self.assertEqual(inputs["num_tokens"].dtype, np.int64)
self.assertEqual(inputs["num_tokens"], 3600)
def test_infer_forwards_memory_release_boundary(self):
height, width = 8, 12
raw = {
"points": np.zeros((1, height, width, 3), dtype=np.float32),
"normal": np.zeros((1, height, width, 3), dtype=np.float32),
"mask": np.ones((1, height, width), dtype=np.float32),
"scale": np.ones((1,), dtype=np.float32),
}
session = FakeSession(raw)
with (
patch.object(self.moge, "postprocess", return_value={}),
patch.object(
self.moge,
"run_session",
side_effect=lambda model, names, feeds, **_options: model.run(
names, feeds
),
) as run,
):
self.moge.infer(
session,
np.zeros((height, width, 3), dtype=np.float32),
0,
release_memory=False,
)
self.assertFalse(run.call_args.kwargs["release_memory"])
def test_postprocess_recovers_camera_projection_and_metric_scale(self):
height, width = 64, 80
focal = np.float32(0.9)
shift = np.float32(0.3)
metric_scale = np.float32(2.0)
uv = self.moge.normalized_view_plane_uv(width, height, np.float32)
depth = np.linspace(1.0, 2.4, height * width, dtype=np.float32).reshape(
height,
width,
)
raw_points = np.concatenate(
(uv * depth[..., None] / focal, (depth - shift)[..., None]),
axis=-1,
)
raw = {
"points": raw_points[None],
"normal": np.broadcast_to(
np.array((0.0, 0.0, 1.0), dtype=np.float32),
(1, height, width, 3),
),
"mask": np.ones((1, height, width), dtype=np.float32),
"metric_scale": np.array((metric_scale,), dtype=np.float32),
}
raw["mask"][0, 0, :4] = [0.0, 0.2, 0.7, 1.0]
result = self.moge.postprocess(raw)
np.testing.assert_allclose(result["depth"], depth * metric_scale, rtol=1e-3)
np.testing.assert_allclose(result["points"][..., 2], result["depth"], rtol=1e-5)
np.testing.assert_array_equal(result["mask"], raw["mask"][0])
def test_postprocess_preserves_mask_for_nonpositive_depth(self):
mask = np.array([[[0.2, 0.7], [0.0, 1.0]]], dtype=np.float32)
raw = {
"points": np.zeros((1, 2, 2, 3), dtype=np.float32),
"normal": np.zeros((1, 2, 2, 3), dtype=np.float32),
"mask": mask,
"metric_scale": np.ones(1, dtype=np.float32),
}
with patch.object(self.moge, "recover_focal_shift", return_value=(1.0, -1.0)) as recover:
result = self.moge.postprocess(raw)
np.testing.assert_array_equal(recover.call_args.args[1], mask[0] > 0.5)
np.testing.assert_array_equal(result["mask"], mask[0])
self.assertTrue((result["depth"] < 0).all())
if __name__ == "__main__":
unittest.main()