torch-harness 0.10.1__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 (39) hide show
  1. torch_harness-0.10.1/LICENSE +21 -0
  2. torch_harness-0.10.1/PKG-INFO +236 -0
  3. torch_harness-0.10.1/README.md +204 -0
  4. torch_harness-0.10.1/pyproject.toml +58 -0
  5. torch_harness-0.10.1/pyproject.toml.orig +52 -0
  6. torch_harness-0.10.1/src/torch_harness/__init__.py +27 -0
  7. torch_harness-0.10.1/src/torch_harness/layers/__init__.py +9 -0
  8. torch_harness-0.10.1/src/torch_harness/layers/safe_batch_norm/DEVLOG.md +64 -0
  9. torch_harness-0.10.1/src/torch_harness/layers/safe_batch_norm/README.md +43 -0
  10. torch_harness-0.10.1/src/torch_harness/layers/safe_batch_norm/__init__.py +9 -0
  11. torch_harness-0.10.1/src/torch_harness/layers/safe_batch_norm/safe_batch_norm.py +108 -0
  12. torch_harness-0.10.1/src/torch_harness/lightning/__init__.py +9 -0
  13. torch_harness-0.10.1/src/torch_harness/lightning/fault_tolerant.py +241 -0
  14. torch_harness-0.10.1/src/torch_harness/lightning/file_model_structure.py +58 -0
  15. torch_harness-0.10.1/src/torch_harness/losses/__init__.py +19 -0
  16. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/DEVLOG.md +34 -0
  17. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/README.md +148 -0
  18. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/__init__.py +20 -0
  19. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/config.py +52 -0
  20. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/controller.py +392 -0
  21. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/measurement.py +130 -0
  22. torch_harness-0.10.1/src/torch_harness/losses/adaptive_balancing/numerics.py +25 -0
  23. torch_harness-0.10.1/src/torch_harness/losses/super_loss/DEVLOG.md +46 -0
  24. torch_harness-0.10.1/src/torch_harness/losses/super_loss/README.md +76 -0
  25. torch_harness-0.10.1/src/torch_harness/losses/super_loss/__init__.py +5 -0
  26. torch_harness-0.10.1/src/torch_harness/losses/super_loss/super_loss.py +142 -0
  27. torch_harness-0.10.1/src/torch_harness/losses/uncertainty_weighting/DEVLOG.md +40 -0
  28. torch_harness-0.10.1/src/torch_harness/losses/uncertainty_weighting/README.md +74 -0
  29. torch_harness-0.10.1/src/torch_harness/losses/uncertainty_weighting/__init__.py +7 -0
  30. torch_harness-0.10.1/src/torch_harness/losses/uncertainty_weighting/uncertainty_weighting.py +126 -0
  31. torch_harness-0.10.1/src/torch_harness/onnx/DEVLOG.md +42 -0
  32. torch_harness-0.10.1/src/torch_harness/onnx/README.md +86 -0
  33. torch_harness-0.10.1/src/torch_harness/onnx/__init__.py +6 -0
  34. torch_harness-0.10.1/src/torch_harness/onnx/_io.py +41 -0
  35. torch_harness-0.10.1/src/torch_harness/onnx/_text_graph.py +345 -0
  36. torch_harness-0.10.1/src/torch_harness/py.typed +0 -0
  37. torch_harness-0.10.1/src/torch_harness/runtime/README.md +28 -0
  38. torch_harness-0.10.1/src/torch_harness/runtime/__init__.py +5 -0
  39. torch_harness-0.10.1/src/torch_harness/runtime/replace_layers.py +70 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vadym Stupakov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: torch-harness
3
+ Version: 0.10.1
4
+ Summary: Reliable utilities for PyTorch and Lightning
5
+ Keywords: lightning,machine-learning,pytorch,torch
6
+ Author: Vadym Stupakov
7
+ Author-email: Vadym Stupakov <vadim.stupakov@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Typing :: Typed
20
+ Requires-Dist: jaxtyping>=0.3.11
21
+ Requires-Dist: loguru>=0.7
22
+ Requires-Dist: torch>=2.0
23
+ Requires-Dist: typing-extensions>=4.4
24
+ Requires-Dist: lightning>=2.6,<3 ; extra == 'lightning'
25
+ Requires-Dist: onnx>=1.18 ; extra == 'onnx'
26
+ Requires-Python: >=3.11
27
+ Project-URL: Repository, https://github.com/Red-Eyed/torch-harness
28
+ Project-URL: Issues, https://github.com/Red-Eyed/torch-harness/issues
29
+ Provides-Extra: lightning
30
+ Provides-Extra: onnx
31
+ Description-Content-Type: text/markdown
32
+
33
+ # torch-harness
34
+
35
+ An intentionally uncategorized collection of utilities for PyTorch modeling
36
+ experiments. It is a toolbox rather than a single framework: utilities are added
37
+ as experimental needs arise, without forcing them into an artificial hierarchy.
38
+
39
+ Each utility is modular and self-contained. It owns its implementation and tests,
40
+ avoids assumptions about the surrounding project, and can be used independently
41
+ of the other utilities. Optional framework integrations remain isolated so they
42
+ do not add dependencies to the core package.
43
+
44
+ ## Adaptive loss balancing
45
+
46
+ `LossBalancer` adapts named auxiliary weights from shared gradient norms while
47
+ keeping the primary loss weight exactly one:
48
+
49
+ ```python
50
+ from torch_harness.losses import LossBalancer, LossTarget, weighted_loss
51
+
52
+ balancer = LossBalancer(
53
+ reference="primary",
54
+ adaptive={"auxiliary": LossTarget(ratio=0.3, initial_weight=0.1)},
55
+ )
56
+ weights = balancer.update(losses, shared=shared_features, step=global_step)
57
+ total_loss = weighted_loss(losses, weights)
58
+ ```
59
+
60
+ It supports independent targets, fixed weights, optional losses, periodic EMA
61
+ updates, checkpoint continuation, and synchronized DDP activation measurements.
62
+ See the [component documentation](src/torch_harness/losses/adaptive_balancing/README.md)
63
+ for stability controls, diagnostics, and training integration. Run
64
+ `uv run examples/adaptive_loss_balancing.py` for a synthetic optimization example.
65
+
66
+ ## Uncertainty weighting
67
+
68
+ `UncertaintyWeighting` learns positive weights for a vector of peer task losses:
69
+
70
+ ```python
71
+ import torch
72
+
73
+ from torch_harness.losses import UncertaintyWeighting
74
+
75
+ weighting = UncertaintyWeighting(num_tasks=3)
76
+ task_losses = torch.stack((classification_loss, depth_loss, normal_loss))
77
+ loss = weighting(task_losses)
78
+ weights_for_logging = weighting.effective_weights
79
+ ```
80
+
81
+ Each effective weight starts near one and adapts jointly with the model. The
82
+ module preserves gradients to the input task losses and its uncertainty
83
+ parameters, while the weights exposed for logging are detached. See the
84
+ [component documentation](src/torch_harness/losses/uncertainty_weighting/README.md)
85
+ for the exact objective, optimizer wiring, numerical behavior, and limitations.
86
+
87
+ ## SuperLoss
88
+
89
+ `SuperLoss` applies robust curriculum weighting to any unreduced task loss:
90
+
91
+ ```python
92
+ from math import log
93
+
94
+ import torch.nn.functional as F
95
+
96
+ from torch_harness.losses import SuperLoss
97
+
98
+ criterion = SuperLoss(threshold=log(10), regularization=1.0)
99
+ task_loss = F.cross_entropy(logits, targets, reduction="none")
100
+ loss = criterion(task_loss)
101
+ ```
102
+
103
+ It computes the closed-form optimal sample confidence from the SuperLoss paper,
104
+ upweighting easy samples and downweighting hard samples. The implementation is
105
+ task-agnostic, runs entirely in PyTorch, and has no SciPy or per-sample-state
106
+ dependency. See the [component documentation](src/torch_harness/losses/super_loss/README.md)
107
+ for parameter guidance and numerical details.
108
+
109
+ ## SafeBatchNorm
110
+
111
+ `SafeBatchNorm` rejects a non-finite activation before it can corrupt BatchNorm
112
+ running statistics.
113
+
114
+ ```python
115
+ from torch_harness.layers import SafeBatchNorm2d
116
+
117
+ normalization = SafeBatchNorm2d(64)
118
+ ```
119
+
120
+ `SafeBatchNorm1d`, `SafeBatchNorm2d`, and `SafeBatchNorm3d` directly inherit
121
+ their matching PyTorch classes. They retain the native constructor, state-dict
122
+ layout, and type identity. A non-finite input raises `FloatingPointError`, which
123
+ a fault-tolerant training loop can catch to skip the step.
124
+
125
+ `nn.SyncBatchNorm` is intentionally unsupported because a rank-local failure
126
+ before its collective could deadlock the other ranks.
127
+
128
+ ## Runtime layer replacement
129
+
130
+ `replace_layers` recursively transforms existing models through an explicit
131
+ replacement factory:
132
+
133
+ ```python
134
+ from torch import nn
135
+
136
+ from torch_harness.runtime import replace_layers
137
+
138
+ model = replace_layers(
139
+ model,
140
+ old_layer_cls=nn.SiLU,
141
+ replacement_factory=lambda silu: nn.ReLU(inplace=silu.inplace),
142
+ )
143
+ ```
144
+
145
+ The traversal includes nested containers such as `Sequential`. Run replacement
146
+ before constructing the optimizer, distributed wrappers, or a compiled model.
147
+
148
+ ## Fault-tolerant training steps
149
+
150
+ `FaultTolerantTrainingStep` skips occasional exceptions and NaN or infinite losses
151
+ before Lightning automatic optimization runs backward or updates the optimizer:
152
+
153
+ ```python
154
+ from datetime import timedelta
155
+
156
+ from lightning.pytorch import Trainer
157
+ from torch_harness.lightning import FaultTolerantTrainingStep
158
+
159
+ fault_tolerance = FaultTolerantTrainingStep(
160
+ max_faults=3,
161
+ fault_window=timedelta(hours=1),
162
+ )
163
+ trainer = Trainer(callbacks=[fault_tolerance])
164
+ ```
165
+
166
+ This example skips the first three faults in any rolling one-hour window. A fourth
167
+ fault within that window is logged through Loguru and propagated. Exceptions retain
168
+ their original type and traceback; repeated non-finite losses raise
169
+ `NonFiniteLossError`.
170
+
171
+ Install the Lightning integration with `torch-harness[lightning]`.
172
+
173
+ The callback intentionally supports only single-process automatic optimization.
174
+ Errors raised during backward or `optimizer.step` happen after the recoverable
175
+ boundary and are propagated because an optimizer update may already be partial.
176
+
177
+ ## Model structures in files
178
+
179
+ `FileModelStructure` saves the recursive structure produced by `print(model)` as
180
+ readable UTF-8 text when fitting starts:
181
+
182
+ ```python
183
+ from pathlib import Path
184
+
185
+ from lightning.pytorch import Trainer
186
+ from torch_harness.lightning import FileModelStructure
187
+
188
+ structure = FileModelStructure(
189
+ output_path=Path("artifacts/model-structure.txt"),
190
+ )
191
+ trainer = Trainer(callbacks=[structure])
192
+ ```
193
+
194
+ The callback includes the complete registered module hierarchy without requiring
195
+ example inputs or running a forward pass. It creates parent directories, replaces
196
+ an existing structure file, and writes only from the global-zero process. Runtime
197
+ tensor operations that are not registered modules do not appear.
198
+
199
+ Run `uv run examples/file_model_structure.py` to generate an inspectable example
200
+ at `examples/model-structure.txt`.
201
+
202
+ ## Human-readable ONNX graphs
203
+
204
+ Install `torch-harness[onnx]` to save module summaries suitable for Git diffs
205
+ and Meld:
206
+
207
+ ```python
208
+ from pathlib import Path
209
+
210
+ import onnx
211
+
212
+ from torch_harness.onnx import write_text_graph
213
+
214
+ model = onnx.load("model.onnx")
215
+ write_text_graph(model, Path("artifacts/model.onnx.txt"))
216
+ ```
217
+
218
+ Summaries show operation signatures and counts, attributes, small constants,
219
+ parameter shapes, and input/output dimensions. They omit temporary node indexes
220
+ and weight payloads, making RMSNorm decomposition versus `RMSNormalization`
221
+ visible without renumbering unrelated operations. Internal wiring is omitted.
222
+
223
+ See the [ONNX documentation](src/torch_harness/onnx/README.md) for source module
224
+ capture, shape inference, and format limitations. Run
225
+ `uv run --extra onnx examples/onnx_text_graph.py` for a small example.
226
+
227
+ ## Planned utilities
228
+
229
+ - A Lightning `PreciseBN` callback for recomputing BatchNorm running statistics.
230
+ - A Lightning mixin that manages schedule-free AdamW train/evaluation state.
231
+
232
+ Each integration will be isolated so users only install the frameworks they need.
233
+
234
+ ## License
235
+
236
+ `torch-harness` is released under the MIT License.
@@ -0,0 +1,204 @@
1
+ # torch-harness
2
+
3
+ An intentionally uncategorized collection of utilities for PyTorch modeling
4
+ experiments. It is a toolbox rather than a single framework: utilities are added
5
+ as experimental needs arise, without forcing them into an artificial hierarchy.
6
+
7
+ Each utility is modular and self-contained. It owns its implementation and tests,
8
+ avoids assumptions about the surrounding project, and can be used independently
9
+ of the other utilities. Optional framework integrations remain isolated so they
10
+ do not add dependencies to the core package.
11
+
12
+ ## Adaptive loss balancing
13
+
14
+ `LossBalancer` adapts named auxiliary weights from shared gradient norms while
15
+ keeping the primary loss weight exactly one:
16
+
17
+ ```python
18
+ from torch_harness.losses import LossBalancer, LossTarget, weighted_loss
19
+
20
+ balancer = LossBalancer(
21
+ reference="primary",
22
+ adaptive={"auxiliary": LossTarget(ratio=0.3, initial_weight=0.1)},
23
+ )
24
+ weights = balancer.update(losses, shared=shared_features, step=global_step)
25
+ total_loss = weighted_loss(losses, weights)
26
+ ```
27
+
28
+ It supports independent targets, fixed weights, optional losses, periodic EMA
29
+ updates, checkpoint continuation, and synchronized DDP activation measurements.
30
+ See the [component documentation](src/torch_harness/losses/adaptive_balancing/README.md)
31
+ for stability controls, diagnostics, and training integration. Run
32
+ `uv run examples/adaptive_loss_balancing.py` for a synthetic optimization example.
33
+
34
+ ## Uncertainty weighting
35
+
36
+ `UncertaintyWeighting` learns positive weights for a vector of peer task losses:
37
+
38
+ ```python
39
+ import torch
40
+
41
+ from torch_harness.losses import UncertaintyWeighting
42
+
43
+ weighting = UncertaintyWeighting(num_tasks=3)
44
+ task_losses = torch.stack((classification_loss, depth_loss, normal_loss))
45
+ loss = weighting(task_losses)
46
+ weights_for_logging = weighting.effective_weights
47
+ ```
48
+
49
+ Each effective weight starts near one and adapts jointly with the model. The
50
+ module preserves gradients to the input task losses and its uncertainty
51
+ parameters, while the weights exposed for logging are detached. See the
52
+ [component documentation](src/torch_harness/losses/uncertainty_weighting/README.md)
53
+ for the exact objective, optimizer wiring, numerical behavior, and limitations.
54
+
55
+ ## SuperLoss
56
+
57
+ `SuperLoss` applies robust curriculum weighting to any unreduced task loss:
58
+
59
+ ```python
60
+ from math import log
61
+
62
+ import torch.nn.functional as F
63
+
64
+ from torch_harness.losses import SuperLoss
65
+
66
+ criterion = SuperLoss(threshold=log(10), regularization=1.0)
67
+ task_loss = F.cross_entropy(logits, targets, reduction="none")
68
+ loss = criterion(task_loss)
69
+ ```
70
+
71
+ It computes the closed-form optimal sample confidence from the SuperLoss paper,
72
+ upweighting easy samples and downweighting hard samples. The implementation is
73
+ task-agnostic, runs entirely in PyTorch, and has no SciPy or per-sample-state
74
+ dependency. See the [component documentation](src/torch_harness/losses/super_loss/README.md)
75
+ for parameter guidance and numerical details.
76
+
77
+ ## SafeBatchNorm
78
+
79
+ `SafeBatchNorm` rejects a non-finite activation before it can corrupt BatchNorm
80
+ running statistics.
81
+
82
+ ```python
83
+ from torch_harness.layers import SafeBatchNorm2d
84
+
85
+ normalization = SafeBatchNorm2d(64)
86
+ ```
87
+
88
+ `SafeBatchNorm1d`, `SafeBatchNorm2d`, and `SafeBatchNorm3d` directly inherit
89
+ their matching PyTorch classes. They retain the native constructor, state-dict
90
+ layout, and type identity. A non-finite input raises `FloatingPointError`, which
91
+ a fault-tolerant training loop can catch to skip the step.
92
+
93
+ `nn.SyncBatchNorm` is intentionally unsupported because a rank-local failure
94
+ before its collective could deadlock the other ranks.
95
+
96
+ ## Runtime layer replacement
97
+
98
+ `replace_layers` recursively transforms existing models through an explicit
99
+ replacement factory:
100
+
101
+ ```python
102
+ from torch import nn
103
+
104
+ from torch_harness.runtime import replace_layers
105
+
106
+ model = replace_layers(
107
+ model,
108
+ old_layer_cls=nn.SiLU,
109
+ replacement_factory=lambda silu: nn.ReLU(inplace=silu.inplace),
110
+ )
111
+ ```
112
+
113
+ The traversal includes nested containers such as `Sequential`. Run replacement
114
+ before constructing the optimizer, distributed wrappers, or a compiled model.
115
+
116
+ ## Fault-tolerant training steps
117
+
118
+ `FaultTolerantTrainingStep` skips occasional exceptions and NaN or infinite losses
119
+ before Lightning automatic optimization runs backward or updates the optimizer:
120
+
121
+ ```python
122
+ from datetime import timedelta
123
+
124
+ from lightning.pytorch import Trainer
125
+ from torch_harness.lightning import FaultTolerantTrainingStep
126
+
127
+ fault_tolerance = FaultTolerantTrainingStep(
128
+ max_faults=3,
129
+ fault_window=timedelta(hours=1),
130
+ )
131
+ trainer = Trainer(callbacks=[fault_tolerance])
132
+ ```
133
+
134
+ This example skips the first three faults in any rolling one-hour window. A fourth
135
+ fault within that window is logged through Loguru and propagated. Exceptions retain
136
+ their original type and traceback; repeated non-finite losses raise
137
+ `NonFiniteLossError`.
138
+
139
+ Install the Lightning integration with `torch-harness[lightning]`.
140
+
141
+ The callback intentionally supports only single-process automatic optimization.
142
+ Errors raised during backward or `optimizer.step` happen after the recoverable
143
+ boundary and are propagated because an optimizer update may already be partial.
144
+
145
+ ## Model structures in files
146
+
147
+ `FileModelStructure` saves the recursive structure produced by `print(model)` as
148
+ readable UTF-8 text when fitting starts:
149
+
150
+ ```python
151
+ from pathlib import Path
152
+
153
+ from lightning.pytorch import Trainer
154
+ from torch_harness.lightning import FileModelStructure
155
+
156
+ structure = FileModelStructure(
157
+ output_path=Path("artifacts/model-structure.txt"),
158
+ )
159
+ trainer = Trainer(callbacks=[structure])
160
+ ```
161
+
162
+ The callback includes the complete registered module hierarchy without requiring
163
+ example inputs or running a forward pass. It creates parent directories, replaces
164
+ an existing structure file, and writes only from the global-zero process. Runtime
165
+ tensor operations that are not registered modules do not appear.
166
+
167
+ Run `uv run examples/file_model_structure.py` to generate an inspectable example
168
+ at `examples/model-structure.txt`.
169
+
170
+ ## Human-readable ONNX graphs
171
+
172
+ Install `torch-harness[onnx]` to save module summaries suitable for Git diffs
173
+ and Meld:
174
+
175
+ ```python
176
+ from pathlib import Path
177
+
178
+ import onnx
179
+
180
+ from torch_harness.onnx import write_text_graph
181
+
182
+ model = onnx.load("model.onnx")
183
+ write_text_graph(model, Path("artifacts/model.onnx.txt"))
184
+ ```
185
+
186
+ Summaries show operation signatures and counts, attributes, small constants,
187
+ parameter shapes, and input/output dimensions. They omit temporary node indexes
188
+ and weight payloads, making RMSNorm decomposition versus `RMSNormalization`
189
+ visible without renumbering unrelated operations. Internal wiring is omitted.
190
+
191
+ See the [ONNX documentation](src/torch_harness/onnx/README.md) for source module
192
+ capture, shape inference, and format limitations. Run
193
+ `uv run --extra onnx examples/onnx_text_graph.py` for a small example.
194
+
195
+ ## Planned utilities
196
+
197
+ - A Lightning `PreciseBN` callback for recomputing BatchNorm running statistics.
198
+ - A Lightning mixin that manages schedule-free AdamW train/evaluation state.
199
+
200
+ Each integration will be isolated so users only install the frameworks they need.
201
+
202
+ ## License
203
+
204
+ `torch-harness` is released under the MIT License.
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "torch-harness"
3
+ version = "0.10.1"
4
+ description = "Reliable utilities for PyTorch and Lightning"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "jaxtyping>=0.3.11",
9
+ "loguru>=0.7",
10
+ "torch>=2.0",
11
+ "typing-extensions>=4.4",
12
+ ]
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Intended Audience :: Science/Research",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Typing :: Typed",
26
+ ]
27
+ keywords = [
28
+ "lightning",
29
+ "machine-learning",
30
+ "pytorch",
31
+ "torch",
32
+ ]
33
+
34
+ [[project.authors]]
35
+ name = "Vadym Stupakov"
36
+ email = "vadim.stupakov@gmail.com"
37
+
38
+ [project.optional-dependencies]
39
+ lightning = ["lightning>=2.6,<3"]
40
+ onnx = ["onnx>=1.18"]
41
+
42
+ [project.urls]
43
+ Repository = "https://github.com/Red-Eyed/torch-harness"
44
+ Issues = "https://github.com/Red-Eyed/torch-harness/issues"
45
+
46
+ [build-system]
47
+ requires = ["uv_build>=0.12.1,<0.13.0"]
48
+ build-backend = "uv_build"
49
+
50
+ [dependency-groups]
51
+ dev = [
52
+ "lightning>=2.6,<3",
53
+ "onnx>=1.18",
54
+ "pyrefly>=1.2.0",
55
+ "pytest>=9.1.1",
56
+ "ruff>=0.16.4",
57
+ "scipy>=1.17.1",
58
+ ]
@@ -0,0 +1,52 @@
1
+ [project]
2
+ name = "torch-harness"
3
+ version = "0.10.1"
4
+ description = "Reliable utilities for PyTorch and Lightning"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Vadym Stupakov", email = "vadim.stupakov@gmail.com" },
8
+ ]
9
+ requires-python = ">=3.11"
10
+ dependencies = [
11
+ "jaxtyping>=0.3.11",
12
+ "loguru>=0.7",
13
+ "torch>=2.0",
14
+ "typing-extensions>=4.4",
15
+ ]
16
+ license = "MIT"
17
+ license-files = ["LICENSE"]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: Science/Research",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Typing :: Typed",
29
+ ]
30
+ keywords = ["lightning", "machine-learning", "pytorch", "torch"]
31
+
32
+ [project.optional-dependencies]
33
+ lightning = ["lightning>=2.6,<3"]
34
+ onnx = ["onnx>=1.18"]
35
+
36
+ [project.urls]
37
+ Repository = "https://github.com/Red-Eyed/torch-harness"
38
+ Issues = "https://github.com/Red-Eyed/torch-harness/issues"
39
+
40
+ [build-system]
41
+ requires = ["uv_build>=0.12.1,<0.13.0"]
42
+ build-backend = "uv_build"
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "lightning>=2.6,<3",
47
+ "onnx>=1.18",
48
+ "pyrefly>=1.2.0",
49
+ "pytest>=9.1.1",
50
+ "ruff>=0.16.4",
51
+ "scipy>=1.17.1",
52
+ ]
@@ -0,0 +1,27 @@
1
+ """Reliable utilities for PyTorch and Lightning."""
2
+
3
+ from torch_harness.layers import (
4
+ SafeBatchNorm1d,
5
+ SafeBatchNorm2d,
6
+ SafeBatchNorm3d,
7
+ )
8
+ from torch_harness.losses import (
9
+ BalancerConfig,
10
+ LossBalancer,
11
+ LossTarget,
12
+ SuperLoss,
13
+ UncertaintyWeighting,
14
+ weighted_loss,
15
+ )
16
+
17
+ __all__ = [
18
+ "BalancerConfig",
19
+ "LossBalancer",
20
+ "LossTarget",
21
+ "SafeBatchNorm1d",
22
+ "SafeBatchNorm2d",
23
+ "SafeBatchNorm3d",
24
+ "SuperLoss",
25
+ "UncertaintyWeighting",
26
+ "weighted_loss",
27
+ ]
@@ -0,0 +1,9 @@
1
+ """Reliable neural-network layers."""
2
+
3
+ from torch_harness.layers.safe_batch_norm import (
4
+ SafeBatchNorm1d,
5
+ SafeBatchNorm2d,
6
+ SafeBatchNorm3d,
7
+ )
8
+
9
+ __all__ = ["SafeBatchNorm1d", "SafeBatchNorm2d", "SafeBatchNorm3d"]
@@ -0,0 +1,64 @@
1
+ # SafeBatchNorm development log
2
+
3
+ ## 0.3.0
4
+
5
+ ### Motivating observation
6
+
7
+ Models often already contain native BatchNorm layers when fault-tolerant
8
+ training is enabled. Runtime conversion should not rely on changing an
9
+ instance's `__class__`, which skips construction and couples correctness to
10
+ Python object-layout details.
11
+
12
+ ### Decision
13
+
14
+ Add explicit `from_batch_norm` constructors that rebuild each safe layer from
15
+ the corresponding native BatchNorm configuration and persistent state. The
16
+ conversion also preserves training mode and affine-parameter `requires_grad`
17
+ settings. Runtime traversal remains independent through a replacement factory.
18
+
19
+ ### Verified result
20
+
21
+ Parameterized tests verify that BatchNorm1d, BatchNorm2d, and BatchNorm3d are
22
+ rebuilt as distinct safe instances with equivalent configuration, parameters,
23
+ running statistics, training mode, device, dtype, and `requires_grad` settings.
24
+ The runtime integration also converts nested native BatchNorm layers without
25
+ changing the traversal implementation.
26
+
27
+ ### Unproven claims
28
+
29
+ The per-layer scalar check introduces a device-to-host synchronization on
30
+ accelerators; its training-throughput cost has not been benchmarked.
31
+
32
+ ## 0.2.0
33
+
34
+ ### Motivating observation
35
+
36
+ A fault-tolerant training loop can reject non-finite model outputs, but that
37
+ check occurs after BatchNorm has already updated its persistent running state
38
+ from the faulty activation.
39
+
40
+ ### Decision
41
+
42
+ Directly inherit BatchNorm1d, BatchNorm2d, and BatchNorm3d, and raise
43
+ `FloatingPointError` when a shared pre-forward input check finds a NaN or
44
+ infinity. Checking before BatchNorm prevents any running-state mutation and
45
+ leaves PyTorch's forward and backward implementations untouched for finite
46
+ inputs. Inheritance preserves native constructors, state-dict keys, and type
47
+ identity.
48
+
49
+ Use an explicit exception rather than `assert`, because optimized Python can
50
+ remove assertions. Synchronized BatchNorm is excluded because a rank-local
51
+ early failure could deadlock peers already entering its collective.
52
+
53
+ ### Verified result
54
+
55
+ Parameterized tests against BatchNorm1d, BatchNorm2d, and BatchNorm3d verify
56
+ that finite outputs, running-state updates, input gradients, and affine
57
+ parameter gradients match native BatchNorm. NaN and infinity inputs raise
58
+ before the running mean, running variance, or batch counter changes. Evaluation
59
+ mode and disabled running statistics are covered as well.
60
+
61
+ ### Unproven claims
62
+
63
+ The per-layer scalar check introduces a device-to-host synchronization on
64
+ accelerators; its training-throughput cost has not been benchmarked.