Equimo 2.5.0__tar.gz → 2.6.0__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 (171) hide show
  1. {equimo-2.5.0 → equimo-2.6.0}/CHANGELOG.md +36 -0
  2. {equimo-2.5.0 → equimo-2.6.0}/PKG-INFO +1 -1
  3. {equimo-2.5.0 → equimo-2.6.0}/pyproject.toml +1 -1
  4. equimo-2.6.0/src/equimo/__init__.py +1 -0
  5. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/eomt.py +15 -1
  6. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/query_training/_assignment.py +10 -8
  7. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/query_training/_loss.py +4 -2
  8. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/segmentation.py +6 -2
  9. equimo-2.5.0/src/equimo/__init__.py +0 -1
  10. {equimo-2.5.0 → equimo-2.6.0}/LICENSE.md +0 -0
  11. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/Apache-2.0.txt +0 -0
  12. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/README.md +0 -0
  13. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/ast-BSD-3-Clause.txt +0 -0
  14. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/convnext-Apache-2.0.txt +0 -0
  15. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/convnextv2-CC-BY-NC-4.0.txt +0 -0
  16. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/dinov2-Apache-2.0.txt +0 -0
  17. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/dinov3-License.md +0 -0
  18. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/eupe-FAIR-Noncommercial-Research-License.md +0 -0
  19. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/lingbot-vision-Apache-2.0.txt +0 -0
  20. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/siglip2-Apache-2.0.txt +0 -0
  21. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/t0-alpha-Apache-2.0.txt +0 -0
  22. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/tabpfn-3-License-v1.0.txt +0 -0
  23. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/pretrained/tips-CC-BY-4.0.txt +0 -0
  24. {equimo-2.5.0 → equimo-2.6.0}/LICENSES/tfc-t0-APACHE-2.0.txt +0 -0
  25. {equimo-2.5.0 → equimo-2.6.0}/NOTICE +0 -0
  26. {equimo-2.5.0 → equimo-2.6.0}/README.md +0 -0
  27. {equimo-2.5.0 → equimo-2.6.0}/docs/licensing/t0-source-provenance.md +0 -0
  28. {equimo-2.5.0 → equimo-2.6.0}/docs/migration-v2.md +0 -0
  29. {equimo-2.5.0 → equimo-2.6.0}/docs/stability.md +0 -0
  30. {equimo-2.5.0 → equimo-2.6.0}/docs/timeseries.md +0 -0
  31. {equimo-2.5.0 → equimo-2.6.0}/models/huggingface/NOTICE +0 -0
  32. {equimo-2.5.0 → equimo-2.6.0}/models/huggingface/README.md +0 -0
  33. {equimo-2.5.0 → equimo-2.6.0}/models/huggingface/convnext-conversion.json +0 -0
  34. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/_checkpoint_limits.py +0 -0
  35. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/_io.py +0 -0
  36. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/_pretrained.py +0 -0
  37. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/__init__.py +0 -0
  38. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/io.py +0 -0
  39. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/layers/__init__.py +0 -0
  40. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/layers/patch.py +0 -0
  41. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/models/__init__.py +0 -0
  42. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/audio/models/ast.py +0 -0
  43. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/catalog.py +0 -0
  44. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/conversion/__init__.py +0 -0
  45. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/conversion/utils.py +0 -0
  46. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/__init__.py +0 -0
  47. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/_prng.py +0 -0
  48. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/emamodel.py +0 -0
  49. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/factory.py +0 -0
  50. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/__init__.py +0 -0
  51. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/_base.py +0 -0
  52. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/deq.py +0 -0
  53. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/injectors.py +0 -0
  54. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/stabilizers.py +0 -0
  55. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/implicit/strategies.py +0 -0
  56. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/intermediates.py +0 -0
  57. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/__init__.py +0 -0
  58. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/_registry.py +0 -0
  59. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/activation.py +0 -0
  60. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/attention.py +0 -0
  61. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/dropout.py +0 -0
  62. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/ffn.py +0 -0
  63. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/generic.py +0 -0
  64. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/mamba.py +0 -0
  65. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/norm.py +0 -0
  66. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/layers/rotary.py +0 -0
  67. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/ops/__init__.py +0 -0
  68. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/core/ops/scan.py +0 -0
  69. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/__init__.py +0 -0
  70. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/_blocks.py +0 -0
  71. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/_serialization_codecs.py +0 -0
  72. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/_typing.py +0 -0
  73. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/audio/__init__.py +0 -0
  74. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/audio/recipes.py +0 -0
  75. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/audio/selectors.py +0 -0
  76. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/calibration.py +0 -0
  77. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/config.py +0 -0
  78. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/continued_ssl.py +0 -0
  79. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/feature_extraction.py +0 -0
  80. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/heads.py +0 -0
  81. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/inspection.py +0 -0
  82. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/labels.py +0 -0
  83. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/language/__init__.py +0 -0
  84. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/language/recipes.py +0 -0
  85. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/language/selectors.py +0 -0
  86. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/masks.py +0 -0
  87. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/merging.py +0 -0
  88. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/paths.py +0 -0
  89. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/__init__.py +0 -0
  90. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/_common.py +0 -0
  91. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/_compat.py +0 -0
  92. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/adapters.py +0 -0
  93. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/base.py +0 -0
  94. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/bitfit.py +0 -0
  95. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/dora.py +0 -0
  96. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/ia3.py +0 -0
  97. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/lora.py +0 -0
  98. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/prefix.py +0 -0
  99. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/prompts.py +0 -0
  100. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/scale_shift.py +0 -0
  101. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/peft/vera.py +0 -0
  102. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/pooling.py +0 -0
  103. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/recipes.py +0 -0
  104. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/regularization.py +0 -0
  105. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/selectors.py +0 -0
  106. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/serialization.py +0 -0
  107. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/surgery.py +0 -0
  108. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/tags.py +0 -0
  109. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/vision/__init__.py +0 -0
  110. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/vision/dense.py +0 -0
  111. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/vision/eomt.py +0 -0
  112. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/finetune/vision/pmt.py +0 -0
  113. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/language/__init__.py +0 -0
  114. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/language/models.py +0 -0
  115. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/language/tokenizers.py +0 -0
  116. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/registry.py +0 -0
  117. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/serialization.py +0 -0
  118. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/__init__.py +0 -0
  119. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/__init__.py +0 -0
  120. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/attention.py +0 -0
  121. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/blocks.py +0 -0
  122. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/decoder.py +0 -0
  123. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/mlp.py +0 -0
  124. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/preprocessing.py +0 -0
  125. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/layers/registry.py +0 -0
  126. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/models/__init__.py +0 -0
  127. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/tabular/models/tabpfn.py +0 -0
  128. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/__init__.py +0 -0
  129. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/__init__.py +0 -0
  130. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/axis_attn.py +0 -0
  131. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/blocks.py +0 -0
  132. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/patch_encoder.py +0 -0
  133. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/registry.py +0 -0
  134. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/layers/residual_mlp.py +0 -0
  135. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/models/__init__.py +0 -0
  136. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/timeseries/models/t0.py +0 -0
  137. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/utils.py +0 -0
  138. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/__init__.py +0 -0
  139. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/_encoder_identity.py +0 -0
  140. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/io.py +0 -0
  141. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/__init__.py +0 -0
  142. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/attention.py +0 -0
  143. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/convolution.py +0 -0
  144. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/downsample.py +0 -0
  145. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/patch.py +0 -0
  146. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/posemb.py +0 -0
  147. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/registry.py +0 -0
  148. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/squeeze_excite.py +0 -0
  149. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/layers/wavelet.py +0 -0
  150. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/__init__.py +0 -0
  151. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/_embedding.py +0 -0
  152. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/_features.py +0 -0
  153. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/attnet.py +0 -0
  154. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/convnext.py +0 -0
  155. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/deq.py +0 -0
  156. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/fastervit.py +0 -0
  157. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/iformer.py +0 -0
  158. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/lowformer.py +0 -0
  159. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/mlla.py +0 -0
  160. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/mobilenet.py +0 -0
  161. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/parcae.py +0 -0
  162. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/partialformer.py +0 -0
  163. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/pmd.py +0 -0
  164. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/pmt.py +0 -0
  165. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/reduceformer.py +0 -0
  166. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/shvit.py +0 -0
  167. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/vit.py +0 -0
  168. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/models/vssd.py +0 -0
  169. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/pmt_checkpoint.py +0 -0
  170. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/query_training/__init__.py +0 -0
  171. {equimo-2.5.0 → equimo-2.6.0}/src/equimo/vision/query_training/_sampling.py +0 -0
@@ -2,6 +2,42 @@
2
2
 
3
3
  All notable changes to Equimo are documented here. Equimo follows Semantic Versioning from version 2.0.0 onward.
4
4
 
5
+ ## [2.6.0] - 2026-10-17
6
+
7
+ ### Fixed
8
+
9
+ - `anneal_mask_state` and `anneal_pmt_mask_state` return exactly zero mask probability from the declared end step. On
10
+ GPUs, the float32 progress quotient could round just below one (600 / 600 is 0.99999994 on an H100), which left a
11
+ probability near 3e-7 at that step and made `mask_free_eomt` and `mask_free_pmt` refuse a model whose annealing had
12
+ ended.
13
+ - Masked attention in EoMT and PMT keeps each query mask with exactly the annealed probability. A query kept its mask
14
+ when its uniform draw was at most the probability, so at probability zero a draw of exactly 0.0 (about one in 8.4
15
+ million per query) still applied it. Only draws exactly equal to the probability change outcome.
16
+
17
+ ## [2.5.2] - 2026-10-16
18
+
19
+ ### Fixed
20
+
21
+ - The EoMT and PMT mask-head `ScaleBlock` accumulates its upscaling matmul in the input precision when that exceeds
22
+ float32. In 2.5.1, float64 models computed the upscale in float32 on CPU and failed on GPU, where cuBLAS has no
23
+ float64-input, float32-output GEMM.
24
+
25
+ ## [2.5.1] - 2026-10-16
26
+
27
+ ### Changed
28
+
29
+ - The EoMT and PMT mask-head `ScaleBlock` computes its 2 × 2, stride-2 transposed convolution as a matmul followed by
30
+ depth-to-space. This avoids an untuned cuDNN fallback for the bfloat16 weight gradient that made GPU training steps
31
+ several times slower at batch sizes of 12 and above. Parameters and checkpoints are unchanged; outputs match the
32
+ previous implementation within floating-point rounding.
33
+
34
+ ### Fixed
35
+
36
+ - `match_queries` and the query-segmentation losses no longer rely on dropping out-of-range scatter updates. Under
37
+ `vmap` with `--xla_gpu_deterministic_ops` or `--xla_gpu_exclude_nondeterministic_ops`, jaxlib 0.11.2 and earlier write
38
+ such updates into the next batch row (openxla/xla#49380), which silently produced non-optimal query assignments and
39
+ wrong classification targets.
40
+
5
41
  ## [2.5.0] - 2026-10-15
6
42
 
7
43
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Equimo
3
- Version: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: Implementation of modern multimodal models in JAX/Equinox
5
5
  License-Expression: MIT AND Apache-2.0
6
6
  License-File: LICENSE.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "Equimo"
3
- version = "2.5.0"
3
+ version = "2.6.0"
4
4
  description = "Implementation of modern multimodal models in JAX/Equinox"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12,<3.15"
@@ -0,0 +1 @@
1
+ __version__ = "2.6.0"
@@ -76,7 +76,21 @@ class ScaleBlock(eqx.Module):
76
76
  self.norm = LayerNorm2d(channels, eps=1e-6)
77
77
 
78
78
  def __call__(self, x: jax.Array) -> jax.Array:
79
- return self.norm(self.conv2(jax.nn.gelu(self.conv1(x), approximate=False)))
79
+ # The 2x2 stride-2 transposed convolution has no overlapping windows, so
80
+ # it is a per-pixel matmul followed by depth-to-space. Lowering it as a
81
+ # convolution sends its bfloat16 weight gradient to an untuned cuDNN
82
+ # kernel that dominates training steps at larger batch sizes.
83
+ _, height, width = x.shape
84
+ # Equinox correlates the stored kernel with the dilated input.
85
+ weight = self.conv1.weight[:, :, ::-1, ::-1]
86
+ # Accumulate in at least float32 without demoting float64 inputs.
87
+ accumulation_dtype = jnp.promote_types(jnp.result_type(weight, x), jnp.float32)
88
+ upscaled = jnp.einsum(
89
+ "oiab,ihw->ohawb", weight, x, preferred_element_type=accumulation_dtype
90
+ )
91
+ upscaled = upscaled.reshape(-1, 2 * height, 2 * width) + self.conv1.bias
92
+ upscaled = upscaled.astype(x.dtype)
93
+ return self.norm(self.conv2(jax.nn.gelu(upscaled, approximate=False)))
80
94
 
81
95
 
82
96
  class MaskEmbedding(eqx.Module):
@@ -71,10 +71,11 @@ def match_queries(costs: jax.Array, target_valid: jax.Array) -> QueryAssignment:
71
71
  candidate = jnp.where(available, distance, jnp.inf)
72
72
  next_column = jnp.argmin(candidate).astype(jnp.int32) + 1
73
73
  delta = candidate[next_column - 1]
74
- # Out-of-range scatter updates are dropped; unvisited columns
75
- # must not repeatedly add to the dummy row's potential.
76
- indices = jnp.where(visited, owner, targets + 1)
77
- u = u.at[indices].add(delta, mode="drop")
74
+ # Unvisited columns add zero instead of being dropped as
75
+ # out-of-range updates: deterministic GPU scatters in jaxlib
76
+ # <= 0.11.2 write those into the next batch row
77
+ # (openxla/xla#49380).
78
+ u = u.at[owner].add(jnp.where(visited, delta, 0))
78
79
  v = jnp.where(visited, v - delta, v)
79
80
  distance = jnp.where(available, distance - delta, distance)
80
81
  return u, v, visited, distance, previous, next_column, steps + 1
@@ -120,11 +121,12 @@ def match_queries(costs: jax.Array, target_valid: jax.Array) -> QueryAssignment:
120
121
  finite,
121
122
  )
122
123
  _, _, owner, feasible = lax.fori_loop(0, targets, insert, initial)
123
- indices = jnp.full((targets,), -1, dtype=jnp.int32)
124
+ # Unmatched queries write to a spare slot rather than out of range, which
125
+ # deterministic GPU scatters mishandle (openxla/xla#49380).
126
+ indices = jnp.full((targets + 1,), -1, dtype=jnp.int32)
124
127
  destinations = jnp.where(owner[1:] > 0, owner[1:] - 1, targets)
125
- indices = indices.at[destinations].set(
126
- jnp.arange(queries, dtype=jnp.int32), mode="drop"
127
- )
128
+ indices = indices.at[destinations].set(jnp.arange(queries, dtype=jnp.int32))
129
+ indices = indices[:targets]
128
130
  return QueryAssignment(
129
131
  jnp.where(feasible, indices, -1), active & feasible, feasible
130
132
  )
@@ -410,9 +410,11 @@ def query_prediction_loss(
410
410
  )
411
411
  is_valid &= jnp.all(counts <= 1)
412
412
  no_object = classes.shape[1] - 1
413
- assigned_labels = jnp.full((classes.shape[0],), no_object, dtype=jnp.int32)
413
+ # Unmatched targets write to a spare slot rather than out of range, which
414
+ # deterministic GPU scatters mishandle (openxla/xla#49380).
415
+ assigned_labels = jnp.full((classes.shape[0] + 1,), no_object, dtype=jnp.int32)
414
416
  destinations = jnp.where(matched, indices, classes.shape[0])
415
- assigned_labels = assigned_labels.at[destinations].set(labels, mode="drop")
417
+ assigned_labels = assigned_labels.at[destinations].set(labels)[:-1]
416
418
  weights = (
417
419
  jnp.where(assigned_labels == no_object, config.no_object_weight, 1.0)
418
420
  * targets.supervised
@@ -63,7 +63,8 @@ def _query_attention_mask(
63
63
  """
64
64
  num_queries = mask_logits.shape[0]
65
65
  allowed = resize_mask_logits(mask_logits, grid) > 0
66
- keep = jr.uniform(key, (num_queries,)) <= probability
66
+ # Strict: uniform draws include exactly zero, which must not keep a mask at probability zero.
67
+ keep = jr.uniform(key, (num_queries,)) < probability
67
68
  allowed = jnp.where(keep[:, None, None], allowed, True)
68
69
  patch_start = num_queries + num_prefix_tokens
69
70
  length = patch_start + grid[0] * grid[1]
@@ -90,7 +91,10 @@ def _anneal_mask_probabilities(
90
91
  start = jnp.asarray(start_steps, dtype=jnp.float32)
91
92
  end = jnp.asarray(end_steps, dtype=jnp.float32)
92
93
  progress = jnp.clip((step.astype(jnp.float32) - start) / (end - start), 0, 1)
93
- return (1 - progress) ** power
94
+ # GPU float32 division is not correctly rounded (600 / 600 is 0.99999994 on an H100),
95
+ # so the end step itself, not the quotient reaching one, removes the masks.
96
+ ended = step >= jnp.asarray(end_steps, dtype=jnp.int32)
97
+ return jnp.where(ended, 0.0, (1 - progress) ** power)
94
98
 
95
99
 
96
100
  def semantic_scores(
@@ -1 +0,0 @@
1
- __version__ = "2.5.0"
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