Download code/tests/test_mano_host.py from changh95/hamer-p150: direct link, hf CLI and curl.
- Browser
- Download file 2.58 kB
-
https://huggingface.co/changh95/hamer-p150/resolve/main/code/tests/test_mano_host.py
- Command line
-
hf download hf://changh95/hamer-p150/code/tests/test_mano_host.py
-
curl -L -o test_mano_host.py https://huggingface.co/changh95/hamer-p150/resolve/main/code/tests/test_mano_host.py
2.58 kB
| # SPDX-FileCopyrightText: © 2026 Tenstorrent Inc. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| """Host-only MANO checks (no device, no licensed MANO_RIGHT.pkl needed). | |
| A synthetic pkl with the real MANO array shapes stands in for MANO_RIGHT.pkl: its outputs are meaningless, but | |
| the shape blend / kinematic walk / skinning code paths are the same, which is all the bit-identity test needs. | |
| """ | |
| import pickle | |
| import numpy as np | |
| import pytest | |
| import torch | |
| from hamer.mano import MANO | |
| def mano(tmp_path_factory): | |
| g = np.random.default_rng(0) | |
| w = g.random((778, 16)) | |
| w /= w.sum(1, keepdims=True) | |
| jr = np.zeros((16, 778)) | |
| for j in range(16): | |
| jr[j, g.choice(778, 20, replace=False)] = 1 / 20 | |
| d = {"v_template": g.random((778, 3)) * 0.1, "shapedirs": g.normal(0, 1e-3, (778, 3, 10)), | |
| "posedirs": g.normal(0, 1e-3, (778, 3, 135)), "J_regressor": jr, "weights": w, | |
| "kintree_table": np.array([[4294967295, 0, 1, 2, 0, 4, 5, 0, 7, 8, 0, 10, 11, 0, 13, 14], list(range(16))]), | |
| "f": g.integers(0, 778, (1538, 3))} | |
| p = tmp_path_factory.mktemp("mano") / "MANO_RIGHT.pkl" | |
| with open(p, "wb") as f: | |
| pickle.dump(d, f) | |
| return MANO(p).eval() | |
| def _random_pose(g, batch): | |
| a = torch.randn(batch, 16, 3, 3, generator=g, dtype=torch.float64) * 0.5 | |
| rot = torch.linalg.matrix_exp(a - a.transpose(-1, -2)).float() # proper rotations | |
| return rot, torch.randn(batch, 10, generator=g) | |
| def test_forward_with_joints_bit_identical(mano, batch): | |
| """The server's one-walk path (default) returns exactly forward() + joints_21() (the HAMER_MANO_ONEPASS=0 path).""" | |
| g = torch.Generator().manual_seed(batch) | |
| with torch.inference_mode(): | |
| for _ in range(100): | |
| rot, betas = _random_pose(g, batch) | |
| v0, j0 = mano(rot, betas), mano.joints_21(rot, betas) | |
| v1, j1 = mano.forward_with_joints(rot, betas) | |
| assert v1.shape == (batch, 778, 3) and j1.shape == (batch, 21, 3) | |
| assert torch.equal(v0, v1) and torch.equal(j0, j1) | |
| def test_server_mano_onepass_switch(monkeypatch): | |
| import importlib | |
| import hamer.server.app as app | |
| try: | |
| monkeypatch.setenv("HAMER_MANO_ONEPASS", "0") | |
| assert importlib.reload(app).MANO_ONEPASS is False | |
| monkeypatch.delenv("HAMER_MANO_ONEPASS") | |
| assert importlib.reload(app).MANO_ONEPASS is True # default on | |
| finally: | |
| monkeypatch.delenv("HAMER_MANO_ONEPASS", raising=False) | |
| importlib.reload(app) | |