srforge 0.16.0__tar.gz → 0.16.2__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 (330) hide show
  1. {srforge-0.16.0 → srforge-0.16.2}/CHANGELOG.md +111 -1
  2. {srforge-0.16.0/srforge.egg-info → srforge-0.16.2}/PKG-INFO +1 -1
  3. srforge-0.16.2/docs/src/api/dataset/stats.md +3 -0
  4. {srforge-0.16.0 → srforge-0.16.2}/docs/src/configuration.md +2 -1
  5. {srforge-0.16.0 → srforge-0.16.2}/docs/src/datasets.md +104 -0
  6. srforge-0.16.2/docs/src/metrics/classification-metrics.md +448 -0
  7. {srforge-0.16.0 → srforge-0.16.2}/docs/src/metrics/external-metrics.md +11 -0
  8. {srforge-0.16.0 → srforge-0.16.2}/docs/src/metrics/index.md +14 -2
  9. {srforge-0.16.0 → srforge-0.16.2}/docs/src/metrics/writing-a-metric.md +32 -0
  10. {srforge-0.16.0 → srforge-0.16.2}/docs/src/trainers-and-runners.md +38 -1
  11. {srforge-0.16.0 → srforge-0.16.2}/mkdocs.yml +1 -0
  12. {srforge-0.16.0 → srforge-0.16.2}/srforge/config/resolver.py +10 -1
  13. srforge-0.16.2/srforge/dataset/stats.py +648 -0
  14. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/__init__.py +16 -1
  15. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/adapters.py +41 -0
  16. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/base.py +22 -0
  17. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/classification.py +345 -21
  18. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/image.py +54 -1
  19. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/wrappers.py +22 -0
  20. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/hooks.py +147 -0
  21. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/runners.py +26 -0
  22. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/trainers.py +34 -1
  23. {srforge-0.16.0 → srforge-0.16.2}/srforge/transform/data.py +179 -10
  24. {srforge-0.16.0 → srforge-0.16.2/srforge.egg-info}/PKG-INFO +1 -1
  25. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/SOURCES.txt +6 -0
  26. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/scm_file_list.json +6 -0
  27. srforge-0.16.2/srforge.egg-info/scm_version.json +8 -0
  28. {srforge-0.16.0 → srforge-0.16.2}/tests/config/test_resolver.py +20 -0
  29. srforge-0.16.2/tests/dataset/test_stats.py +322 -0
  30. srforge-0.16.2/tests/loss/test_classification_losses.py +291 -0
  31. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_lpips_pointwise.py +43 -0
  32. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_pointwise_and_uncertainty.py +3 -2
  33. srforge-0.16.2/tests/training/test_loss_gradient_check.py +207 -0
  34. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_runners_coverage.py +4 -3
  35. srforge-0.16.2/tests/transform/test_classification_glue.py +129 -0
  36. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_no_redundant_unbatched.py +34 -0
  37. srforge-0.16.0/docs/src/metrics/classification-metrics.md +0 -235
  38. srforge-0.16.0/srforge.egg-info/scm_version.json +0 -8
  39. {srforge-0.16.0 → srforge-0.16.2}/.gitignore +0 -0
  40. {srforge-0.16.0 → srforge-0.16.2}/.gitlab-ci.yml +0 -0
  41. {srforge-0.16.0 → srforge-0.16.2}/.graphify_concepts.yaml +0 -0
  42. {srforge-0.16.0 → srforge-0.16.2}/.graphifyignore +0 -0
  43. {srforge-0.16.0 → srforge-0.16.2}/AGENTS.md +0 -0
  44. {srforge-0.16.0 → srforge-0.16.2}/CLAUDE.md +0 -0
  45. {srforge-0.16.0 → srforge-0.16.2}/README.md +0 -0
  46. {srforge-0.16.0 → srforge-0.16.2}/TODO.md +0 -0
  47. {srforge-0.16.0 → srforge-0.16.2}/benchmarks/README.md +0 -0
  48. {srforge-0.16.0 → srforge-0.16.2}/benchmarks/corrected_loss_vs_clcombiner.py +0 -0
  49. {srforge-0.16.0 → srforge-0.16.2}/docs/architecture.puml +0 -0
  50. {srforge-0.16.0 → srforge-0.16.2}/docs/design/distributed-training-rfc.md +0 -0
  51. {srforge-0.16.0 → srforge-0.16.2}/docs/design/external-metric-adapters-rfc.md +0 -0
  52. {srforge-0.16.0 → srforge-0.16.2}/docs/design/global-settings-shrink.md +0 -0
  53. {srforge-0.16.0 → srforge-0.16.2}/docs/design/lr-schedule-group-rfc.md +0 -0
  54. {srforge-0.16.0 → srforge-0.16.2}/docs/overrides/main.html +0 -0
  55. {srforge-0.16.0 → srforge-0.16.2}/docs/requirements.txt +0 -0
  56. {srforge-0.16.0 → srforge-0.16.2}/docs/src/anatomy-of-training.md +0 -0
  57. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/config.md +0 -0
  58. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/collation.md +0 -0
  59. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/entry.md +0 -0
  60. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/graph_entry.md +0 -0
  61. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/loader.md +0 -0
  62. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/multispectral/descriptors.md +0 -0
  63. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/multispectral/index.md +0 -0
  64. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/data/multispectral/utils.md +0 -0
  65. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/dataset/index.md +0 -0
  66. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/dataset/lazy.md +0 -0
  67. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/dataset/patching.md +0 -0
  68. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/deprecation.md +0 -0
  69. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/adapters.md +0 -0
  70. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/adversarial.md +0 -0
  71. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/base.md +0 -0
  72. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/classification.md +0 -0
  73. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/combiner.md +0 -0
  74. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/image.md +0 -0
  75. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/index.md +0 -0
  76. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/regression.md +0 -0
  77. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/regularization.md +0 -0
  78. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/schedule.md +0 -0
  79. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/scores.md +0 -0
  80. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/metrics/wrappers.md +0 -0
  81. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/MISR/MagNAt.md +0 -0
  82. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/MISR/RAMS.md +0 -0
  83. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/MISR/TRMISR.md +0 -0
  84. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/SISR/DSen2.md +0 -0
  85. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/SISR/FSRCNN.md +0 -0
  86. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/models/basic.md +0 -0
  87. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/nn/graph/convolution.md +0 -0
  88. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/nn/graph/index.md +0 -0
  89. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/nn/graph/interpolation.md +0 -0
  90. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/registry.md +0 -0
  91. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/training/index.md +0 -0
  92. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/training/runners.md +0 -0
  93. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/training/schedule.md +0 -0
  94. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/training/trainers.md +0 -0
  95. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/transforms.md +0 -0
  96. {srforge-0.16.0 → srforge-0.16.2}/docs/src/api/utils/io.md +0 -0
  97. {srforge-0.16.0 → srforge-0.16.2}/docs/src/architecture.md +0 -0
  98. {srforge-0.16.0 → srforge-0.16.2}/docs/src/cheatsheet.md +0 -0
  99. {srforge-0.16.0 → srforge-0.16.2}/docs/src/code-or-config.md +0 -0
  100. {srforge-0.16.0 → srforge-0.16.2}/docs/src/collation.md +0 -0
  101. {srforge-0.16.0 → srforge-0.16.2}/docs/src/concepts.md +0 -0
  102. {srforge-0.16.0 → srforge-0.16.2}/docs/src/config-indirection.md +0 -0
  103. {srforge-0.16.0 → srforge-0.16.2}/docs/src/distributed.md +0 -0
  104. {srforge-0.16.0 → srforge-0.16.2}/docs/src/entry.md +0 -0
  105. {srforge-0.16.0 → srforge-0.16.2}/docs/src/extending.md +0 -0
  106. {srforge-0.16.0 → srforge-0.16.2}/docs/src/faq.md +0 -0
  107. {srforge-0.16.0 → srforge-0.16.2}/docs/src/getting-started.md +0 -0
  108. {srforge-0.16.0 → srforge-0.16.2}/docs/src/hooks.md +0 -0
  109. {srforge-0.16.0 → srforge-0.16.2}/docs/src/index.md +0 -0
  110. {srforge-0.16.0 → srforge-0.16.2}/docs/src/io-binding.md +0 -0
  111. {srforge-0.16.0 → srforge-0.16.2}/docs/src/javascripts/mathjax.js +0 -0
  112. {srforge-0.16.0 → srforge-0.16.2}/docs/src/javascripts/mermaid-lightbox.js +0 -0
  113. {srforge-0.16.0 → srforge-0.16.2}/docs/src/javascripts/sections.js +0 -0
  114. {srforge-0.16.0 → srforge-0.16.2}/docs/src/models/gan-model.md +0 -0
  115. {srforge-0.16.0 → srforge-0.16.2}/docs/src/models/index.md +0 -0
  116. {srforge-0.16.0 → srforge-0.16.2}/docs/src/models/model.md +0 -0
  117. {srforge-0.16.0 → srforge-0.16.2}/docs/src/models/sequential-model.md +0 -0
  118. {srforge-0.16.0 → srforge-0.16.2}/docs/src/scripts.md +0 -0
  119. {srforge-0.16.0 → srforge-0.16.2}/docs/src/stylesheets/extra.css +0 -0
  120. {srforge-0.16.0 → srforge-0.16.2}/docs/src/stylesheets/sections.css +0 -0
  121. {srforge-0.16.0 → srforge-0.16.2}/docs/src/tracking.md +0 -0
  122. {srforge-0.16.0 → srforge-0.16.2}/docs/src/transforms/data-transform.md +0 -0
  123. {srforge-0.16.0 → srforge-0.16.2}/docs/src/transforms/entry-transform.md +0 -0
  124. {srforge-0.16.0 → srforge-0.16.2}/docs/src/transforms/index.md +0 -0
  125. {srforge-0.16.0 → srforge-0.16.2}/docs/upstream-pr-drafts/01-importance-aware-ranking.md +0 -0
  126. {srforge-0.16.0 → srforge-0.16.2}/docs/upstream-pr-drafts/02-first-class-mcp-tools.md +0 -0
  127. {srforge-0.16.0 → srforge-0.16.2}/docs/upstream-pr-drafts/README.md +0 -0
  128. {srforge-0.16.0 → srforge-0.16.2}/examples/minimal_sr/README.md +0 -0
  129. {srforge-0.16.0 → srforge-0.16.2}/examples/minimal_sr/config.yaml +0 -0
  130. {srforge-0.16.0 → srforge-0.16.2}/examples/minimal_sr/synthetic_data.py +0 -0
  131. {srforge-0.16.0 → srforge-0.16.2}/examples/minimal_sr/train.py +0 -0
  132. {srforge-0.16.0 → srforge-0.16.2}/pyproject.toml +0 -0
  133. {srforge-0.16.0 → srforge-0.16.2}/scripts/post_graphify.py +0 -0
  134. {srforge-0.16.0 → srforge-0.16.2}/scripts/refresh_graph.sh +0 -0
  135. {srforge-0.16.0 → srforge-0.16.2}/scripts/save_graph_answer.sh +0 -0
  136. {srforge-0.16.0 → srforge-0.16.2}/setup.cfg +0 -0
  137. {srforge-0.16.0 → srforge-0.16.2}/srforge/__init__.py +0 -0
  138. {srforge-0.16.0 → srforge-0.16.2}/srforge/_paths.py +0 -0
  139. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/__init__.py +0 -0
  140. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/benchmark-cfg.yaml +0 -0
  141. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/benchmark.py +0 -0
  142. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/graphify_concepts.yaml.tmpl +0 -0
  143. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/graphifyignore.tmpl +0 -0
  144. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/mcp.json.tmpl +0 -0
  145. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/post_graphify.py.tmpl +0 -0
  146. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/pre-commit.tmpl +0 -0
  147. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/refresh_graph.sh.tmpl +0 -0
  148. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/graphify/save_graph_answer.sh.tmpl +0 -0
  149. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/train-cfg.yaml +0 -0
  150. {srforge-0.16.0 → srforge-0.16.2}/srforge/_scaffold/train.py +0 -0
  151. {srforge-0.16.0 → srforge-0.16.2}/srforge/cli.py +0 -0
  152. {srforge-0.16.0 → srforge-0.16.2}/srforge/config/__init__.py +0 -0
  153. {srforge-0.16.0 → srforge-0.16.2}/srforge/config/audit.py +0 -0
  154. {srforge-0.16.0 → srforge-0.16.2}/srforge/config/spec.py +0 -0
  155. {srforge-0.16.0 → srforge-0.16.2}/srforge/config/utils.py +0 -0
  156. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/__init__.py +0 -0
  157. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/collation.py +0 -0
  158. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/entry.py +0 -0
  159. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/graph_entry.py +0 -0
  160. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/loader.py +0 -0
  161. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/multispectral/__init__.py +0 -0
  162. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/multispectral/descriptors.py +0 -0
  163. {srforge-0.16.0 → srforge-0.16.2}/srforge/data/multispectral/utils.py +0 -0
  164. {srforge-0.16.0 → srforge-0.16.2}/srforge/dataset/__init__.py +0 -0
  165. {srforge-0.16.0 → srforge-0.16.2}/srforge/dataset/lazy_datasets.py +0 -0
  166. {srforge-0.16.0 → srforge-0.16.2}/srforge/dataset/patching.py +0 -0
  167. {srforge-0.16.0 → srforge-0.16.2}/srforge/distributed/__init__.py +0 -0
  168. {srforge-0.16.0 → srforge-0.16.2}/srforge/distributed/strategy.py +0 -0
  169. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/__init__.py +0 -0
  170. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/adapters.py +0 -0
  171. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/adversarial.py +0 -0
  172. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/classification.py +0 -0
  173. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/metrics.py +0 -0
  174. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/schedule.py +0 -0
  175. {srforge-0.16.0 → srforge-0.16.2}/srforge/loss/storage.py +0 -0
  176. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/adversarial.py +0 -0
  177. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/combiner.py +0 -0
  178. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/regression.py +0 -0
  179. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/regularization.py +0 -0
  180. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/schedule.py +0 -0
  181. {srforge-0.16.0 → srforge-0.16.2}/srforge/metrics/scores.py +0 -0
  182. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/DeepSent.py +0 -0
  183. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/HighResNet.py +0 -0
  184. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/MagNAt.py +0 -0
  185. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/PIUnet.py +0 -0
  186. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/RAMS.py +0 -0
  187. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/TRMISR.py +0 -0
  188. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/MISR/__init__.py +0 -0
  189. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/SISR/DSen2.py +0 -0
  190. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/SISR/FSRCNN.py +0 -0
  191. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/SISR/__init__.py +0 -0
  192. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/__init__.py +0 -0
  193. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/basic.py +0 -0
  194. {srforge-0.16.0 → srforge-0.16.2}/srforge/models/discriminator.py +0 -0
  195. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/__init__.py +0 -0
  196. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/__init__.py +0 -0
  197. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/aggregation.py +0 -0
  198. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/convert.py +0 -0
  199. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/convolution.py +0 -0
  200. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/dropout.py +0 -0
  201. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/embedding.py +0 -0
  202. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/interpolation.py +0 -0
  203. {srforge-0.16.0 → srforge-0.16.2}/srforge/nn/graph/transforms.py +0 -0
  204. {srforge-0.16.0 → srforge-0.16.2}/srforge/registry.py +0 -0
  205. {srforge-0.16.0 → srforge-0.16.2}/srforge/tracking/__init__.py +0 -0
  206. {srforge-0.16.0 → srforge-0.16.2}/srforge/tracking/base.py +0 -0
  207. {srforge-0.16.0 → srforge-0.16.2}/srforge/tracking/null.py +0 -0
  208. {srforge-0.16.0 → srforge-0.16.2}/srforge/tracking/wandb.py +0 -0
  209. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/__init__.py +0 -0
  210. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/best_per_metric.py +0 -0
  211. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/context.py +0 -0
  212. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/hookpoint.py +0 -0
  213. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/optim.py +0 -0
  214. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/precision.py +0 -0
  215. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/schedule.py +0 -0
  216. {srforge-0.16.0 → srforge-0.16.2}/srforge/training/stop.py +0 -0
  217. {srforge-0.16.0 → srforge-0.16.2}/srforge/transform/__init__.py +0 -0
  218. {srforge-0.16.0 → srforge-0.16.2}/srforge/transform/entry.py +0 -0
  219. {srforge-0.16.0 → srforge-0.16.2}/srforge/transform/graph.py +0 -0
  220. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/__init__.py +0 -0
  221. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/_init_audit.py +0 -0
  222. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/checkpoint.py +0 -0
  223. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/child_processes.py +0 -0
  224. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/convert.py +0 -0
  225. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/deprecation.py +0 -0
  226. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/experimental.py +0 -0
  227. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/io.py +0 -0
  228. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/io_parsing.py +0 -0
  229. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/iomodule.py +0 -0
  230. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/iospec.py +0 -0
  231. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/logging.py +0 -0
  232. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/model.py +0 -0
  233. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/model_ops.py +0 -0
  234. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/multigpu.py +0 -0
  235. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/shape_trace.py +0 -0
  236. {srforge-0.16.0 → srforge-0.16.2}/srforge/utils/version_check.py +0 -0
  237. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/dependency_links.txt +0 -0
  238. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/entry_points.txt +0 -0
  239. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/requires.txt +0 -0
  240. {srforge-0.16.0 → srforge-0.16.2}/srforge.egg-info/top_level.txt +0 -0
  241. {srforge-0.16.0 → srforge-0.16.2}/tests/config/test_audit.py +0 -0
  242. {srforge-0.16.0 → srforge-0.16.2}/tests/config/test_config_io.py +0 -0
  243. {srforge-0.16.0 → srforge-0.16.2}/tests/config/test_resolver_graph.py +0 -0
  244. {srforge-0.16.0 → srforge-0.16.2}/tests/config/test_spec.py +0 -0
  245. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_collation_pyg_parity.py +0 -0
  246. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_dynamic_storage.py +0 -0
  247. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_entry_batch_indexing.py +0 -0
  248. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_entry_collation.py +0 -0
  249. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_entry_to_numpy.py +0 -0
  250. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_iomodule_set_io.py +0 -0
  251. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_lazy_graph_entry.py +0 -0
  252. {srforge-0.16.0 → srforge-0.16.2}/tests/data/test_merge_fields.py +0 -0
  253. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_dataset_caching.py +0 -0
  254. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_dataset_transforms.py +0 -0
  255. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_lazy_dataset_filters.py +0 -0
  256. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_lazy_multispectral_dataset.py +0 -0
  257. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_multispectral_patching.py +0 -0
  258. {srforge-0.16.0 → srforge-0.16.2}/tests/dataset/test_shape_tracing.py +0 -0
  259. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/__init__.py +0 -0
  260. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/test_ddp_gloo.py +0 -0
  261. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/test_distributed_options.py +0 -0
  262. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/test_model_accessors.py +0 -0
  263. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/test_rank_gating.py +0 -0
  264. {srforge-0.16.0 → srforge-0.16.2}/tests/distributed/test_strategy.py +0 -0
  265. {srforge-0.16.0 → srforge-0.16.2}/tests/integration/__init__.py +0 -0
  266. {srforge-0.16.0 → srforge-0.16.2}/tests/integration/test_end_to_end_yaml.py +0 -0
  267. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_adapters.py +0 -0
  268. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_adversarial_losses.py +0 -0
  269. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_aggregate.py +0 -0
  270. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_band_aggregation.py +0 -0
  271. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_classification_metrics.py +0 -0
  272. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_corrected_loss.py +0 -0
  273. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_deprecated_loss_paths.py +0 -0
  274. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_epoch_aggregation.py +0 -0
  275. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_loss_dict_inputs.py +0 -0
  276. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_loss_entry_only.py +0 -0
  277. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_loss_scheduler.py +0 -0
  278. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_loss_set_io.py +0 -0
  279. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_mask_counting.py +0 -0
  280. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_pointwise_inputs.py +0 -0
  281. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_reduction_applies.py +0 -0
  282. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_sam_mask.py +0 -0
  283. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_total_variation_mask.py +0 -0
  284. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_uncertainty_any_base.py +0 -0
  285. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_windowed_masking.py +0 -0
  286. {srforge-0.16.0 → srforge-0.16.2}/tests/loss/test_writing_a_metric_page.py +0 -0
  287. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_gan_model.py +0 -0
  288. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_model_graphentry_merge.py +0 -0
  289. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_model_optional_iospec.py +0 -0
  290. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_model_output_merge.py +0 -0
  291. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_model_set_io_validation.py +0 -0
  292. {srforge-0.16.0 → srforge-0.16.2}/tests/models/test_sequential_model_flow.py +0 -0
  293. {srforge-0.16.0 → srforge-0.16.2}/tests/test_cli_init.py +0 -0
  294. {srforge-0.16.0 → srforge-0.16.2}/tests/test_init.py +0 -0
  295. {srforge-0.16.0 → srforge-0.16.2}/tests/test_io_binding_cheatsheet.py +0 -0
  296. {srforge-0.16.0 → srforge-0.16.2}/tests/test_io_binding_integration.py +0 -0
  297. {srforge-0.16.0 → srforge-0.16.2}/tests/test_io_binding_reference.py +0 -0
  298. {srforge-0.16.0 → srforge-0.16.2}/tests/test_preflight_audit.py +0 -0
  299. {srforge-0.16.0 → srforge-0.16.2}/tests/test_registry_collisions.py +0 -0
  300. {srforge-0.16.0 → srforge-0.16.2}/tests/tracking/__init__.py +0 -0
  301. {srforge-0.16.0 → srforge-0.16.2}/tests/tracking/test_null_tracker.py +0 -0
  302. {srforge-0.16.0 → srforge-0.16.2}/tests/tracking/test_tracker.py +0 -0
  303. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_best_per_metric.py +0 -0
  304. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_hookpoint_system.py +0 -0
  305. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_hooks.py +0 -0
  306. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_output_directory.py +0 -0
  307. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_precision.py +0 -0
  308. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_progress_bar_values.py +0 -0
  309. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_runner_graphentry_output.py +0 -0
  310. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_runner_optimizers.py +0 -0
  311. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_runner_output_merge.py +0 -0
  312. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_sampler_epoch.py +0 -0
  313. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_schedule.py +0 -0
  314. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_stop.py +0 -0
  315. {srforge-0.16.0 → srforge-0.16.2}/tests/training/test_trainers.py +0 -0
  316. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_batched_unbatched_equivalence.py +0 -0
  317. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_data_transforms.py +0 -0
  318. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_entry_transforms.py +0 -0
  319. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_equalization.py +0 -0
  320. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_per_sample_transform.py +0 -0
  321. {srforge-0.16.0 → srforge-0.16.2}/tests/transform/test_resize_bands.py +0 -0
  322. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/__init__.py +0 -0
  323. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_checkpoint.py +0 -0
  324. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_child_processes.py +0 -0
  325. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_init_audit.py +0 -0
  326. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_io_parsing.py +0 -0
  327. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_iospec.py +0 -0
  328. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_multigpu.py +0 -0
  329. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_utils_coverage.py +0 -0
  330. {srforge-0.16.0 → srforge-0.16.2}/tests/utils/test_version_check.py +0 -0
@@ -7,6 +7,114 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.2] - 2026-10-19
11
+
12
+ ### Added
13
+
14
+ - **A loss that trains nothing is caught.** A loss with a non-zero weight
15
+ that passes no gradient — a hard `F1Score`, a metric calling `.detach()`
16
+ or `.item()`, a library metric computed without gradients — used to train
17
+ silently on nothing. Now:
18
+ - **`Metric.differentiable`** (default `True`) declares it. False for the
19
+ hard confusion ratios (true only with `soft=True`), the confusion
20
+ counts and `TBE`; `UncertaintyLoss` / `CorrectedLoss` follow their base
21
+ metric; a torchmetrics metric is differentiable when the library says so
22
+ and `aggregate="macro"`, a pyiqa metric when created with
23
+ `as_loss=True`. Each class's docstring states which configurations are
24
+ differentiable.
25
+ - **The trainer refuses** a training criterion (including every
26
+ criterion a `LossScheduler` switches to, and the GAN runner's D and G
27
+ criteria) that holds a declared non-differentiable metric with a
28
+ non-zero weight, naming it and what to use instead.
29
+ - **`LossGradientCheck`**, installed on every training runner, checks each
30
+ weighted loss once, on its first batch: not connected to the model
31
+ stops training, an exactly zero gradient warns. Hook-added loss terms
32
+ are checked too; weight-0 metrics are skipped. The runners'
33
+ `check_losses` option — `on` (default), `strict`, `off` — controls it.
34
+ - **`get_class_weights(scheme="inverse_sqrt_freq")`** — weights `∝ 1/√f_c`,
35
+ for strongly imbalanced data where `inverse_freq` gets extreme (a class on
36
+ 0.1% of the pixels: 32× instead of 1000×). Like `inverse_freq` it averages
37
+ to 1 over the pixels, keeping the weighted loss on the unweighted scale.
38
+ - **More dataset statistics in `srforge.dataset.stats`**, each computed once
39
+ from the dataset when the config is built and passed on with `${ref:...}`:
40
+ `channel_mean_std` (per-channel mean and std), `value_range` (robust
41
+ per-channel low/high at chosen percentiles, with `bounds()` for
42
+ `Normalize` and `data_range()` for PSNR), `field_report` (shapes, dtypes,
43
+ NaN/inf and constant entries per field), `mask_coverage` and
44
+ `indices_with_coverage` (for a `SubsetDataset` without near-empty
45
+ samples), and `spatial_sizes`. They skip non-finite values, take
46
+ `mask_field`, and `max_samples` reads a seeded random subset.
47
+ - **`Standardize` and `Destandardize` take one mean and std per channel**,
48
+ or `stats=` — the result of `channel_mean_std` — instead of the two.
49
+ - **A `${ref:...}` may resolve to a number computed by a `_target`** or
50
+ returned by a method (`${ref:value_range}.data_range()`). The refusal
51
+ remains for references to plain config values, which belong in `${...}`.
52
+ - **`Sigmoid`, `Softmax`, `SelectChannels` and `IgnoreValue` transforms** —
53
+ the glue between a real model and dataset and the classification metrics,
54
+ which read probabilities and a mask: logits become probabilities in the
55
+ runner's `postprocessor`, `SelectChannels` picks the positive class of a
56
+ two-channel model, and `IgnoreValue` turns a label's ignore value (e.g.
57
+ 255) into a clean label plus a mask for `y_mask`.
58
+ - **Documentation:** *Datasets* has a *Dataset Statistics* section;
59
+ *Classification Metrics* shows the path from logits and ignore labels;
60
+ *Trainers & Runners* → *Losses that train nothing*;
61
+ *Writing a Metric* covers `differentiable`.
62
+ - **Documentation:** a rule of thumb for choosing the scheme — up to ~10×
63
+ imbalance `inverse_freq`, beyond that `inverse_sqrt_freq` or unweighted
64
+ BCE + `DiceLoss`.
65
+
66
+ ## [0.16.1] - 2026-09-25
67
+
68
+ ### Added
69
+
70
+ - **Every confusion ratio can be trained on: `soft=True`.** F1, IoU and
71
+ the other ratios threshold the prediction, so no gradient passes through
72
+ them. With `soft=True` the same `ratio()` runs on soft counts
73
+ (`TP = Σ p·y`, …), equal to the hard counts on a 0/1 prediction — your
74
+ own ratios included. The ratio keeps its direction: soft F1 is
75
+ higher-is-better and the training total negates it, as for PSNR or SSIM,
76
+ so a negative weighted Dice is what "maximising" looks like. `smooth`
77
+ defaults to 1 when soft (0 when hard), without which a batch with no
78
+ positives gives no gradient; the default name becomes `Soft<Class>` so a
79
+ soft value is never logged under the hard metric's name, and an explicit
80
+ `name` is kept. A `threshold` is refused with `soft=True`.
81
+ - **`DiceLoss`, `JaccardLoss`, `TverskyLoss`** — `F1Score`, `IoU` and
82
+ `TverskyIndex` with `soft=True` built in, by the names they are known
83
+ under.
84
+ - **`BinaryCrossEntropy`** — per-pixel `−[y·log p + (1−y)·log(1−p)]` on a
85
+ probability map, with optional `class_weights=(negative, positive)`. The
86
+ usual change-detection criterion is it plus `DiceLoss`.
87
+ - **`TverskyIndex(alpha, beta)`** — F1 and IoU with false alarms and missed
88
+ positives priced apart.
89
+ - **`CrossEntropy` takes `class_weights`** (one per class) **and class-index
90
+ targets** (`[B, H, W]` or `[B, 1, H, W]`, integer) as well as one-hot or
91
+ soft ones — what projects wrote their own class-balanced CE for.
92
+ - **`srforge.dataset.stats.get_class_weights`** — class-balancing weights
93
+ counted once from a dataset when the config is built, for the losses'
94
+ `class_weights` (`${ref:...}` passes them on). `inverse_freq` (rare classes
95
+ weigh more) or `proportional`; `ignore_index` and `mask_field` leave
96
+ elements out. `class_counts` gives the raw counts. The first of the
97
+ dataset-statistics helpers, so losses no longer iterate the data.
98
+ - **Documentation:** *Classification Metrics* has a *Training with them*
99
+ section.
100
+
101
+ ### Fixed
102
+
103
+ - **`CrossEntropy` was not a cross-entropy on a yes/no map.** It computed
104
+ `−y·log p` per element and averaged over classes too: on one channel there
105
+ was no term for the negative class, so predicting "yes" everywhere scored
106
+ a perfect 0. It now sums over the class axis (`−Σ_c y_c·log p_c` per
107
+ pixel) and refuses a one-channel prediction, pointing to
108
+ `BinaryCrossEntropy`. **Breaking:** on a multi-class map its value is `C`
109
+ times what it was (the mean no longer divides by the class count) —
110
+ rescale its `weight` in a `LossCombiner` to keep the old balance.
111
+ - **`LPIPS` could return NaN gradients.** The `lpips` package normalises
112
+ each feature vector by `sqrt(sum(x²))` with `eps` only in the divisor, so
113
+ where the squared norm underflows to 0 the backward is infinite — tiny
114
+ activations in float32, and routinely small ones under float16 mixed
115
+ precision. Building `LPIPS` now swaps in a normalisation with `eps` under
116
+ the root and the norm computed in float32; values are unchanged to ~1e-10.
117
+
10
118
  ## [0.16.0] - 2026-09-25
11
119
 
12
120
  ### Changed
@@ -1494,7 +1602,9 @@ likelihood of affecting a given codebase:
1494
1602
  - `Preprocessor` and `TransformationSpec` removed; `EntryTransform` is standalone.
1495
1603
  - Codebase cleanup: `assert` replaced with proper exceptions, `super()` modernized.
1496
1604
 
1497
- [Unreleased]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.16.0...HEAD
1605
+ [Unreleased]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.16.2...HEAD
1606
+ [0.16.2]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.16.1...v0.16.2
1607
+ [0.16.1]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.16.0...v0.16.1
1498
1608
  [0.16.0]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.15.4...v0.16.0
1499
1609
  [0.15.4]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.15.3...v0.15.4
1500
1610
  [0.15.3]: https://gitlab.com/tarasiewicztomasz/sr-forge/-/compare/v0.15.2...v0.15.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: srforge
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: Super‑resolution research framework for PyTorch with a focus on simplicity and flexibility using config files.
5
5
  Author-email: Tomasz Tarasiewicz <tomasz.tarasiewicz@polsl.pl>
6
6
  Project-URL: Homepage, https://gitlab.com/tarasiewicztomasz/sr-forge
@@ -0,0 +1,3 @@
1
+ # Dataset Statistics
2
+
3
+ ::: srforge.dataset.stats
@@ -331,7 +331,8 @@ b: ${ref:a}
331
331
  | Reuse a config block (e.g., same transforms for train and val) | `${path}` | Each dataset gets its own independent pipeline |
332
332
  | Share one object (e.g., optimizer needs the model's params) | `${ref:path}` | Must be the exact same Python object |
333
333
  | Call a method on another object | `${ref:path}.method()` | Only references support method chains |
334
- | Copy a scalar value (number, string) | `${path}` | `${ref:}` raises TypeError on primitives |
334
+ | Copy a scalar value (number, string) | `${path}` | `${ref:}` to a plain value raises TypeError |
335
+ | Use a number *computed* by a `_target` (e.g. a [dataset statistic](datasets.md#dataset-statistics)) | `${ref:path}` or `${ref:path}.method()` | It has no `${...}` spelling — it exists only once built |
335
336
 
336
337
  ---
337
338
 
@@ -404,6 +404,110 @@ Supports optional internal disk caching (`use_internal_cache=True`) with cross-p
404
404
 
405
405
  ---
406
406
 
407
+ ## Dataset Statistics
408
+
409
+ Some numbers a run needs are properties of the data: the mean and std to
410
+ standardise with, the value range PSNR measures against, the class balance
411
+ a loss weighs by. Guessing them, or copying them from another project, is
412
+ how they go stale. `srforge.dataset.stats` computes them from the dataset
413
+ **once, when the config is built**, and `${ref:...}` hands them on.
414
+
415
+ | Helper | Gives you | Feeds |
416
+ |---|---|---|
417
+ | `channel_mean_std` | mean and std per channel | `Standardize` / `Destandardize` (`stats=`) |
418
+ | `value_range` | robust low/high per channel (percentiles) | `Normalize(range=...)`, `PSNR(data_range=...)` |
419
+ | `get_class_weights` | one weight per class | the cross-entropies' `class_weights` — see [Classification Metrics](metrics/classification-metrics.md#training-with-them) |
420
+ | `class_counts` | elements per class | your own use |
421
+ | `field_report` | shapes, dtypes, NaN/inf, constant entries | a check before training |
422
+ | `mask_coverage` / `indices_with_coverage` | the valid share of each entry's mask | a `SubsetDataset` without near-empty samples |
423
+ | `spatial_sizes` | the height × width the entries come in | choosing a patch size |
424
+
425
+ ```yaml
426
+ stats:
427
+ _target: srforge.dataset.stats.channel_mean_std
428
+ params:
429
+ dataset: ${ref:dataset.training}
430
+ field: lr
431
+
432
+ value_range:
433
+ _target: srforge.dataset.stats.value_range
434
+ params:
435
+ dataset: ${ref:dataset.training}
436
+ field: hr
437
+ percentiles: [0, 100]
438
+
439
+ # ... in the transforms:
440
+ - _target: srforge.transform.data.Standardize
441
+ params:
442
+ stats: ${ref:stats} # one mean and std per channel
443
+
444
+ # ... in the metrics:
445
+ - _target: srforge.metrics.regression.PSNR
446
+ params:
447
+ data_range: ${ref:value_range}.data_range()
448
+ ```
449
+
450
+ ??? tip "Why per channel, and why percentiles"
451
+
452
+ Each band of a multispectral or SAR image has its own scale; one mean
453
+ and std for all of them leaves the quiet bands nearly flat. That is why
454
+ `channel_mean_std` works per channel, and why `Standardize` and
455
+ `Destandardize` now accept one value per channel.
456
+
457
+ `value_range` defaults to the 1st and 99th percentile rather than the
458
+ true minimum and maximum, which a single saturated pixel or speckle
459
+ outlier can set on its own. Pass `percentiles: [0, 100]` for the exact
460
+ ends — right for `PSNR`, whose `data_range` should be the real
461
+ peak-to-peak span. On a large dataset the percentiles are estimated from
462
+ up to a million values per channel, drawn evenly across the entries.
463
+
464
+ ??? tip "Checking the data: `field_report`"
465
+
466
+ ```python
467
+ from srforge.dataset.stats import field_report
468
+
469
+ report = field_report(train_dataset) # logs one line per field
470
+ report["hr"].non_finite # NaN / inf count
471
+ report["hr"].problems() # ['12 non-finite value(s) (0.01%)', ...]
472
+ ```
473
+
474
+ It flags NaN and infinite values, constant entries (a blank tile, a
475
+ failed read), and fields whose shape or dtype changes between entries.
476
+ A field holding a mapping of bands is reported band by band. Nothing is
477
+ changed — it is a report, to run before training rather than find a NaN
478
+ an epoch in.
479
+
480
+ ??? tip "Dropping almost-empty samples: `indices_with_coverage`"
481
+
482
+ ```yaml
483
+ dataset:
484
+ training:
485
+ _target: srforge.dataset.SubsetDataset
486
+ params:
487
+ dataset: ${ref:dataset.full}
488
+ indices:
489
+ _target: srforge.dataset.stats.indices_with_coverage
490
+ params:
491
+ dataset: ${ref:dataset.full}
492
+ mask_field: valid
493
+ minimum: 0.2 # keep entries at least 20% valid
494
+ ```
495
+
496
+ **Common to all of them:**
497
+
498
+ - Each reads the whole dataset once through `dataset[i]`, so the dataset's
499
+ transforms run first. Two helpers mean two passes; `max_samples` reads a
500
+ seeded random subset instead, for datasets too large to walk at start-up.
501
+ - The value helpers take `mask_field` — elements where that mask is 0 are
502
+ left out — and skip NaN and infinite values.
503
+ - Under `torchrun` every process computes the same result independently.
504
+ - A field holding a mapping of bands is refused by the per-channel helpers;
505
+ select or stack the bands with a transform first.
506
+
507
+ The full signatures are in the [API reference](api/dataset/stats.md).
508
+
509
+ ---
510
+
407
511
  ## DataLoader Integration
408
512
 
409
513
  `DataLoaderFactory` creates a PyTorch `DataLoader` with the right collation for your dataset. It takes the same `batch_size`, `shuffle`, `num_workers`, `pin_memory`, and other keyword arguments you'd normally pass to `DataLoader`, plus an optional `device` parameter for multi-GPU detection: