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.
- {totf-0.2.5 → totf-0.2.6}/PKG-INFO +16 -1
- {totf-0.2.5 → totf-0.2.6}/README.md +15 -0
- {totf-0.2.5 → totf-0.2.6}/ToTf/__init__.py +23 -2
- {totf-0.2.5 → totf-0.2.6}/ToTf/backend_manager.py +75 -1
- {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/PKG-INFO +16 -1
- {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/SOURCES.txt +1 -0
- {totf-0.2.5 → totf-0.2.6}/pyproject.toml +1 -1
- {totf-0.2.5 → totf-0.2.6}/setup.py +1 -1
- totf-0.2.6/test/test_phase1_utils.py +345 -0
- {totf-0.2.5 → totf-0.2.6}/LICENSE +0 -0
- {totf-0.2.5 → totf-0.2.6}/ToTf/backend.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/dependency_links.txt +0 -0
- {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/requires.txt +0 -0
- {totf-0.2.5 → totf-0.2.6}/ToTf.egg-info/top_level.txt +0 -0
- {totf-0.2.5 → totf-0.2.6}/setup.cfg +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_connection_api.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_connections_visual.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_integration.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_modelview_quick.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_modelview_tf.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_monitor.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_onnx_pytorch.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_onnx_tensorflow.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_pytorch_modelview_quick.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary_features.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_smartsummary_tf.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_utils_integration.py +0 -0
- {totf-0.2.5 → totf-0.2.6}/test/test_utils_pytorch.py +0 -0
- {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.
|
|
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.
|
|
17
|
+
__version__ = "0.2.6"
|
|
11
18
|
__author__ = "Akshay"
|
|
12
|
-
__all__ = [
|
|
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
|
|
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.
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ToTf"
|
|
7
|
-
version = "0.2.
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|