spatial-frequency-loss 1.0.1__py3-none-any.whl

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.
@@ -0,0 +1,460 @@
1
+ Metadata-Version: 2.4
2
+ Name: spatial-frequency-loss
3
+ Version: 1.0.1
4
+ Summary: Spatial Frequency Loss for mitigating spectral bias in deep neural networks
5
+ Author-email: Naoyuki Ichimura <naoyuki.ichimura@aist.go.jp>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://naoyukiichimura.github.io/spatial-frequency-loss/
8
+ Project-URL: Repository, https://github.com/NaoyukiIchimura/spatial-frequency-loss
9
+ Project-URL: Documentation, https://naoyukiichimura.github.io/spatial-frequency-loss/
10
+ Project-URL: Issues, https://github.com/NaoyukiIchimura/spatial-frequency-loss/issues
11
+ Project-URL: Paper, https://doi.org/10.1007/s00138-026-01927-5
12
+ Project-URL: Corrections, https://naoyukiichimura.github.io/spatial-frequency-loss/corrections.html
13
+ Keywords: deep-learning,image-reconstruction,loss-function,pytorch,spatial-frequency,spectral-bias
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy
25
+ Requires-Dist: torch
26
+ Dynamic: license-file
27
+
28
+ # Spatial Frequency Loss
29
+
30
+ Spatial Frequency Loss (the SFL) is a subband-aware loss designed to mitigate
31
+ spectral bias in deep neural networks and improve the learning of fine-scale
32
+ image structures. The SFL measures reconstruction errors in overlapping
33
+ spatial-frequency subbands produced by a Difference-of-Gaussians filter bank.
34
+
35
+ - [Project page](https://naoyukiichimura.github.io/spatial-frequency-loss/)
36
+ - [Paper](https://doi.org/10.1007/s00138-026-01927-5)
37
+ - [View-only full text](https://rdcu.be/XSJ786PqnMca)
38
+ - [Supplementary material](https://media.springernature.com/original/springer-static/esm/art%3A10.1007%2Fs00138-026-01927-5/MediaObjects/138_2026_1927_MOESM1_ESM.pdf)
39
+ - [Post-publication corrections](https://naoyukiichimura.github.io/spatial-frequency-loss/corrections.html)
40
+
41
+ ## Key features
42
+
43
+ - **Frequency-selective measurements:** A Difference-of-Gaussians filter bank
44
+ measures discrepancies between corresponding spatial-frequency responses of
45
+ output and target images.
46
+ - **Data-driven subband weighting:** The Inverse Error Ratio (IER)
47
+ determines the subband weights automatically from the training data.
48
+ - **Fidelity-oriented learning:** The SFL does not require adversarial training or
49
+ nonlinear features from a pre-trained model. In the evaluated experiments,
50
+ the SFL improved fine-scale image structures without introducing noticeable
51
+ additional artifacts.
52
+ - **Minimal integration:** The SFL is implemented as a regular PyTorch module. Existing model
53
+ architectures, data loaders, optimizers, and training loops require only
54
+ small, localized additions.
55
+ - **Efficient default backend:** Separable filtering is the recommended default
56
+ backend. The original two-dimensional convolution backend remains available
57
+ for compatibility and numerical validation.
58
+
59
+ The fidelity-oriented design of the SFL may be particularly valuable when artificially
60
+ generated structures are undesirable, including potential applications in
61
+ medical imaging and physics-based image processing.
62
+
63
+ ## Requirements
64
+
65
+ The public implementation uses:
66
+
67
+ - Python
68
+ - PyTorch
69
+ - NumPy
70
+
71
+ Use versions compatible with the PyTorch environment of the target project.
72
+
73
+ ## Installation
74
+
75
+ ### Install from PyPI
76
+
77
+ For most users, install the released package from PyPI:
78
+
79
+ ```bash
80
+ python3 -m pip install spatial-frequency-loss
81
+ ```
82
+
83
+ ### Install from GitHub
84
+
85
+ To use the source code, tests, and documentation from GitHub, clone the
86
+ repository and install it in editable mode:
87
+
88
+ ```bash
89
+ git clone https://github.com/NaoyukiIchimura/spatial-frequency-loss.git
90
+ cd spatial-frequency-loss
91
+ python3 -m pip install -e .
92
+ ```
93
+
94
+ Alternatively, `spatial_frequency_loss.py` can be copied directly into an
95
+ existing project when a local single-file integration is preferred.
96
+
97
+ ## Quick start
98
+
99
+ The following example shows the simplest workflow in which the SFL automatically
100
+ determines the subband weights using the IER before training.
101
+
102
+ ### 1. Import the SFL
103
+
104
+ ```python
105
+ import torch
106
+
107
+ from spatial_frequency_loss import SpatialFrequencyLoss
108
+ ```
109
+
110
+ ### 2. Initialize the SFL
111
+
112
+ ```python
113
+ sfl = SpatialFrequencyLoss(
114
+ num_image_channels=3,
115
+ base_scale=0.6,
116
+ num_subbands=7,
117
+ ier_update_mode="calibration",
118
+ ).to(device)
119
+
120
+ mse_loss = torch.nn.MSELoss()
121
+ ```
122
+
123
+ `ier_update_mode="calibration"` is written explicitly for clarity, although
124
+ `"calibration"` is the default update mode for the IER. The default filter backend is
125
+ `"separable"`. The values `base_scale=0.6` and `num_subbands=7` match the
126
+ published experiments for RGB images.
127
+
128
+ ### 3. Determine the subband weights using the IER
129
+
130
+ ```python
131
+ model.eval()
132
+ sfl.eval()
133
+
134
+ with torch.no_grad():
135
+ for inputs, targets in training_loader:
136
+ inputs = inputs.to(device)
137
+ targets = targets.to(device)
138
+
139
+ outputs = model(inputs)
140
+
141
+ sfl.accumulate_calibration_ier(
142
+ outputs,
143
+ targets,
144
+ )
145
+
146
+ sfl.finalize_ier_calibration()
147
+ ```
148
+
149
+ The model forward pass and DataLoader traversal remain responsibilities of the
150
+ training program. The same training data are used for this forward-only pass for the IER,
151
+ and model parameters are
152
+ not updated. `accumulate_calibration_ier()` collects the IER statistics, and
153
+ `finalize_ier_calibration()` sets the subband weights from the accumulated
154
+ statistics.
155
+
156
+ ### 4. Train the model with the SFL
157
+
158
+ ```python
159
+ model.train()
160
+ sfl.train()
161
+
162
+ for epoch in range(num_epochs):
163
+ for inputs, targets in train_loader:
164
+ inputs = inputs.to(device)
165
+ targets = targets.to(device)
166
+
167
+ optimizer.zero_grad()
168
+
169
+ outputs = model(inputs)
170
+
171
+ l2_loss = mse_loss(
172
+ outputs,
173
+ targets,
174
+ )
175
+
176
+ (
177
+ subband_losses,
178
+ weighted_sfl,
179
+ _,
180
+ _,
181
+ _,
182
+ ) = sfl(
183
+ outputs,
184
+ targets,
185
+ )
186
+
187
+ total_loss = l2_loss + weighted_sfl
188
+
189
+ total_loss.backward()
190
+ optimizer.step()
191
+ ```
192
+
193
+ The calibration step determines the subband weights only. During optimization,
194
+ the weighted SFL is simply added to the existing pixel-wise L2 loss.
195
+
196
+ ## IER calibration workflow
197
+
198
+ 1. Construct SFL with `ier_update_mode="calibration"`.
199
+ 2. Set the model and the SFL module to evaluation mode.
200
+ 3. Traverse the training data without gradient computation or optimizer
201
+ updates.
202
+ 4. Pass each output-target pair to `accumulate_calibration_ier()`.
203
+ 5. Call `finalize_ier_calibration()` once after the complete calibration pass.
204
+ 6. Start normal optimization and call the SFL through `forward()`.
205
+
206
+ The default `ier_reduction="sample"` computes one IER vector per sample and
207
+ averages the vectors over all training samples. The alternative
208
+ `ier_reduction="batch"` computes one vector from the batch-mean losses and
209
+ averages the vectors across calibration batches.
210
+
211
+ After `finalize_ier_calibration()` has been called, the calibrated weights are
212
+ fixed during optimization. To repeat calibration, construct a new SFL module.
213
+
214
+ ## Initialization parameters
215
+
216
+ | Parameter | Default | Description |
217
+ |---|---:|---|
218
+ | `num_image_channels` | Required | Number of image channels. |
219
+ | `base_scale` | Required | Base Gaussian scale. The published RGB experiments used `0.6`. |
220
+ | `num_subbands` | Required | Number of the SFL subbands. The published experiments used `7`. |
221
+ | `scale_radix` | `2.0` | Ratio between adjacent Gaussian scales. |
222
+ | `filter_size_factor` | `8.0` | Factor used to determine each finite filter size. |
223
+ | `filter_backend` | `"separable"` | `"separable"` is recommended; `"conv2d"` is retained for compatibility and validation. |
224
+ | `ier_update_mode` | `"calibration"` | `"calibration"` determines weights from a forward-only pass; `"fixed"` uses supplied weights. |
225
+ | `ier_reduction` | `"sample"` | Averages sample-wise or batch-wise IER vectors. |
226
+ | `eps` | `1.0e-12` | Positive lower bound for IER denominators. |
227
+ | `subband_weights` | `None` | Explicit weights. Required when `ier_update_mode="fixed"`. |
228
+ | `normalize_gaussian` | `False` | Whether each finite Gaussian kernel is normalized to sum to one. |
229
+
230
+ ### Explicitly fixed subband weights
231
+
232
+ Use fixed mode when the subband weights are already known.
233
+
234
+ ```python
235
+ sfl = SpatialFrequencyLoss(
236
+ num_image_channels=3,
237
+ base_scale=0.6,
238
+ num_subbands=7,
239
+ ier_update_mode="fixed",
240
+ subband_weights=[
241
+ weight_sb1,
242
+ weight_sb2,
243
+ weight_sb3,
244
+ weight_sb4,
245
+ weight_sb5,
246
+ weight_sb6,
247
+ weight_sb7,
248
+ ],
249
+ ).to(device)
250
+ ```
251
+
252
+ To observe how another loss function changes the subband losses without adding
253
+ the SFL to the optimization objective, use fixed mode with all subband weights
254
+ set to zero. The returned `weighted_sfl` is then zero, while the returned
255
+ `subband_losses` remain available for monitoring.
256
+
257
+ ```python
258
+ sfl_for_monitoring = SpatialFrequencyLoss(
259
+ num_image_channels=3,
260
+ base_scale=0.6,
261
+ num_subbands=7,
262
+ ier_update_mode="fixed",
263
+ subband_weights=[
264
+ 0.0,
265
+ 0.0,
266
+ 0.0,
267
+ 0.0,
268
+ 0.0,
269
+ 0.0,
270
+ 0.0,
271
+ ],
272
+ ).to(device)
273
+
274
+ (
275
+ subband_losses,
276
+ weighted_sfl,
277
+ _,
278
+ _,
279
+ _,
280
+ ) = sfl_for_monitoring(
281
+ outputs,
282
+ targets,
283
+ )
284
+ ```
285
+
286
+ In this monitoring configuration, optimize the model with the other loss
287
+ function only and record `subband_losses` to analyze the spatial-frequency error
288
+ in each subband.
289
+
290
+ ## Return values
291
+
292
+ Calling the SFL returns five values:
293
+
294
+ ```python
295
+ (
296
+ subband_losses,
297
+ weighted_sfl,
298
+ output_subbands,
299
+ target_subbands,
300
+ active_weights,
301
+ ) = sfl(
302
+ outputs,
303
+ targets,
304
+ )
305
+ ```
306
+
307
+ - `subband_losses`: one batch-mean L2 loss per subband.
308
+ - `weighted_sfl`: scalar weighted sum of the subband losses.
309
+ - `output_subbands`: subband images obtained from the output image, ordered
310
+ from high to low spatial frequency.
311
+ - `target_subbands`: subband images obtained from the target image, in the
312
+ same order.
313
+ - `active_weights`: detached copy of the active subband weights.
314
+
315
+ The public `filter_bank()` method may also be used when the subband images are
316
+ needed explicitly.
317
+
318
+ ```python
319
+ output_subbands = sfl.filter_bank(outputs)
320
+ ```
321
+
322
+ ## Filter backends
323
+
324
+ ### Separable backend
325
+
326
+ The default `"separable"` backend applies each isotropic Gaussian as consecutive
327
+ horizontal and vertical depthwise convolutions. It is mathematically equivalent
328
+ to the corresponding two-dimensional Gaussian filtering operation and is the
329
+ recommended backend for normal use.
330
+
331
+ ### Conv2d backend
332
+
333
+ The `"conv2d"` backend applies two-dimensional depthwise Gaussian convolution.
334
+ It was the initial implementation used throughout the paper to maintain fair
335
+ comparisons across the reported experiments. It remains available for
336
+ compatibility and numerical validation.
337
+
338
+ ```python
339
+ sfl = SpatialFrequencyLoss(
340
+ num_image_channels=3,
341
+ base_scale=0.6,
342
+ num_subbands=7,
343
+ filter_backend="conv2d",
344
+ ier_update_mode="calibration",
345
+ ).to(device)
346
+ ```
347
+
348
+ The test suite checks agreement between the backends within floating-point
349
+ numerical tolerances.
350
+
351
+ ## Checkpoint save and restore
352
+
353
+ The active weights based on the IER, accumulated calibration statistics, observation count,
354
+ and calibration-ready state are persistent buffers in `state_dict()`.
355
+
356
+ ```python
357
+ torch.save(
358
+ {
359
+ "model": model.state_dict(),
360
+ "sfl": sfl.state_dict(),
361
+ "optimizer": optimizer.state_dict(),
362
+ },
363
+ checkpoint_path,
364
+ )
365
+ ```
366
+
367
+ Reconstruct the model and SFL module with the intended configuration before
368
+ loading the checkpoint.
369
+
370
+ ```python
371
+ checkpoint = torch.load(
372
+ checkpoint_path,
373
+ map_location=device,
374
+ )
375
+
376
+ model.load_state_dict(checkpoint["model"])
377
+ sfl.load_state_dict(checkpoint["sfl"])
378
+ optimizer.load_state_dict(checkpoint["optimizer"])
379
+ ```
380
+
381
+ `filter_backend` is a construction-time configuration and is not selected by
382
+ `state_dict()`. Construct SFL with the backend intended for the restored run.
383
+
384
+ ## Computation time
385
+
386
+ The paper measured FFHQ training with 40,000 images resized to 256 x 256, batch
387
+ size 4, and three complete epochs of 10,000 iterations each. The interval
388
+ included GPU transfer, forward propagation, loss computation, backward
389
+ propagation, and the optimizer update.
390
+
391
+ | Loss condition | Training time (ms/iteration) | Relative time |
392
+ |---|---:|---:|
393
+ | Baseline | 50.50 +/- 0.043 | 1.00 |
394
+ | Baseline + FFL | 52.15 +/- 0.033 | 1.03 |
395
+ | Baseline + FRL | 59.67 +/- 0.063 | 1.18 |
396
+ | Baseline + SFL, conv2d | 267.9 +/- 0.724 | 5.31 |
397
+ | **Baseline + SFL, separable** | **66.85 +/- 0.021** | **1.32** |
398
+
399
+ The first four rows are from Table 6 of the paper, where FFL and FRL stand for
400
+ Focal Frequency Loss and Feature Reconstruction Loss, respectively. The
401
+ original SFL implementation used the conv2d backend, which was retained
402
+ throughout the paper to ensure fair comparisons across experiments. Because
403
+ separable filtering is mathematically equivalent and substantially faster, the
404
+ separable backend was implemented after publication and is used as the default
405
+ in the public software.
406
+
407
+ A post-publication measurement using the same measurement procedure found an
408
+ approximately 4.01-fold speed-up over the original SFL implementation and an
409
+ approximately 75.05% reduction in the SFL training time.
410
+
411
+ ## Testing
412
+
413
+ Run the public test suite from the repository root.
414
+
415
+ ```bash
416
+ python3 -m pytest -q
417
+ ```
418
+
419
+ This command asks pytest to discover and execute the public test files in the
420
+ repository. The `-q` option selects quieter output. The individual test cases
421
+ should be reviewed separately before a detailed coverage list is added here.
422
+
423
+ ## Public repository scope
424
+
425
+ This repository contains the public SFL implementation, documentation, and unit
426
+ tests. The public API supports calibrated and explicitly fixed weights based on the IER.
427
+
428
+ ## Results and project information
429
+
430
+ The published experiments evaluated the SFL with VQ-VAE models on FFHQ and
431
+ COCO2017. The SFL improved the reported validation image-quality metrics and reduced
432
+ high-frequency subband losses relative to the pixel-wise baseline. See the
433
+ [project page](https://naoyukiichimura.github.io/spatial-frequency-loss/) for visual examples, quantitative tables,
434
+ computation-time context, and post-publication information.
435
+
436
+ ## Paper
437
+
438
+ Naoyuki Ichimura, "Spatial frequency loss for mitigating spectral bias in deep
439
+ neural networks," *Machine Vision and Applications* 37, 173 (2026).
440
+ [DOI: 10.1007/s00138-026-01927-5](https://doi.org/10.1007/s00138-026-01927-5)
441
+
442
+ ## Citation
443
+
444
+ Citation metadata are provided in [CITATION.cff](CITATION.cff). GitHub users can
445
+ also select **Cite this repository** on the repository page to obtain formatted
446
+ citation information.
447
+
448
+ When citing the SFL method and its experimental evaluation, please cite the
449
+ paper listed above.
450
+ ## License
451
+
452
+ The Spatial Frequency Loss software is licensed under the GNU General Public
453
+ License, version 3 only (`GPL-3.0-only`). Commercial use, modification, and
454
+ redistribution are permitted under the terms of the license. If a modified
455
+ version of the SFL or a derivative program based on the SFL is distributed, the
456
+ corresponding source code must be provided under GPLv3.
457
+
458
+ See [LICENSE](LICENSE) for the complete license terms.
459
+
460
+ Copyright (C) 2026 Naoyuki Ichimura
@@ -0,0 +1,6 @@
1
+ spatial_frequency_loss.py,sha256=ddszsLQqqHzFQ-Pl827xy-Zm0iJk4mJnyn5KlRaPMLQ,36302
2
+ spatial_frequency_loss-1.0.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
3
+ spatial_frequency_loss-1.0.1.dist-info/METADATA,sha256=zwSUFm9Dn3oYepcjYUL0Xg5Yx_2WuIhhWpGnksY2URs,15439
4
+ spatial_frequency_loss-1.0.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
5
+ spatial_frequency_loss-1.0.1.dist-info/top_level.txt,sha256=NqDxOk5GVialvZJpWE7gYr3oRjSyVf5Rzl67tZJcHi0,23
6
+ spatial_frequency_loss-1.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+