fix(convexadam): disable only the TensorExpr fuser during registration
Browse filesThe TS feature models trip torch's TensorExpr fuser alias analysis (INTERNAL ASSERT on aten::size/dim in FuseTensorExprs) when itk-impact runs them. Verified via itk-impact: model-side is impossible (itk-impact passes an undefined direction, so guarding it needs a shape op = the fuser trigger); disabling the fuser is the only fix. Scope it (_no_texpr_fuser) to the registration: modern profiling executor stays on (not legacy), measured ~1% cost (fuser only touches the few feature forwards, not the 150-iter C++ optimisation loop).
ConvexAdam_Coarse/Model.py
CHANGED
|
@@ -33,6 +33,7 @@ NOTE: do NOT add ``from __future__ import annotations`` — KonfAI's config engi
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
|
|
|
| 36 |
import json
|
| 37 |
import os
|
| 38 |
from dataclasses import dataclass, field
|
|
@@ -106,6 +107,22 @@ class ModelSpec:
|
|
| 106 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 107 |
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
def _coarse_registration_type():
|
| 110 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 111 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
@@ -444,7 +461,7 @@ class ConvexAdamRegistration(torch.nn.Module):
|
|
| 444 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 445 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 446 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 447 |
-
with torch.inference_mode(False), torch.enable_grad():
|
| 448 |
for b in range(fixed.shape[0]):
|
| 449 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 450 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
|
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
| 36 |
+
import contextlib
|
| 37 |
import json
|
| 38 |
import os
|
| 39 |
from dataclasses import dataclass, field
|
|
|
|
| 107 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 108 |
|
| 109 |
|
| 110 |
+
@contextlib.contextmanager
|
| 111 |
+
def _no_texpr_fuser():
|
| 112 |
+
"""Disable ONLY torch's TensorExpr (NNC) fuser for the block. The TS feature-model graphs have a direction/
|
| 113 |
+
orientation branch whose shape ops (aten::dim / aten::size) crash the fuser's alias analysis under itk-impact
|
| 114 |
+
("INTERNAL ASSERT ... We don't have an op for aten::size" in FuseTensorExprs). It cannot be fixed model-side:
|
| 115 |
+
itk-impact passes an *undefined* direction, so guarding it needs a shape op — the very fuser trigger. The
|
| 116 |
+
modern profiling executor stays on (NOT the legacy executor); measured cost ~1% of a registration (the fuser
|
| 117 |
+
only touches the few feature forwards, not the C++ optimisation loop). The caller's setting is restored."""
|
| 118 |
+
prev = torch._C._jit_texpr_fuser_enabled()
|
| 119 |
+
torch._C._jit_set_texpr_fuser_enabled(False)
|
| 120 |
+
try:
|
| 121 |
+
yield
|
| 122 |
+
finally:
|
| 123 |
+
torch._C._jit_set_texpr_fuser_enabled(prev)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
def _coarse_registration_type():
|
| 127 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 128 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
|
|
| 461 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 462 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 463 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 464 |
+
with torch.inference_mode(False), torch.enable_grad(), _no_texpr_fuser():
|
| 465 |
for b in range(fixed.shape[0]):
|
| 466 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 467 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
ConvexAdam_Composite/Model.py
CHANGED
|
@@ -33,6 +33,7 @@ NOTE: do NOT add ``from __future__ import annotations`` — KonfAI's config engi
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
|
|
|
| 36 |
import json
|
| 37 |
import os
|
| 38 |
from dataclasses import dataclass, field
|
|
@@ -106,6 +107,22 @@ class ModelSpec:
|
|
| 106 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 107 |
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
def _coarse_registration_type():
|
| 110 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 111 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
@@ -444,7 +461,7 @@ class ConvexAdamRegistration(torch.nn.Module):
|
|
| 444 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 445 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 446 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 447 |
-
with torch.inference_mode(False), torch.enable_grad():
|
| 448 |
for b in range(fixed.shape[0]):
|
| 449 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 450 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
|
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
| 36 |
+
import contextlib
|
| 37 |
import json
|
| 38 |
import os
|
| 39 |
from dataclasses import dataclass, field
|
|
|
|
| 107 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 108 |
|
| 109 |
|
| 110 |
+
@contextlib.contextmanager
|
| 111 |
+
def _no_texpr_fuser():
|
| 112 |
+
"""Disable ONLY torch's TensorExpr (NNC) fuser for the block. The TS feature-model graphs have a direction/
|
| 113 |
+
orientation branch whose shape ops (aten::dim / aten::size) crash the fuser's alias analysis under itk-impact
|
| 114 |
+
("INTERNAL ASSERT ... We don't have an op for aten::size" in FuseTensorExprs). It cannot be fixed model-side:
|
| 115 |
+
itk-impact passes an *undefined* direction, so guarding it needs a shape op — the very fuser trigger. The
|
| 116 |
+
modern profiling executor stays on (NOT the legacy executor); measured cost ~1% of a registration (the fuser
|
| 117 |
+
only touches the few feature forwards, not the C++ optimisation loop). The caller's setting is restored."""
|
| 118 |
+
prev = torch._C._jit_texpr_fuser_enabled()
|
| 119 |
+
torch._C._jit_set_texpr_fuser_enabled(False)
|
| 120 |
+
try:
|
| 121 |
+
yield
|
| 122 |
+
finally:
|
| 123 |
+
torch._C._jit_set_texpr_fuser_enabled(prev)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
def _coarse_registration_type():
|
| 127 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 128 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
|
|
| 461 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 462 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 463 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 464 |
+
with torch.inference_mode(False), torch.enable_grad(), _no_texpr_fuser():
|
| 465 |
for b in range(fixed.shape[0]):
|
| 466 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 467 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
ConvexAdam_Fine/Model.py
CHANGED
|
@@ -33,6 +33,7 @@ NOTE: do NOT add ``from __future__ import annotations`` — KonfAI's config engi
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
|
|
|
| 36 |
import json
|
| 37 |
import os
|
| 38 |
from dataclasses import dataclass, field
|
|
@@ -106,6 +107,22 @@ class ModelSpec:
|
|
| 106 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 107 |
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
def _coarse_registration_type():
|
| 110 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 111 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
@@ -444,7 +461,7 @@ class ConvexAdamRegistration(torch.nn.Module):
|
|
| 444 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 445 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 446 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 447 |
-
with torch.inference_mode(False), torch.enable_grad():
|
| 448 |
for b in range(fixed.shape[0]):
|
| 449 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 450 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
|
|
|
| 33 |
runtime-evaluated annotations (``get_origin``); PEP 563 stringized annotations break binding.
|
| 34 |
"""
|
| 35 |
|
| 36 |
+
import contextlib
|
| 37 |
import json
|
| 38 |
import os
|
| 39 |
from dataclasses import dataclass, field
|
|
|
|
| 107 |
distance: Literal["L1", "L2", "Dice", "Cosine", "NCC"] = "L1"
|
| 108 |
|
| 109 |
|
| 110 |
+
@contextlib.contextmanager
|
| 111 |
+
def _no_texpr_fuser():
|
| 112 |
+
"""Disable ONLY torch's TensorExpr (NNC) fuser for the block. The TS feature-model graphs have a direction/
|
| 113 |
+
orientation branch whose shape ops (aten::dim / aten::size) crash the fuser's alias analysis under itk-impact
|
| 114 |
+
("INTERNAL ASSERT ... We don't have an op for aten::size" in FuseTensorExprs). It cannot be fixed model-side:
|
| 115 |
+
itk-impact passes an *undefined* direction, so guarding it needs a shape op — the very fuser trigger. The
|
| 116 |
+
modern profiling executor stays on (NOT the legacy executor); measured cost ~1% of a registration (the fuser
|
| 117 |
+
only touches the few feature forwards, not the C++ optimisation loop). The caller's setting is restored."""
|
| 118 |
+
prev = torch._C._jit_texpr_fuser_enabled()
|
| 119 |
+
torch._C._jit_set_texpr_fuser_enabled(False)
|
| 120 |
+
try:
|
| 121 |
+
yield
|
| 122 |
+
finally:
|
| 123 |
+
torch._C._jit_set_texpr_fuser_enabled(prev)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
def _coarse_registration_type():
|
| 127 |
"""The coupled-convex initializer, tolerant to the two names the wrapping has shipped under."""
|
| 128 |
cls = getattr(itk, "ImpactCoarseRegistration", None) or getattr(itk, "ImpactConvexAdamInitializer", None)
|
|
|
|
| 461 |
# ConvexAdam runs a gradient-based instance optimisation (Adam over the field) inside itk-impact's
|
| 462 |
# .Update(); the predictor calls forward under torch.inference_mode(), which forbids autograd. The
|
| 463 |
# image tensors have already crossed to numpy/ITK here, so re-enable grad for the optimisation.
|
| 464 |
+
with torch.inference_mode(False), torch.enable_grad(), _no_texpr_fuser():
|
| 465 |
for b in range(fixed.shape[0]):
|
| 466 |
fixed_img = data_to_image(fixed[b].detach().cpu().numpy(), fixed_attrs[b])
|
| 467 |
moving_img = data_to_image(moving[b].detach().cpu().numpy(), moving_attrs[b])
|
ConvexAdam_Fine/__pycache__/Model.cpython-313.pyc
CHANGED
|
Binary files a/ConvexAdam_Fine/__pycache__/Model.cpython-313.pyc and b/ConvexAdam_Fine/__pycache__/Model.cpython-313.pyc differ
|
|
|