Skip to content

Commit c516072

Browse files
test Hailo preprocessing contract
1 parent ec2d9c1 commit c516072

1 file changed

Lines changed: 33 additions & 24 deletions

File tree

tests/test_hailo_end_to_end.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import torch
66
from PIL import Image
77

8+
from anomavision.inference.model.backends.hailo_backend import HailoAnomalyRuntime
89
from anomavision.quantize.model.backends.hef import graphs as hailo_graphs
910
from anomavision.quantize.model.backends.hef.exporter import (
1011
_write_calibration_manifest,
@@ -18,7 +19,6 @@ def __init__(self, backbone, device):
1819

1920
def forward(self, image, layer_indices=None):
2021
batch = image.shape[0]
21-
# Four-by-four patch grid with four channels for compact graph tests.
2222
features = torch.nn.functional.adaptive_avg_pool2d(image, (4, 4))
2323
features = features.mean(dim=1, keepdim=True).repeat(1, 4, 1, 1)
2424
return features.permute(0, 2, 3, 1).reshape(batch, 16, 4), 4, 4
@@ -31,12 +31,8 @@ def _patch_fake_extractor(monkeypatch):
3131
def test_padim_graph_contains_distance_and_reduction(monkeypatch):
3232
_patch_fake_extractor(monkeypatch)
3333
graph = hailo_graphs.PadimEndToEndGraph(
34-
backbone="resnet18",
35-
layer_indices=[0, 1],
36-
channel_indices=torch.arange(4),
37-
mean=torch.zeros(16, 4),
38-
cov_inv=torch.eye(4).repeat(16, 1, 1),
39-
input_size=(32, 32),
34+
backbone="resnet18", layer_indices=[0, 1], channel_indices=torch.arange(4),
35+
mean=torch.zeros(16, 4), cov_inv=torch.eye(4).repeat(16, 1, 1), input_size=(32, 32)
4036
).eval()
4137
image_scores, score_map = graph(torch.ones(1, 3, 32, 32))
4238
assert image_scores.shape == (1,)
@@ -48,11 +44,8 @@ def test_padim_graph_contains_distance_and_reduction(monkeypatch):
4844
def test_patchcore_graph_contains_memory_distance_and_reduction(monkeypatch):
4945
_patch_fake_extractor(monkeypatch)
5046
graph = hailo_graphs.PatchCoreEndToEndGraph(
51-
backbone="resnet18",
52-
layer_indices=[0, 1],
53-
memory_bank=torch.zeros(8, 4),
54-
patch_grid=4,
55-
input_size=(32, 32),
47+
backbone="resnet18", layer_indices=[0, 1], memory_bank=torch.zeros(8, 4),
48+
patch_grid=4, input_size=(32, 32)
5649
).eval()
5750
image_scores, score_map = graph(torch.ones(1, 3, 32, 32))
5851
assert image_scores.shape == (1,)
@@ -61,20 +54,10 @@ def test_patchcore_graph_contains_memory_distance_and_reduction(monkeypatch):
6154
assert torch.isfinite(score_map).all()
6255

6356

64-
def test_export_writes_end_to_end_metadata_and_calibration_manifest(
65-
tmp_path, monkeypatch
66-
):
57+
def test_export_writes_end_to_end_metadata_and_calibration_manifest(tmp_path, monkeypatch):
6758
_patch_fake_extractor(monkeypatch)
6859
artifact = tmp_path / "patchcore.pt"
69-
torch.save(
70-
{
71-
"backbone": "resnet18",
72-
"layer_indices": [0, 1],
73-
"memory_bank": torch.zeros(8, 4),
74-
"patch_grid": 4,
75-
},
76-
artifact,
77-
)
60+
torch.save({"backbone": "resnet18", "layer_indices": [0, 1], "memory_bank": torch.zeros(8, 4), "patch_grid": 4}, artifact)
7861
calibration = tmp_path / "calibration"
7962
calibration.mkdir()
8063
Image.fromarray(np.zeros((32, 32, 3), dtype=np.uint8)).save(calibration / "one.png")
@@ -83,9 +66,35 @@ def test_export_writes_end_to_end_metadata_and_calibration_manifest(
8366
assert onnx_path.exists()
8467
manifest = _write_calibration_manifest(calibration, output, (32, 32))
8568
assert manifest.exists()
69+
calibration_array = np.load(output / "calibration_npy" / "sample_0000.npy")
70+
expected = -(np.asarray([0.485, 0.456, 0.406]) / np.asarray([0.229, 0.224, 0.225]))
71+
np.testing.assert_allclose(calibration_array[0, 0], expected, atol=1e-6)
8672
assert onnx_path.name.endswith("_end_to_end.onnx")
8773

8874

75+
def test_hailo_preprocessed_tensor_only_transposes():
76+
runtime = HailoAnomalyRuntime.__new__(HailoAnomalyRuntime)
77+
runtime.input_size = (32, 32)
78+
runtime.input_dtype = np.float32
79+
runtime.mean = np.asarray([0.485, 0.456, 0.406], dtype=np.float32).reshape(1, 1, 3)
80+
runtime.std = np.asarray([0.229, 0.224, 0.225], dtype=np.float32).reshape(1, 1, 3)
81+
nchw = np.random.default_rng(42).normal(size=(1, 3, 32, 32)).astype(np.float32)
82+
prepared = runtime._prepare_input(nchw)
83+
np.testing.assert_allclose(prepared, np.transpose(nchw[0], (1, 2, 0)))
84+
85+
86+
def test_hailo_raw_image_is_normalized_once():
87+
runtime = HailoAnomalyRuntime.__new__(HailoAnomalyRuntime)
88+
runtime.input_size = (32, 32)
89+
runtime.input_dtype = np.float32
90+
runtime.mean = np.asarray([0.485, 0.456, 0.406], dtype=np.float32).reshape(1, 1, 3)
91+
runtime.std = np.asarray([0.229, 0.224, 0.225], dtype=np.float32).reshape(1, 1, 3)
92+
raw = np.full((32, 32, 3), 255, dtype=np.uint8)
93+
prepared = runtime._prepare_input(raw)
94+
expected = (1.0 - runtime.mean) / runtime.std
95+
np.testing.assert_allclose(prepared, expected, atol=1e-6)
96+
97+
8998
def test_export_rejects_partial_artifact(tmp_path):
9099
artifact = tmp_path / "bad.pt"
91100
torch.save({"backbone": "resnet18"}, artifact)

0 commit comments

Comments
 (0)