test_xnet_2d.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from __future__ import annotations
  2. import importlib
  3. import sys
  4. import warnings
  5. from pathlib import Path
  6. import torch
  7. from torch import nn
  8. ROOT_DIR = Path(__file__).resolve().parents[1]
  9. if str(ROOT_DIR) not in sys.path:
  10. sys.path.insert(0, str(ROOT_DIR))
  11. def test_importing_xnet2d_does_not_emit_deprecation_warnings() -> None:
  12. modules_to_clear = [
  13. name
  14. for name in sys.modules
  15. if name == "lib.modules.xnet_2d" or name.startswith("lib.modules.lib_mamba")
  16. ]
  17. for name in modules_to_clear:
  18. sys.modules.pop(name, None)
  19. with warnings.catch_warnings(record=True) as caught:
  20. warnings.simplefilter("always", DeprecationWarning)
  21. importlib.import_module("lib.modules.xnet_2d")
  22. assert not [
  23. warning
  24. for warning in caught
  25. if issubclass(warning.category, DeprecationWarning)
  26. ]
  27. def test_xnet2d_forward_preserves_segmentation_shape() -> None:
  28. from lib.modules.xnet_2d import XNet2d, XTEB2d
  29. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  30. model = XNet2d(
  31. in_channels=3,
  32. num_classes=1,
  33. encoder_channels=(8, 16, 24, 32),
  34. encoder_depths=(1, 1, 1, 1),
  35. decoder_channels=(24, 16, 8),
  36. stem_channels=8,
  37. bottleneck_depth=1,
  38. global_ratio=1.0,
  39. use_wavelet_branch=True,
  40. use_global_branch_stage1=False,
  41. ssm_d_state=1,
  42. ssm_backend="torch",
  43. use_frequency_refine=True,
  44. learnable_low_freq_radius=False,
  45. ).to(device)
  46. if device.type == "cpu":
  47. for module in model.modules():
  48. if isinstance(module, XTEB2d):
  49. module.global_branch = nn.Identity()
  50. model.eval()
  51. x = torch.randn(2, 3, 64, 64, device=device)
  52. with torch.no_grad():
  53. outputs = model(x)
  54. assert outputs["seg_logits"].shape == (2, 1, 64, 64)
  55. assert outputs["logits"].shape == outputs["seg_logits"].shape
  56. assert "guides" not in outputs
  57. def test_xnet2d_decoder_uses_plain_unet_skip_connections() -> None:
  58. from lib.modules.xnet_2d import XNet2d
  59. model = XNet2d(
  60. in_channels=3,
  61. num_classes=1,
  62. encoder_channels=(8, 16, 24, 32),
  63. encoder_depths=(1, 1, 1, 1),
  64. decoder_channels=(24, 16, 8),
  65. stem_channels=8,
  66. bottleneck_depth=1,
  67. use_global_branch_stage1=False,
  68. ssm_d_state=1,
  69. ssm_backend="torch",
  70. )
  71. decoder_module_names = dict(model.decoder.named_modules())
  72. assert not any(name.startswith("guide") for name in decoder_module_names)
  73. def test_xnet2d_main_path_does_not_use_batchnorm2d() -> None:
  74. from lib.modules.xnet_2d import XNet2d
  75. model = XNet2d(
  76. in_channels=3,
  77. num_classes=1,
  78. encoder_channels=(8, 16, 24, 32),
  79. encoder_depths=(1, 1, 1, 1),
  80. decoder_channels=(24, 16, 8),
  81. stem_channels=8,
  82. bottleneck_depth=1,
  83. use_global_branch_stage1=False,
  84. ssm_d_state=1,
  85. ssm_backend="torch",
  86. )
  87. batchnorm_modules = [
  88. module
  89. for module in model.modules()
  90. if isinstance(module, nn.BatchNorm2d)
  91. ]
  92. assert not batchnorm_modules
  93. def test_xnet2d_train_mode_supports_batch_size_one_without_batchnorm_failure() -> None:
  94. from lib.modules.xnet_2d import XNet2d, XTEB2d
  95. model = XNet2d(
  96. in_channels=3,
  97. num_classes=1,
  98. encoder_channels=(8, 16, 24, 32),
  99. encoder_depths=(1, 1, 1, 1),
  100. decoder_channels=(24, 16, 8),
  101. stem_channels=8,
  102. bottleneck_depth=1,
  103. global_ratio=1.0,
  104. use_wavelet_branch=True,
  105. use_global_branch_stage1=False,
  106. ssm_d_state=1,
  107. ssm_backend="torch",
  108. use_frequency_refine=True,
  109. learnable_low_freq_radius=False,
  110. )
  111. for module in model.modules():
  112. if isinstance(module, XTEB2d):
  113. module.global_branch = nn.Identity()
  114. model.train()
  115. x = torch.randn(1, 3, 64, 64)
  116. outputs = model(x)
  117. assert outputs["seg_logits"].shape == (1, 1, 64, 64)