ToTf 0.2.5__tar.gz → 0.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {totf-0.2.5 → totf-0.2.6}/PKG-INFO +16 -1
  2. {totf-0.2.5 → totf-0.2.6}/README.md +15 -0
  3. {totf-0.2.5 → totf-0.2.6}/ToTf/__init__.py +23 -2
  4. {totf-0.2.5 → totf-0.2.6}/ToTf/backend_manager.py +75 -1
  5. {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/PKG-INFO +16 -1
  6. {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/SOURCES.txt +1 -0
  7. {totf-0.2.5 → totf-0.2.6}/pyproject.toml +1 -1
  8. {totf-0.2.5 → totf-0.2.6}/setup.py +1 -1
  9. totf-0.2.6/test/test_phase1_utils.py +345 -0
  10. {totf-0.2.5 → totf-0.2.6}/LICENSE +0 -0
  11. {totf-0.2.5 → totf-0.2.6}/ToTf/backend.py +0 -0
  12. {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/dependency_links.txt +0 -0
  13. {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/requires.txt +0 -0
  14. {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/top_level.txt +0 -0
  15. {totf-0.2.5 → totf-0.2.6}/setup.cfg +0 -0
  16. {totf-0.2.5 → totf-0.2.6}/test/test_connection_api.py +0 -0
  17. {totf-0.2.5 → totf-0.2.6}/test/test_connections_visual.py +0 -0
  18. {totf-0.2.5 → totf-0.2.6}/test/test_integration.py +0 -0
  19. {totf-0.2.5 → totf-0.2.6}/test/test_modelview_quick.py +0 -0
  20. {totf-0.2.5 → totf-0.2.6}/test/test_modelview_tf.py +0 -0
  21. {totf-0.2.5 → totf-0.2.6}/test/test_monitor.py +0 -0
  22. {totf-0.2.5 → totf-0.2.6}/test/test_onnx_pytorch.py +0 -0
  23. {totf-0.2.5 → totf-0.2.6}/test/test_onnx_tensorflow.py +0 -0
  24. {totf-0.2.5 → totf-0.2.6}/test/test_pytorch_modelview_quick.py +0 -0
  25. {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary.py +0 -0
  26. {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary_features.py +0 -0
  27. {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary_tf.py +0 -0
  28. {totf-0.2.5 → totf-0.2.6}/test/test_utils_integration.py +0 -0
  29. {totf-0.2.5 → totf-0.2.6}/test/test_utils_pytorch.py +0 -0
  30. {totf-0.2.5 → totf-0.2.6}/test/test_utils_tf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ToTf
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: A Cross-Library Compatible Library for PyTorch and TensorFlow that provides advanced features for ease of use
5
5
  Home-page: https://github.com/Akshay-Ramesh-VITC/ToTf
6
6
  Author: Akshay, Shyamanth Reddy
@@ -124,6 +124,21 @@ Framework-agnostic "missing" functions that save time and improve code quality:
124
124
  - **`LRFinder`** - Full-featured LR range test class with plotting
125
125
  - **Use case**: Automatically discover the best learning rate before training (fast.ai style), avoid manual tuning
126
126
 
127
+ #### Cross-Framework Reproducibility
128
+ - **`seed_everything(seed=42, deterministic=False, benchmark=False, verbose=False)`** - Seeds Python, NumPy, PyTorch (CPU & CUDA), and TensorFlow in a single call. Optionally sets deterministic algorithms and cuBLAS workspace config.
129
+ - **Use case**: Guaranteed reproducible experiments and benchmarks across backends without repeating 10 lines of boilerplate.
130
+
131
+ #### Tensor Health & Diagnostics
132
+ - **`inspect_tensor(tensor, name=None, print_info=True, quantiles=True)`** - One-line diagnostic inspector for PyTorch, TensorFlow, or NumPy tensors.
133
+ - **Information provided**: Shape, dtype, device, memory MB, element count, NaN/Inf detection, zero sparsity %, min, max, mean, std, and quantiles (p25, p50, p75).
134
+ - **Use case**: Rapid sanity-checking and debugging of activations, embeddings, and gradients.
135
+
136
+ #### Transfer Learning & Fine-Tuning
137
+ - **`freeze_layers(model, up_to=None, layer_names=None, layer_types=None, regex=None)`** - Freeze model parameters/layers (supports both `torch.nn.Module` and `tf.keras.Model`).
138
+ - **`unfreeze_layers(model, last_n=None, layer_names=None, layer_types=None, regex=None)`** - Selectively unfreeze layers (e.g., `last_n=1` for classification heads).
139
+ - **`freeze_batchnorm(model, freeze_eval=True)`** - Lock BatchNorm affine parameters and freeze running statistics (eval mode) during fine-tuning.
140
+ - **Use case**: Effortless backbone freezing and transfer learning across both frameworks.
141
+
127
142
  ### 📊 ModelView (PyTorch & TensorFlow)
128
143
  Publication-quality neural network architecture diagrams for both frameworks:
129
144
  - **PyTorch support** - Wraps torchview for comprehensive PyTorch model visualization
@@ -52,6 +52,21 @@ Framework-agnostic "missing" functions that save time and improve code quality:
52
52
  - **`LRFinder`** - Full-featured LR range test class with plotting
53
53
  - **Use case**: Automatically discover the best learning rate before training (fast.ai style), avoid manual tuning
54
54
 
55
+ #### Cross-Framework Reproducibility
56
+ - **`seed_everything(seed=42, deterministic=False, benchmark=False, verbose=False)`** - Seeds Python, NumPy, PyTorch (CPU & CUDA), and TensorFlow in a single call. Optionally sets deterministic algorithms and cuBLAS workspace config.
57
+ - **Use case**: Guaranteed reproducible experiments and benchmarks across backends without repeating 10 lines of boilerplate.
58
+
59
+ #### Tensor Health & Diagnostics
60
+ - **`inspect_tensor(tensor, name=None, print_info=True, quantiles=True)`** - One-line diagnostic inspector for PyTorch, TensorFlow, or NumPy tensors.
61
+ - **Information provided**: Shape, dtype, device, memory MB, element count, NaN/Inf detection, zero sparsity %, min, max, mean, std, and quantiles (p25, p50, p75).
62
+ - **Use case**: Rapid sanity-checking and debugging of activations, embeddings, and gradients.
63
+
64
+ #### Transfer Learning & Fine-Tuning
65
+ - **`freeze_layers(model, up_to=None, layer_names=None, layer_types=None, regex=None)`** - Freeze model parameters/layers (supports both `torch.nn.Module` and `tf.keras.Model`).
66
+ - **`unfreeze_layers(model, last_n=None, layer_names=None, layer_types=None, regex=None)`** - Selectively unfreeze layers (e.g., `last_n=1` for classification heads).
67
+ - **`freeze_batchnorm(model, freeze_eval=True)`** - Lock BatchNorm affine parameters and freeze running statistics (eval mode) during fine-tuning.
68
+ - **Use case**: Effortless backbone freezing and transfer learning across both frameworks.
69
+
55
70
  ### 📊 ModelView (PyTorch & TensorFlow)
56
71
  Publication-quality neural network architecture diagrams for both frameworks:
57
72
  - **PyTorch support** - Wraps torchview for comprehensive PyTorch model visualization
@@ -6,9 +6,30 @@ Provides additional features for ease of use not directly available in Torch or
6
6
  from .backend import get_backend, _BACKEND
7
7
  from .backend_manager import SmartSummary, TrainingMonitor, ModelView, draw_graph, get_component
8
8
  from .backend_manager import toONNX, fromONNX
9
+ from .backend_manager import (
10
+ seed_everything,
11
+ inspect_tensor,
12
+ freeze_layers,
13
+ unfreeze_layers,
14
+ freeze_batchnorm,
15
+ )
9
16
 
10
- __version__ = "0.2.5"
17
+ __version__ = "0.2.6"
11
18
  __author__ = "Akshay"
12
- __all__ = ["get_backend", "TrainingMonitor", "SmartSummary", "ModelView", "draw_graph", "get_component", "toONNX", "fromONNX"]
19
+ __all__ = [
20
+ "get_backend",
21
+ "TrainingMonitor",
22
+ "SmartSummary",
23
+ "ModelView",
24
+ "draw_graph",
25
+ "get_component",
26
+ "toONNX",
27
+ "fromONNX",
28
+ "seed_everything",
29
+ "inspect_tensor",
30
+ "freeze_layers",
31
+ "unfreeze_layers",
32
+ "freeze_batchnorm",
33
+ ]
13
34
 
14
35
  # Use backend_manager factories for dynamic dispatch to framework implementations
@@ -44,7 +44,7 @@ def _is_torch_tensor(obj: Any) -> bool:
44
44
  def _is_tf_tensor(obj: Any) -> bool:
45
45
  try:
46
46
  import tensorflow as tf
47
- return isinstance(obj, tf.Tensor) or isinstance(obj, tf.keras.Model)
47
+ return isinstance(obj, (tf.Tensor, tf.Variable, tf.keras.Model, tf.keras.layers.Layer))
48
48
  except Exception:
49
49
  return False
50
50
 
@@ -225,3 +225,77 @@ def fromONNX(onnx_path: str, *args, backend_name: Optional[str] = None, **kwargs
225
225
  raise ImportError(f"fromONNX not implemented in backend utils for '{b}'")
226
226
 
227
227
  return fn(onnx_path, *args, **kwargs)
228
+
229
+
230
+ def seed_everything(
231
+ seed: int = 42,
232
+ deterministic: bool = False,
233
+ benchmark: bool = False,
234
+ verbose: bool = False,
235
+ backend_name: Optional[str] = None,
236
+ ) -> int:
237
+ """
238
+ Sets seeds across Python, NumPy, PyTorch, and TensorFlow for reproducibility.
239
+ """
240
+ b = backend_name or get_default_backend()
241
+ impl_mod = _load_backend_impl(b, "utils")
242
+ if impl_mod is not None and hasattr(impl_mod, "seed_everything"):
243
+ return impl_mod.seed_everything(seed=seed, deterministic=deterministic, benchmark=benchmark, verbose=verbose)
244
+ # Fallback to direct seeding
245
+ import os
246
+ import random
247
+ import numpy as np
248
+ random.seed(seed)
249
+ os.environ["PYTHONHASHSEED"] = str(seed)
250
+ np.random.seed(seed)
251
+ return seed
252
+
253
+
254
+ def inspect_tensor(
255
+ tensor: Any,
256
+ name: Optional[str] = None,
257
+ print_info: bool = True,
258
+ quantiles: bool = True,
259
+ backend_name: Optional[str] = None,
260
+ ) -> Dict[str, Any]:
261
+ """
262
+ Inspects a tensor (Torch, TF, or NumPy) and returns detailed statistics and health metrics.
263
+ """
264
+ b = _choose_backend_from_obj(tensor) or backend_name or get_default_backend()
265
+ impl_mod = _load_backend_impl(b, "utils")
266
+ if impl_mod is None or not hasattr(impl_mod, "inspect_tensor"):
267
+ raise ImportError(f"inspect_tensor utils not available for backend '{b}'")
268
+ return impl_mod.inspect_tensor(tensor, name=name, print_info=print_info, quantiles=quantiles)
269
+
270
+
271
+ def freeze_layers(model: Any, *args, backend_name: Optional[str] = None, **kwargs) -> int:
272
+ """
273
+ Freeze layers or parameters in a PyTorch or TensorFlow model for transfer learning.
274
+ """
275
+ b = _choose_backend_from_obj(model) or backend_name or get_default_backend()
276
+ impl_mod = _load_backend_impl(b, "utils")
277
+ if impl_mod is None or not hasattr(impl_mod, "freeze_layers"):
278
+ raise ImportError(f"freeze_layers utils not available for backend '{b}'")
279
+ return impl_mod.freeze_layers(model, *args, **kwargs)
280
+
281
+
282
+ def unfreeze_layers(model: Any, *args, backend_name: Optional[str] = None, **kwargs) -> int:
283
+ """
284
+ Unfreeze layers or parameters in a PyTorch or TensorFlow model.
285
+ """
286
+ b = _choose_backend_from_obj(model) or backend_name or get_default_backend()
287
+ impl_mod = _load_backend_impl(b, "utils")
288
+ if impl_mod is None or not hasattr(impl_mod, "unfreeze_layers"):
289
+ raise ImportError(f"unfreeze_layers utils not available for backend '{b}'")
290
+ return impl_mod.unfreeze_layers(model, *args, **kwargs)
291
+
292
+
293
+ def freeze_batchnorm(model: Any, *args, backend_name: Optional[str] = None, **kwargs) -> int:
294
+ """
295
+ Freeze BatchNorm layers in a PyTorch or TensorFlow model.
296
+ """
297
+ b = _choose_backend_from_obj(model) or backend_name or get_default_backend()
298
+ impl_mod = _load_backend_impl(b, "utils")
299
+ if impl_mod is None or not hasattr(impl_mod, "freeze_batchnorm"):
300
+ raise ImportError(f"freeze_batchnorm utils not available for backend '{b}'")
301
+ return impl_mod.freeze_batchnorm(model, *args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ToTf
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: A Cross-Library Compatible Library for PyTorch and TensorFlow that provides advanced features for ease of use
5
5
  Home-page: https://github.com/Akshay-Ramesh-VITC/ToTf
6
6
  Author: Akshay, Shyamanth Reddy
@@ -124,6 +124,21 @@ Framework-agnostic "missing" functions that save time and improve code quality:
124
124
  - **`LRFinder`** - Full-featured LR range test class with plotting
125
125
  - **Use case**: Automatically discover the best learning rate before training (fast.ai style), avoid manual tuning
126
126
 
127
+ #### Cross-Framework Reproducibility
128
+ - **`seed_everything(seed=42, deterministic=False, benchmark=False, verbose=False)`** - Seeds Python, NumPy, PyTorch (CPU & CUDA), and TensorFlow in a single call. Optionally sets deterministic algorithms and cuBLAS workspace config.
129
+ - **Use case**: Guaranteed reproducible experiments and benchmarks across backends without repeating 10 lines of boilerplate.
130
+
131
+ #### Tensor Health & Diagnostics
132
+ - **`inspect_tensor(tensor, name=None, print_info=True, quantiles=True)`** - One-line diagnostic inspector for PyTorch, TensorFlow, or NumPy tensors.
133
+ - **Information provided**: Shape, dtype, device, memory MB, element count, NaN/Inf detection, zero sparsity %, min, max, mean, std, and quantiles (p25, p50, p75).
134
+ - **Use case**: Rapid sanity-checking and debugging of activations, embeddings, and gradients.
135
+
136
+ #### Transfer Learning & Fine-Tuning
137
+ - **`freeze_layers(model, up_to=None, layer_names=None, layer_types=None, regex=None)`** - Freeze model parameters/layers (supports both `torch.nn.Module` and `tf.keras.Model`).
138
+ - **`unfreeze_layers(model, last_n=None, layer_names=None, layer_types=None, regex=None)`** - Selectively unfreeze layers (e.g., `last_n=1` for classification heads).
139
+ - **`freeze_batchnorm(model, freeze_eval=True)`** - Lock BatchNorm affine parameters and freeze running statistics (eval mode) during fine-tuning.
140
+ - **Use case**: Effortless backbone freezing and transfer learning across both frameworks.
141
+
127
142
  ### 📊 ModelView (PyTorch & TensorFlow)
128
143
  Publication-quality neural network architecture diagrams for both frameworks:
129
144
  - **PyTorch support** - Wraps torchview for comprehensive PyTorch model visualization
@@ -18,6 +18,7 @@ test/test_modelview_tf.py
18
18
  test/test_monitor.py
19
19
  test/test_onnx_pytorch.py
20
20
  test/test_onnx_tensorflow.py
21
+ test/test_phase1_utils.py
21
22
  test/test_pytorch_modelview_quick.py
22
23
  test/test_smartsummary.py
23
24
  test/test_smartsummary_features.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ToTf"
7
- version = "0.2.5"
7
+ version = "0.2.6"
8
8
  description = "A Cross-Library Compatible Library for PyTorch and TensorFlow that provides advanced features for ease of use"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -9,7 +9,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
9
9
 
10
10
  setup(
11
11
  name="ToTf",
12
- version="0.2.5",
12
+ version="0.2.6",
13
13
  author="Akshay",
14
14
  author_email="akshay.r2023@vitstudent.ac.in",
15
15
  description="A Cross-Library Compatible Library for PyTorch and TensorFlow",
@@ -0,0 +1,345 @@
1
+ """
2
+ Unit and integration tests for Phase 1 features:
3
+ - seed_everything
4
+ - inspect_tensor
5
+ - freeze_layers, unfreeze_layers, freeze_batchnorm
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import numpy as np
11
+ import pytest
12
+
13
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
14
+
15
+ import torch
16
+ import torch.nn as nn
17
+ import tensorflow as tf
18
+ from tensorflow import keras
19
+
20
+ import ToTf
21
+ from ToTf import (
22
+ seed_everything,
23
+ inspect_tensor,
24
+ freeze_layers,
25
+ unfreeze_layers,
26
+ freeze_batchnorm,
27
+ )
28
+
29
+
30
+ class TorchToyNet(nn.Module):
31
+ def __init__(self):
32
+ super().__init__()
33
+ self.conv1 = nn.Conv2d(3, 8, 3, padding=1)
34
+ self.bn1 = nn.BatchNorm2d(8)
35
+ self.conv2 = nn.Conv2d(8, 16, 3, padding=1)
36
+ self.bn2 = nn.BatchNorm2d(16)
37
+ self.head = nn.Linear(16 * 4 * 4, 10)
38
+
39
+ def forward(self, x):
40
+ x = torch.relu(self.bn1(self.conv1(x)))
41
+ x = torch.relu(self.bn2(self.conv2(x)))
42
+ x = x.flatten(1)
43
+ return self.head(x)
44
+
45
+
46
+ def create_tf_toy_model():
47
+ model = keras.Sequential([
48
+ keras.layers.Input(shape=(32, 32, 3)),
49
+ keras.layers.Conv2D(8, 3, padding='same', name='conv1'),
50
+ keras.layers.BatchNormalization(name='bn1'),
51
+ keras.layers.ReLU(name='relu1'),
52
+ keras.layers.Conv2D(16, 3, padding='same', name='conv2'),
53
+ keras.layers.BatchNormalization(name='bn2'),
54
+ keras.layers.Flatten(name='flatten'),
55
+ keras.layers.Dense(10, name='head'),
56
+ ])
57
+ return model
58
+
59
+
60
+ # =========================================================================
61
+ # 1. seed_everything tests
62
+ # =========================================================================
63
+
64
+ def test_seed_everything_determinism():
65
+ # Run 1
66
+ seed_everything(1234)
67
+ np_val1 = np.random.rand(5)
68
+ th_val1 = torch.randn(5).numpy()
69
+ tf_val1 = tf.random.normal([5]).numpy()
70
+
71
+ # Run 2 with same seed
72
+ seed_val = seed_everything(1234, deterministic=True, benchmark=False)
73
+ assert seed_val == 1234
74
+ np_val2 = np.random.rand(5)
75
+ th_val2 = torch.randn(5).numpy()
76
+ tf_val2 = tf.random.normal([5]).numpy()
77
+
78
+ assert np.allclose(np_val1, np_val2), "NumPy seed failed to reproduce"
79
+ assert np.allclose(th_val1, th_val2), "PyTorch seed failed to reproduce"
80
+ assert np.allclose(tf_val1, tf_val2), "TensorFlow seed failed to reproduce"
81
+
82
+
83
+ # =========================================================================
84
+ # 2. inspect_tensor tests
85
+ # =========================================================================
86
+
87
+ def test_inspect_tensor_pytorch():
88
+ # Normal tensor
89
+ t = torch.tensor([[1.0, 2.0, 0.0], [4.0, 5.0, 0.0]], dtype=torch.float32)
90
+ info = inspect_tensor(t, name="test_th", print_info=True)
91
+
92
+ assert info["framework"] == "torch"
93
+ assert info["shape"] == (2, 3)
94
+ assert info["dtype"] == "float32"
95
+ assert info["numel"] == 6
96
+ assert info["zeros_count"] == 2
97
+ assert abs(info["sparsity_pct"] - 33.333) < 0.1
98
+ assert info["min"] == 0.0
99
+ assert info["max"] == 5.0
100
+ assert info["has_nan"] is False
101
+ assert info["has_inf"] is False
102
+ assert "p50" in info["quantiles"]
103
+
104
+
105
+ def test_inspect_tensor_pytorch_nan_inf():
106
+ # Tensor with NaN and Inf
107
+ t = torch.tensor([1.0, float('nan'), float('inf'), -float('inf'), 0.0])
108
+ info = inspect_tensor(t, name="nan_inf_th", print_info=False)
109
+
110
+ assert info["has_nan"] is True
111
+ assert info["nan_count"] == 1
112
+ assert info["has_inf"] is True
113
+ assert info["inf_count"] == 2
114
+ assert info["min"] == 0.0
115
+ assert info["max"] == 1.0
116
+
117
+
118
+ def test_inspect_tensor_tensorflow():
119
+ # TF Tensor
120
+ t = tf.constant([[1.0, 2.0], [3.0, 4.0]], dtype=tf.float32)
121
+ info = inspect_tensor(t, name="test_tf", print_info=True)
122
+
123
+ assert info["framework"] == "tensorflow"
124
+ assert info["shape"] == (2, 2)
125
+ assert info["dtype"] == "float32"
126
+ assert info["numel"] == 4
127
+ assert info["min"] == 1.0
128
+ assert info["max"] == 4.0
129
+ assert info["has_nan"] is False
130
+
131
+
132
+ def test_inspect_tensor_tf_variable():
133
+ v = tf.Variable([0.0, 10.0, 20.0], dtype=tf.float32)
134
+ info = inspect_tensor(v, name="var_tf", print_info=False)
135
+
136
+ assert info["framework"] == "tensorflow"
137
+ assert info["numel"] == 3
138
+ assert info["zeros_count"] == 1
139
+
140
+
141
+ def test_inspect_tensor_numpy_and_list():
142
+ arr = np.array([10, 20, 30], dtype=np.int32)
143
+ info = inspect_tensor(arr, name="np_arr", print_info=False)
144
+ assert info["framework"] == "numpy"
145
+ assert info["numel"] == 3
146
+ assert info["dtype"] == "int32"
147
+
148
+ py_list = [1.0, 2.0, 3.0]
149
+ info_list = inspect_tensor(py_list, name="py_list", print_info=False)
150
+ assert info_list["numel"] == 3
151
+
152
+
153
+ # =========================================================================
154
+ # 3. PyTorch freeze / unfreeze / freeze_batchnorm tests
155
+ # =========================================================================
156
+
157
+ def test_pytorch_freeze_and_unfreeze_all():
158
+ model = TorchToyNet()
159
+ total_params = sum(p.numel() for p in model.parameters())
160
+
161
+ # Freeze all
162
+ frozen = freeze_layers(model)
163
+ assert frozen == total_params
164
+ assert all(not p.requires_grad for p in model.parameters())
165
+
166
+ # Unfreeze all
167
+ unfrozen = unfreeze_layers(model)
168
+ assert unfrozen == total_params
169
+ assert all(p.requires_grad for p in model.parameters())
170
+
171
+
172
+ def test_pytorch_freeze_up_to_int():
173
+ model = TorchToyNet()
174
+ # Children in order: conv1, bn1, conv2, bn2, head
175
+ # Freeze first 2: conv1 and bn1
176
+ freeze_layers(model, up_to=2)
177
+
178
+ assert all(not p.requires_grad for p in model.conv1.parameters())
179
+ assert all(not p.requires_grad for p in model.bn1.parameters())
180
+ assert all(p.requires_grad for p in model.conv2.parameters())
181
+ assert all(p.requires_grad for p in model.head.parameters())
182
+
183
+
184
+ def test_pytorch_freeze_up_to_str():
185
+ model = TorchToyNet()
186
+ freeze_layers(model, up_to='conv2')
187
+
188
+ assert all(not p.requires_grad for p in model.conv1.parameters())
189
+ assert all(not p.requires_grad for p in model.bn1.parameters())
190
+ assert all(not p.requires_grad for p in model.conv2.parameters())
191
+ # head should still be trainable
192
+ assert all(p.requires_grad for p in model.head.parameters())
193
+
194
+
195
+ def test_pytorch_unfreeze_last_n():
196
+ model = TorchToyNet()
197
+ freeze_layers(model) # freeze everything
198
+ assert all(not p.requires_grad for p in model.parameters())
199
+
200
+ # Unfreeze only the classification head
201
+ unfreeze_layers(model, last_n=1)
202
+ assert all(p.requires_grad for p in model.head.parameters())
203
+ assert all(not p.requires_grad for p in model.conv1.parameters())
204
+
205
+
206
+ def test_pytorch_freeze_by_types_and_regex():
207
+ model = TorchToyNet()
208
+ # Freeze only Conv2d
209
+ freeze_layers(model, layer_types=(nn.Conv2d,))
210
+ assert all(not p.requires_grad for p in model.conv1.parameters())
211
+ assert all(not p.requires_grad for p in model.conv2.parameters())
212
+ assert all(p.requires_grad for p in model.head.parameters())
213
+ assert all(p.requires_grad for p in model.bn1.parameters())
214
+
215
+ # Unfreeze with regex
216
+ unfreeze_layers(model, regex=r'conv1')
217
+ assert all(p.requires_grad for p in model.conv1.parameters())
218
+ assert all(not p.requires_grad for p in model.conv2.parameters())
219
+
220
+
221
+ def test_pytorch_freeze_batchnorm():
222
+ model = TorchToyNet()
223
+ count = freeze_batchnorm(model, freeze_eval=True)
224
+ assert count == 2 # bn1 and bn2
225
+
226
+ # Affine parameters frozen
227
+ assert model.bn1.weight.requires_grad is False
228
+ assert model.bn1.bias.requires_grad is False
229
+ assert model.bn2.weight.requires_grad is False
230
+ assert model.bn2.bias.requires_grad is False
231
+
232
+ # Calling model.train() should keep BN in eval mode because of pre-hook
233
+ model.train()
234
+ dummy_input = torch.randn(2, 3, 4, 4)
235
+ model(dummy_input)
236
+ assert model.bn1.training is False
237
+ assert model.bn2.training is False
238
+ assert model.conv1.training is True
239
+
240
+
241
+ # =========================================================================
242
+ # 4. TensorFlow freeze / unfreeze / freeze_batchnorm tests
243
+ # =========================================================================
244
+
245
+ def test_tf_freeze_and_unfreeze_all():
246
+ model = create_tf_toy_model()
247
+
248
+ # Freeze all layers
249
+ frozen = freeze_layers(model)
250
+ assert frozen == len(model.layers)
251
+ assert all(not l.trainable for l in model.layers)
252
+
253
+ # Unfreeze all layers
254
+ unfrozen = unfreeze_layers(model)
255
+ assert unfrozen == len(model.layers)
256
+ assert all(l.trainable for l in model.layers)
257
+
258
+
259
+ def test_tf_freeze_up_to_int():
260
+ model = create_tf_toy_model()
261
+ # Freeze first 3 layers (conv1, bn1, relu1)
262
+ freeze_layers(model, up_to=3)
263
+ assert model.layers[0].trainable is False
264
+ assert model.layers[1].trainable is False
265
+ assert model.layers[2].trainable is False
266
+ assert model.layers[3].trainable is True
267
+ assert model.get_layer('head').trainable is True
268
+
269
+
270
+ def test_tf_freeze_up_to_str():
271
+ model = create_tf_toy_model()
272
+ freeze_layers(model, up_to='conv2')
273
+
274
+ assert model.get_layer('conv1').trainable is False
275
+ assert model.get_layer('bn1').trainable is False
276
+ assert model.get_layer('conv2').trainable is False
277
+ assert model.get_layer('head').trainable is True
278
+
279
+
280
+ def test_tf_unfreeze_last_n():
281
+ model = create_tf_toy_model()
282
+ freeze_layers(model) # freeze all
283
+ assert all(not l.trainable for l in model.layers)
284
+
285
+ unfreeze_layers(model, last_n=1)
286
+ assert model.get_layer('head').trainable is True
287
+ assert model.get_layer('conv1').trainable is False
288
+
289
+
290
+ def test_tf_freeze_by_types_and_regex():
291
+ model = create_tf_toy_model()
292
+ freeze_layers(model, layer_types=(keras.layers.Conv2D,))
293
+ assert model.get_layer('conv1').trainable is False
294
+ assert model.get_layer('conv2').trainable is False
295
+ assert model.get_layer('head').trainable is True
296
+
297
+ unfreeze_layers(model, regex=r'conv1')
298
+ assert model.get_layer('conv1').trainable is True
299
+ assert model.get_layer('conv2').trainable is False
300
+
301
+
302
+ def test_tf_freeze_batchnorm():
303
+ model = create_tf_toy_model()
304
+ count = freeze_batchnorm(model)
305
+ assert count == 2 # bn1 and bn2
306
+ assert model.get_layer('bn1').trainable is False
307
+ assert model.get_layer('bn2').trainable is False
308
+ assert model.get_layer('conv1').trainable is True
309
+ assert model.get_layer('head').trainable is True
310
+
311
+
312
+ # =========================================================================
313
+ # 5. Dynamic Dispatch via ToTf top-level
314
+ # =========================================================================
315
+
316
+ def test_totf_dispatcher_integration():
317
+ # 1. seed_everything from top-level
318
+ s = ToTf.seed_everything(999)
319
+ assert s == 999
320
+
321
+ # 2. inspect_tensor with torch
322
+ t_th = torch.randn(4, 4)
323
+ info_th = ToTf.inspect_tensor(t_th, name="disp_th", print_info=False)
324
+ assert info_th["framework"] == "torch"
325
+
326
+ # 3. inspect_tensor with tf
327
+ t_tf = tf.ones([3, 3])
328
+ info_tf = ToTf.inspect_tensor(t_tf, name="disp_tf", print_info=False)
329
+ assert info_tf["framework"] == "tensorflow"
330
+
331
+ # 4. freeze_layers on PyTorch model
332
+ m_th = TorchToyNet()
333
+ assert all(p.requires_grad for p in m_th.parameters())
334
+ ToTf.freeze_layers(m_th)
335
+ assert all(not p.requires_grad for p in m_th.parameters())
336
+ ToTf.unfreeze_layers(m_th)
337
+ assert all(p.requires_grad for p in m_th.parameters())
338
+
339
+ # 5. freeze_layers on Keras model
340
+ m_tf = create_tf_toy_model()
341
+ assert all(l.trainable for l in m_tf.layers)
342
+ ToTf.freeze_layers(m_tf)
343
+ assert all(not l.trainable for l in m_tf.layers)
344
+ ToTf.unfreeze_layers(m_tf)
345
+ assert all(l.trainable for l in m_tf.layers)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes