ulpwise 0.3.4__tar.gz → 0.3.5__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.
- {ulpwise-0.3.4 → ulpwise-0.3.5}/CHANGELOG.md +15 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/Cargo.lock +13 -13
- {ulpwise-0.3.4 → ulpwise-0.3.5}/Cargo.toml +2 -2
- {ulpwise-0.3.4 → ulpwise-0.3.5}/PKG-INFO +6 -4
- {ulpwise-0.3.4 → ulpwise-0.3.5}/README.md +5 -3
- {ulpwise-0.3.4 → ulpwise-0.3.5}/pyproject.toml +1 -1
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/__init__.py +1 -1
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/corpus/cases.json +76 -36
- {ulpwise-0.3.4 → ulpwise-0.3.5}/.github/dependabot.yml +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/.github/workflows/ci.yml +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/.github/workflows/release.yml +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/.gitignore +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/CONTRIBUTING.md +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/LICENSE-APACHE +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/LICENSE-MIT +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/examples/sqrt_knife_values.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/examples/torch_sqrt_conformance.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/__main__.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/corpus/__init__.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/plugin.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/scan.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/python/ulpwise/survey.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/edge.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/exact.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/knife.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/lib.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/py.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/src/ulp.rs +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-09/README.md +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-09/results.csv +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-09/results.md +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-10-half/README.md +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-10-half/results.csv +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/studies/accuracy-survey-2026-10-half/results.md +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/tests/test_core.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/tests/test_corpus.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/tests/test_scan.py +0 -0
- {ulpwise-0.3.4 → ulpwise-0.3.5}/tests/test_survey.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.5 (2026-10-28)
|
|
4
|
+
|
|
5
|
+
- kornia 0.9.0 (released 2026-10-23) contains every kornia fix in the corpus and torchrl 0.14.1 (2026-10-10) the four
|
|
6
|
+
pytorch/rl ones, so `fixed_in_release` is set on those 36 cases and they are plain passes instead of expected
|
|
7
|
+
failures. The weekly strict run had been failing on them as unexpected passes since 2026-10-12, the four torchrl
|
|
8
|
+
cases first and all 36 on 2026-10-26.
|
|
9
|
+
- Two more kornia cases, both merged upstream on 2026-10-09 and in 0.9.0. #5653: `gftt_response` took the smaller
|
|
10
|
+
eigenvalue as `0.5 * (trace - sqrt((trace**2 - 4 * det).abs()))`, and on a flat 9 x 9 footprint the blurred moments
|
|
11
|
+
are exactly zero, so the sqrt backward is `inf * 0 = nan` and the whole flat region gets a nan gradient; the case
|
|
12
|
+
takes the gradient of the summed response of an image with black top and bottom rows (2048 nan pixels on 0.8.3).
|
|
13
|
+
#5655: `equalize_clahe` wrote the clipping residual into the first `residual` histogram bins instead of spreading
|
|
14
|
+
it over every `max(256 // residual, 1)`-th bin as OpenCV does, which lifted the whole lookup table of a small tile
|
|
15
|
+
(up to +38 levels against `cv2.createCLAHE`); the case maps a 2 x 4 tile holding levels 0 and 100 with clip 40,
|
|
16
|
+
where level 100 came out as 255 instead of 159.
|
|
17
|
+
|
|
3
18
|
## 0.3.4 (2026-10-09)
|
|
4
19
|
|
|
5
20
|
- Regression corpus case for pytorch/rl #4504, merged upstream: `MultiCategorical.to_one_hot` iterated over `self.nvec`,
|
|
@@ -37,9 +37,9 @@ dependencies = [
|
|
|
37
37
|
|
|
38
38
|
[[package]]
|
|
39
39
|
name = "pyo3"
|
|
40
|
-
version = "0.
|
|
40
|
+
version = "0.30.1"
|
|
41
41
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
-
checksum = "
|
|
42
|
+
checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
|
|
43
43
|
dependencies = [
|
|
44
44
|
"libc",
|
|
45
45
|
"once_cell",
|
|
@@ -51,18 +51,18 @@ dependencies = [
|
|
|
51
51
|
|
|
52
52
|
[[package]]
|
|
53
53
|
name = "pyo3-build-config"
|
|
54
|
-
version = "0.
|
|
54
|
+
version = "0.30.1"
|
|
55
55
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
56
|
-
checksum = "
|
|
56
|
+
checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
|
|
57
57
|
dependencies = [
|
|
58
58
|
"target-lexicon",
|
|
59
59
|
]
|
|
60
60
|
|
|
61
61
|
[[package]]
|
|
62
62
|
name = "pyo3-ffi"
|
|
63
|
-
version = "0.
|
|
63
|
+
version = "0.30.1"
|
|
64
64
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
65
|
-
checksum = "
|
|
65
|
+
checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
|
|
66
66
|
dependencies = [
|
|
67
67
|
"libc",
|
|
68
68
|
"pyo3-build-config",
|
|
@@ -70,9 +70,9 @@ dependencies = [
|
|
|
70
70
|
|
|
71
71
|
[[package]]
|
|
72
72
|
name = "pyo3-macros"
|
|
73
|
-
version = "0.
|
|
73
|
+
version = "0.30.1"
|
|
74
74
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
75
|
-
checksum = "
|
|
75
|
+
checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
|
|
76
76
|
dependencies = [
|
|
77
77
|
"proc-macro2",
|
|
78
78
|
"pyo3-macros-backend",
|
|
@@ -82,9 +82,9 @@ dependencies = [
|
|
|
82
82
|
|
|
83
83
|
[[package]]
|
|
84
84
|
name = "pyo3-macros-backend"
|
|
85
|
-
version = "0.
|
|
85
|
+
version = "0.30.1"
|
|
86
86
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
87
|
-
checksum = "
|
|
87
|
+
checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"heck",
|
|
90
90
|
"proc-macro2",
|
|
@@ -103,9 +103,9 @@ dependencies = [
|
|
|
103
103
|
|
|
104
104
|
[[package]]
|
|
105
105
|
name = "syn"
|
|
106
|
-
version = "
|
|
106
|
+
version = "3.0.9"
|
|
107
107
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
-
checksum = "
|
|
108
|
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"proc-macro2",
|
|
111
111
|
"quote",
|
|
@@ -120,7 +120,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
120
120
|
|
|
121
121
|
[[package]]
|
|
122
122
|
name = "ulpwise"
|
|
123
|
-
version = "0.3.
|
|
123
|
+
version = "0.3.5"
|
|
124
124
|
dependencies = [
|
|
125
125
|
"pyo3",
|
|
126
126
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "ulpwise"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.5"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.86"
|
|
6
6
|
license = "MIT OR Apache-2.0"
|
|
@@ -15,7 +15,7 @@ name = "ulpwise"
|
|
|
15
15
|
crate-type = ["cdylib", "rlib"]
|
|
16
16
|
|
|
17
17
|
[dependencies]
|
|
18
|
-
pyo3 = { version = "0.
|
|
18
|
+
pyo3 = { version = "0.30", features = ["extension-module", "abi3-py39"], optional = true }
|
|
19
19
|
|
|
20
20
|
[features]
|
|
21
21
|
default = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ulpwise
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Framework :: Pytest
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -173,7 +173,7 @@ environment, side-install it and put it first on the path:
|
|
|
173
173
|
|
|
174
174
|
```sh
|
|
175
175
|
pip install --no-deps --target /tmp/kornia-0.8.3 kornia==0.8.3
|
|
176
|
-
PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia #
|
|
176
|
+
PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 34 present, 0 fixed on kornia 0.8.3; 0 present, 34 fixed on 0.9.0
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
| case | kind | merged |
|
|
@@ -230,13 +230,15 @@ PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 31 present, 0 fi
|
|
|
230
230
|
| pytorch #199850 `torch.erf` in bfloat16 and float16 on CPU returns 0 at and below 1.8e-7 and loses relative accuracy below 1e-3 (13404 bfloat16 ulps, 5 float16 ulps) | cancellation | open |
|
|
231
231
|
| pytorch #199867 `torch.special.logit` in float16 and bfloat16 on CPU rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, logit(0.499756) is -0.000488 for -0.000977 (512 float16 ulps, 64 bfloat16 ulps) | rounding | open |
|
|
232
232
|
| kornia #5505 `angle_error_mat` and `angle_error_vec` returned exactly 0 for every rotation below 0.03 degrees in float32 (`acos` next to 1, issue #5500) | cancellation | 2026-10-06 |
|
|
233
|
+
| kornia #5653 `gftt_response` had a nan gradient on every flat patch, `sqrt` of a zero discriminant (issue #5652) | gradient | 2026-10-09 |
|
|
234
|
+
| kornia #5655 `equalize_clahe` wrote the clipping residual into the first histogram bins, small tiles tens of levels brighter than OpenCV (issue #5654) | redistribution | 2026-10-09 |
|
|
233
235
|
| peft #3769 `add_weighted_adapter` with `combination_type='svd'` crashed for Conv1d and Conv3d LoRA layers | crash | open |
|
|
234
236
|
| peft #3830 OFT `module_dropout` was never applied, every training forward used all rotation blocks | no-op | open |
|
|
235
237
|
|
|
236
238
|
Cases marked `open` have an issue with the complete patch attached and no merged fix yet. Every case
|
|
237
239
|
is an expected failure until the installed release contains the fix (`fixed_in_release` in
|
|
238
|
-
`cases.json`; the timm and
|
|
239
|
-
pytorch ones are merged but not in a release yet), and the `max_ulp` check type measures the digits
|
|
240
|
+
`cases.json`; the timm, ultralytics, kornia (0.9.0) and pytorch/rl (0.14.1) fixes above are released,
|
|
241
|
+
the peft and pytorch ones are merged but not in a release yet), and the `max_ulp` check type measures the digits
|
|
240
242
|
directly. The ultralytics dataset and label cases build their one-image
|
|
241
243
|
dataset in a temporary directory and need no weights; two more ultralytics fixes (#26240, #26246) are not in
|
|
242
244
|
the corpus yet because their repros need model weights or the COCO evaluator.
|
|
@@ -144,7 +144,7 @@ environment, side-install it and put it first on the path:
|
|
|
144
144
|
|
|
145
145
|
```sh
|
|
146
146
|
pip install --no-deps --target /tmp/kornia-0.8.3 kornia==0.8.3
|
|
147
|
-
PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia #
|
|
147
|
+
PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 34 present, 0 fixed on kornia 0.8.3; 0 present, 34 fixed on 0.9.0
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
| case | kind | merged |
|
|
@@ -201,13 +201,15 @@ PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 31 present, 0 fi
|
|
|
201
201
|
| pytorch #199850 `torch.erf` in bfloat16 and float16 on CPU returns 0 at and below 1.8e-7 and loses relative accuracy below 1e-3 (13404 bfloat16 ulps, 5 float16 ulps) | cancellation | open |
|
|
202
202
|
| pytorch #199867 `torch.special.logit` in float16 and bfloat16 on CPU rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, logit(0.499756) is -0.000488 for -0.000977 (512 float16 ulps, 64 bfloat16 ulps) | rounding | open |
|
|
203
203
|
| kornia #5505 `angle_error_mat` and `angle_error_vec` returned exactly 0 for every rotation below 0.03 degrees in float32 (`acos` next to 1, issue #5500) | cancellation | 2026-10-06 |
|
|
204
|
+
| kornia #5653 `gftt_response` had a nan gradient on every flat patch, `sqrt` of a zero discriminant (issue #5652) | gradient | 2026-10-09 |
|
|
205
|
+
| kornia #5655 `equalize_clahe` wrote the clipping residual into the first histogram bins, small tiles tens of levels brighter than OpenCV (issue #5654) | redistribution | 2026-10-09 |
|
|
204
206
|
| peft #3769 `add_weighted_adapter` with `combination_type='svd'` crashed for Conv1d and Conv3d LoRA layers | crash | open |
|
|
205
207
|
| peft #3830 OFT `module_dropout` was never applied, every training forward used all rotation blocks | no-op | open |
|
|
206
208
|
|
|
207
209
|
Cases marked `open` have an issue with the complete patch attached and no merged fix yet. Every case
|
|
208
210
|
is an expected failure until the installed release contains the fix (`fixed_in_release` in
|
|
209
|
-
`cases.json`; the timm and
|
|
210
|
-
pytorch ones are merged but not in a release yet), and the `max_ulp` check type measures the digits
|
|
211
|
+
`cases.json`; the timm, ultralytics, kornia (0.9.0) and pytorch/rl (0.14.1) fixes above are released,
|
|
212
|
+
the peft and pytorch ones are merged but not in a release yet), and the `max_ulp` check type measures the digits
|
|
211
213
|
directly. The ultralytics dataset and label cases build their one-image
|
|
212
214
|
dataset in a temporary directory and need no weights; two more ultralytics fixes (#26240, #26246) are not in
|
|
213
215
|
the corpus yet because their repros need model weights or the COCO evaluator.
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ulpwise"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.5"
|
|
8
8
|
description = "Numerical conformance testing for ML code: float edge values, exact rounding oracles, knife-edge finders and a pytest plugin"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT OR Apache-2.0" }
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"torch",
|
|
15
15
|
"kornia"
|
|
16
16
|
],
|
|
17
|
-
"fixed_in_release":
|
|
17
|
+
"fixed_in_release": "0.9.0",
|
|
18
18
|
"repro": "import torch\nimport kornia.filters as KF\nxs = torch.arange(-4, 5, dtype=torch.float64)\ny, x = torch.meshgrid(xs, xs, indexing='ij')\ndxx = KF.spatial_gradient((x * x)[None, None], mode='sobel', order=2)[0, 0, 0, 4, 4]\ndxy = KF.spatial_gradient((x * y)[None, None], mode='sobel', order=2)[0, 0, 1, 4, 4]\ndxy_diff = KF.spatial_gradient((x * y)[None, None], mode='diff', order=2)[0, 0, 1, 4, 4]\nactual = [dxx.item(), dxy.item(), dxy_diff.item()]\nexpected = [2.0, 1.0, 1.0]\n",
|
|
19
19
|
"check": {
|
|
20
20
|
"type": "sign"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"torch",
|
|
34
34
|
"kornia"
|
|
35
35
|
],
|
|
36
|
-
"fixed_in_release":
|
|
36
|
+
"fixed_in_release": "0.9.0",
|
|
37
37
|
"repro": "import torch\nimport kornia.feature as KFe\nxs = torch.arange(-4, 5, dtype=torch.float64)\ny, x = torch.meshgrid(xs, xs, indexing='ij')\ndet_sobel_xy = KFe.hessian_response((x * y)[None, None], grads_mode='sobel')[0, 0, 4, 4]\ndet_diff_quad = KFe.hessian_response((x * x + y * y)[None, None], grads_mode='diff')[0, 0, 4, 4]\ndet_sobel_degenerate = KFe.hessian_response(((x + y) ** 2 / 2)[None, None], grads_mode='sobel')[0, 0, 4, 4]\nactual = [det_sobel_xy.item(), det_diff_quad.item(), det_sobel_degenerate.item()]\nexpected = [-1.0, 4.0, 0.0]\n",
|
|
38
38
|
"check": {
|
|
39
39
|
"type": "allclose",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"torch",
|
|
55
55
|
"kornia"
|
|
56
56
|
],
|
|
57
|
-
"fixed_in_release":
|
|
57
|
+
"fixed_in_release": "0.9.0",
|
|
58
58
|
"repro": "import torch\nimport kornia.feature as KF\n# Oxford ellipses [x, y, a, b, c]; the LAF's A must satisfy A @ A.T == inverse([[a, b], [b, c]])\nells = torch.tensor([[[0.0, 0.0, 1.0, 0.5, 1.0], [3.0, -2.0, 2.0, -0.9, 0.5]]], dtype=torch.float64)\nA = KF.ellipse_to_laf(ells)[..., :2]\nregion = torch.linalg.inv(A @ A.transpose(-1, -2))[0]\nactual = region.reshape(-1).tolist()\nexpected = [1.0, 0.5, 0.5, 1.0, 2.0, -0.9, -0.9, 0.5]\n",
|
|
59
59
|
"check": {
|
|
60
60
|
"type": "allclose",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"torch",
|
|
97
97
|
"torchrl"
|
|
98
98
|
],
|
|
99
|
-
"fixed_in_release":
|
|
99
|
+
"fixed_in_release": "0.14.1",
|
|
100
100
|
"repro": "import torch\nfrom torchrl.envs.transforms import ActionDiscretizer\nt = ActionDiscretizer(num_intervals=49)\nt.dtype = torch.float32\nactual = [t.custom_arange(n, torch.device('cpu')).numel() for n in (49, 98, 103, 107, 10)]\nexpected = [49, 98, 103, 107, 10]\n",
|
|
101
101
|
"check": {
|
|
102
102
|
"type": "equal"
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"torch",
|
|
116
116
|
"torchrl"
|
|
117
117
|
],
|
|
118
|
-
"fixed_in_release":
|
|
118
|
+
"fixed_in_release": "0.14.1",
|
|
119
119
|
"repro": "from torchrl.data.replay_buffers import ListStorage, PrioritizedSampler, ReplayBuffer\nfrom torchrl.data.replay_buffers.scheduler import StepScheduler\nrb = ReplayBuffer(storage=ListStorage(16), sampler=PrioritizedSampler(16, alpha=0.5, beta=0.5))\nsched = StepScheduler(rb, 'alpha', gamma=-0.2, n_steps=1, mode='additive', min_value=0)\nseen = []\nfor _ in range(4):\n sched.step()\n seen.append(float(rb.sampler.alpha))\nactual = seen\nexpected = [0.3, 0.1, 0.0, 0.0]\n",
|
|
120
120
|
"check": {
|
|
121
121
|
"type": "allclose",
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"torch",
|
|
137
137
|
"torchrl"
|
|
138
138
|
],
|
|
139
|
-
"fixed_in_release":
|
|
139
|
+
"fixed_in_release": "0.14.1",
|
|
140
140
|
"repro": "import io\nimport torch\nfrom torchrl.data.replay_buffers import ListStorage, PrioritizedSampler, ReplayBuffer\nfrom torchrl.data.replay_buffers.scheduler import StepScheduler\nrb = ReplayBuffer(storage=ListStorage(16), sampler=PrioritizedSampler(16, alpha=0.5, beta=0.5))\nsched = StepScheduler(rb, 'alpha', gamma=0.5, n_steps=1)\nsched.step()\nsched.step()\nbuf = io.BytesIO()\ntorch.save(sched.state_dict(), buf)\nbuf.seek(0)\nstate = torch.load(buf, weights_only=False)\nactual = [state['_step_cnt']]\nexpected = [2]\n",
|
|
141
141
|
"check": {
|
|
142
142
|
"type": "equal"
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"torch",
|
|
156
156
|
"torchrl"
|
|
157
157
|
],
|
|
158
|
-
"fixed_in_release":
|
|
158
|
+
"fixed_in_release": "0.14.1",
|
|
159
159
|
"repro": "import torch\nfrom torchrl.data import MultiCategorical\nspec = MultiCategorical([3, 2], shape=(4, 2))\nhot = spec.to_one_hot(spec.rand())\nscalar = MultiCategorical([5]).to_one_hot(torch.tensor(3))\nactual = [list(hot.shape), hot.dtype == torch.bool, int(hot.sum()), list(scalar.shape), int(scalar.sum()), bool(scalar[3])]\nexpected = [[4, 5], True, 8, [5], 1, True]\n",
|
|
160
160
|
"check": {
|
|
161
161
|
"type": "equal"
|
|
@@ -318,7 +318,7 @@
|
|
|
318
318
|
"torch",
|
|
319
319
|
"kornia"
|
|
320
320
|
],
|
|
321
|
-
"fixed_in_release":
|
|
321
|
+
"fixed_in_release": "0.9.0",
|
|
322
322
|
"repro": "import torch\nimport kornia.geometry.conversions as C\naxis = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float64) / 14.0**0.5\nv = (9.99e-4 * axis)[None]\nactual = C.axis_angle_to_rotation_matrix(v).flatten().tolist()\nexpected = C.quaternion_to_rotation_matrix(C.axis_angle_to_quaternion(v)).flatten().tolist()\n",
|
|
323
323
|
"check": {
|
|
324
324
|
"type": "allclose",
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
"torch",
|
|
341
341
|
"kornia"
|
|
342
342
|
],
|
|
343
|
-
"fixed_in_release":
|
|
343
|
+
"fixed_in_release": "0.9.0",
|
|
344
344
|
"repro": "import torch\nfrom kornia.geometry.liegroup import Se3, So3\nrot = So3.exp(torch.tensor([[1e-4, 0.0, 0.0]], dtype=torch.float32))\nse = Se3.exp(torch.tensor([[1.0, 0.0, 0.0, 0.0, 0.0, 1e-4]], dtype=torch.float32))\nactual = [rot.log()[0, 0].item(), se.t[0, 1].item()]\nexpected = [1e-4, 5e-5]\n",
|
|
345
345
|
"check": {
|
|
346
346
|
"type": "allclose",
|
|
@@ -464,7 +464,7 @@
|
|
|
464
464
|
"torch",
|
|
465
465
|
"kornia"
|
|
466
466
|
],
|
|
467
|
-
"fixed_in_release":
|
|
467
|
+
"fixed_in_release": "0.9.0",
|
|
468
468
|
"repro": "import torch\nfrom kornia.geometry.liegroup import Se2\nv = torch.tensor([[1.0, 2.0, 1e-8]], dtype=torch.float64) # translation (1, 2) and a turn of 1e-8 rad\ng = Se2.exp(v)\nactual = g.matrix()[0, :2, 2].tolist() + g.log().flatten().tolist()\nb = 0.5e-8 # (1 - cos(theta)) / theta = theta / 2 - theta^3 / 24; sin(theta) / theta = 1 - theta^2 / 6 rounds to 1\nexpected = [1.0 - 2.0 * b, 2.0 + b, 1.0, 2.0, 1e-8]\n",
|
|
469
469
|
"check": {
|
|
470
470
|
"type": "allclose",
|
|
@@ -485,7 +485,7 @@
|
|
|
485
485
|
"torch",
|
|
486
486
|
"kornia"
|
|
487
487
|
],
|
|
488
|
-
"fixed_in_release":
|
|
488
|
+
"fixed_in_release": "0.9.0",
|
|
489
489
|
"repro": "import torch\nfrom kornia.geometry.linalg import point_line_distance\nline = torch.tensor([[0.0, 1.0, -1.0]], dtype=torch.float64) # the line y = 1\npoint = torch.tensor([[[3.0, 5.0, 2.0]]], dtype=torch.float64) # the homogeneous point (1.5, 2.5): w = 2\nactual = point_line_distance(point, line).flatten().tolist()\nexpected = [1.5]\n",
|
|
490
490
|
"check": {
|
|
491
491
|
"type": "allclose",
|
|
@@ -506,7 +506,7 @@
|
|
|
506
506
|
"torch",
|
|
507
507
|
"kornia"
|
|
508
508
|
],
|
|
509
|
-
"fixed_in_release":
|
|
509
|
+
"fixed_in_release": "0.9.0",
|
|
510
510
|
"repro": "import torch\nfrom kornia.geometry.quaternion import Quaternion\nq = Quaternion(torch.tensor([[-1.0, 0.0, 0.0, 0.0]], dtype=torch.float64)) # a half turn: angle pi, axis undefined\nroot = q ** 0.5\nactual = root.data.flatten().tolist() + (root * root).data.flatten().tolist()\nexpected = [0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0]\n",
|
|
511
511
|
"check": {
|
|
512
512
|
"type": "allclose",
|
|
@@ -527,7 +527,7 @@
|
|
|
527
527
|
"torch",
|
|
528
528
|
"kornia"
|
|
529
529
|
],
|
|
530
|
-
"fixed_in_release":
|
|
530
|
+
"fixed_in_release": "0.9.0",
|
|
531
531
|
"repro": "import torch\nfrom kornia.geometry.liegroup import So2\nangle = torch.tensor([[0.0], [1.5707963267948966]], dtype=torch.float64) # (B, 1): one angle per sample, as a column\npoints = torch.tensor([[1.0, 0.0], [1.0, 0.0]], dtype=torch.float64)\nrotated = So2.exp(angle) * points\nactual = [list(rotated.shape), rotated.flatten().tolist()]\nexpected = [[2, 2], [1.0, 0.0, 0.0, 1.0]]\n",
|
|
532
532
|
"check": {
|
|
533
533
|
"type": "allclose",
|
|
@@ -548,7 +548,7 @@
|
|
|
548
548
|
"torch",
|
|
549
549
|
"kornia"
|
|
550
550
|
],
|
|
551
|
-
"fixed_in_release":
|
|
551
|
+
"fixed_in_release": "0.9.0",
|
|
552
552
|
"repro": "import torch\nfrom kornia.geometry.solvers import solve_cubic\ncoeffs = torch.tensor([[1e-30, 0.0, 2.0, -6.0]], dtype=torch.float64) # 1e-30 x^3 + 2 x - 6: the real root is 3\nactual = solve_cubic(coeffs).flatten().tolist()\nexpected = [3.0, 0.0, 0.0]\n",
|
|
553
553
|
"check": {
|
|
554
554
|
"type": "allclose",
|
|
@@ -569,7 +569,7 @@
|
|
|
569
569
|
"torch",
|
|
570
570
|
"kornia"
|
|
571
571
|
],
|
|
572
|
-
"fixed_in_release":
|
|
572
|
+
"fixed_in_release": "0.9.0",
|
|
573
573
|
"repro": "import torch\nfrom kornia.color import RgbToGrayscale, rgb_to_grayscale\nimage = torch.full((1, 3, 2, 2), 200, dtype=torch.uint8)\nactual = [int(RgbToGrayscale()(image).max()), int(RgbToGrayscale()(image).min())]\nexpected = [int(rgb_to_grayscale(image).max()), int(rgb_to_grayscale(image).min())]\n",
|
|
574
574
|
"check": {
|
|
575
575
|
"type": "equal"
|
|
@@ -588,7 +588,7 @@
|
|
|
588
588
|
"torch",
|
|
589
589
|
"kornia"
|
|
590
590
|
],
|
|
591
|
-
"fixed_in_release":
|
|
591
|
+
"fixed_in_release": "0.9.0",
|
|
592
592
|
"repro": "import torch\nfrom kornia.geometry.subpix import conv_soft_argmax2d\nquiet = torch.zeros(1, 1, 7, 7)\nquiet[0, 0, 6, 6] = 1.0 # a weak bump in the bottom right corner\nloud = quiet.clone()\nloud[0, 0, 0, 0] = 200.0 # a peak far away, 200 temperatures above the bump\nkwargs = dict(kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), temperature=torch.tensor(1.0), normalized_coordinates=True)\nactual = conv_soft_argmax2d(loud, **kwargs)[0, 0, :, 6, 6].tolist()\nexpected = conv_soft_argmax2d(quiet, **kwargs)[0, 0, :, 6, 6].tolist()\n",
|
|
593
593
|
"check": {
|
|
594
594
|
"type": "allclose",
|
|
@@ -609,7 +609,7 @@
|
|
|
609
609
|
"torch",
|
|
610
610
|
"kornia"
|
|
611
611
|
],
|
|
612
|
-
"fixed_in_release":
|
|
612
|
+
"fixed_in_release": "0.9.0",
|
|
613
613
|
"repro": "import torch\nfrom kornia.filters import get_gaussian_discrete_kernel1d\none = get_gaussian_discrete_kernel1d(1, 1.0)\nfive = get_gaussian_discrete_kernel1d(5, 1.0)\nactual = [one.numel(), five.numel(), one.flatten().tolist()]\nexpected = [1, 5, [1.0]]\n",
|
|
614
614
|
"check": {
|
|
615
615
|
"type": "equal"
|
|
@@ -628,7 +628,7 @@
|
|
|
628
628
|
"torch",
|
|
629
629
|
"kornia"
|
|
630
630
|
],
|
|
631
|
-
"fixed_in_release":
|
|
631
|
+
"fixed_in_release": "0.9.0",
|
|
632
632
|
"repro": "import torch\nfrom kornia.geometry.liegroup import Se3, So3\nv = torch.tensor([[1.0, 2.0, 3.0, 0.0, 0.0, 0.0]], dtype=torch.float64) # upsilon = (1, 2, 3), omega = 0\njac = torch.autograd.functional.jacobian(lambda x: Se3.exp(x).matrix()[:, :3, 3], v)[0, :, 0, :]\nactual = jac[:, 3:].flatten().tolist()\nexpected = (-0.5 * So3.hat(v[0, :3])).flatten().tolist()\n",
|
|
633
633
|
"check": {
|
|
634
634
|
"type": "allclose",
|
|
@@ -649,7 +649,7 @@
|
|
|
649
649
|
"torch",
|
|
650
650
|
"kornia"
|
|
651
651
|
],
|
|
652
|
-
"fixed_in_release":
|
|
652
|
+
"fixed_in_release": "0.9.0",
|
|
653
653
|
"repro": "import torch\nfrom kornia.geometry.quaternion import Quaternion\ndata = torch.tensor([[1.0, 0.0, 0.0, 0.0]], dtype=torch.float64, requires_grad=True)\nq = Quaternion(data)\nq.polar_angle.sum().backward()\ngrad = data.grad if data.grad is not None else q.data.grad\nactual = grad.flatten().tolist()\nexpected = [0.0, 0.0, 0.0, 0.0]\n",
|
|
654
654
|
"check": {
|
|
655
655
|
"type": "equal"
|
|
@@ -668,7 +668,7 @@
|
|
|
668
668
|
"torch",
|
|
669
669
|
"kornia"
|
|
670
670
|
],
|
|
671
|
-
"fixed_in_release":
|
|
671
|
+
"fixed_in_release": "0.9.0",
|
|
672
672
|
"repro": "import torch\nfrom kornia.geometry.epipolar import decompose_essential_matrix\nE = torch.tensor([[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]]) # [t]_x with t = e_z and R = I\nR1, R2, t = decompose_essential_matrix(E)\nactual = [list(R1.shape), list(R2.shape), list(t.shape)]\nexpected = [[3, 3], [3, 3], [3, 1]]\n",
|
|
673
673
|
"check": {
|
|
674
674
|
"type": "equal"
|
|
@@ -687,7 +687,7 @@
|
|
|
687
687
|
"torch",
|
|
688
688
|
"kornia"
|
|
689
689
|
],
|
|
690
|
-
"fixed_in_release":
|
|
690
|
+
"fixed_in_release": "0.9.0",
|
|
691
691
|
"repro": "import torch\nfrom kornia.geometry.plane import Hyperplane\npoints = [torch.tensor([p], dtype=torch.float64, requires_grad=True) for p in ([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0])]\nplane = Hyperplane.through(*points)\nplane.normal.data.sum().backward()\nactual = [bool(torch.isfinite(p.grad).all()) for p in points] + plane.normal.data.flatten().abs().tolist()\nexpected = [True, True, True, 0.0, 0.0, 1.0]\n",
|
|
692
692
|
"check": {
|
|
693
693
|
"type": "equal"
|
|
@@ -706,7 +706,7 @@
|
|
|
706
706
|
"torch",
|
|
707
707
|
"kornia"
|
|
708
708
|
],
|
|
709
|
-
"fixed_in_release":
|
|
709
|
+
"fixed_in_release": "0.9.0",
|
|
710
710
|
"repro": "import torch\nfrom kornia.geometry.vector import Vector3\nactual = Vector3(torch.zeros(1, 3, dtype=torch.float16)).normalized().data.flatten().tolist()\nexpected = [0.0, 0.0, 0.0]\n",
|
|
711
711
|
"check": {
|
|
712
712
|
"type": "equal"
|
|
@@ -725,7 +725,7 @@
|
|
|
725
725
|
"torch",
|
|
726
726
|
"kornia"
|
|
727
727
|
],
|
|
728
|
-
"fixed_in_release":
|
|
728
|
+
"fixed_in_release": "0.9.0",
|
|
729
729
|
"repro": "import torch\nfrom kornia.filters import otsu_threshold\nx = torch.tensor([[[[-4.0, -3.0], [-2.0, -1.0]]]])\nmask, threshold = otsu_threshold(x, return_mask=True)\nactual = mask.flatten().tolist()\nexpected = [False, False, True, True]\n",
|
|
730
730
|
"check": {
|
|
731
731
|
"type": "equal"
|
|
@@ -744,7 +744,7 @@
|
|
|
744
744
|
"torch",
|
|
745
745
|
"kornia"
|
|
746
746
|
],
|
|
747
|
-
"fixed_in_release":
|
|
747
|
+
"fixed_in_release": "0.9.0",
|
|
748
748
|
"repro": "import torch\nfrom kornia.losses import MS_SSIMLoss\ntorch.manual_seed(0)\nimg1 = torch.rand(1, 3, 16, 20)\nimg2 = torch.rand(1, 3, 16, 20)\nactual = list(MS_SSIMLoss(sigmas=(0.5, 1.3), reduction=\"none\")(img1, img2).shape)\nexpected = [1, 16, 20]\n",
|
|
749
749
|
"check": {
|
|
750
750
|
"type": "equal"
|
|
@@ -763,7 +763,7 @@
|
|
|
763
763
|
"torch",
|
|
764
764
|
"kornia"
|
|
765
765
|
],
|
|
766
|
-
"fixed_in_release":
|
|
766
|
+
"fixed_in_release": "0.9.0",
|
|
767
767
|
"repro": "import torch\nfrom kornia.geometry.epipolar import sampson_epipolar_distance\nF = torch.tensor([[[0.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]]]) # a pure horizontal shift: the epiline of (x, y) is y' = y\npts1 = torch.zeros(1, 1, 2)\npts2 = torch.tensor([[[2.0, 0.0]]]) # on its epiline\nactual = sampson_epipolar_distance(pts1, pts2, F, squared=False).item()\nexpected = 0.0\n",
|
|
768
768
|
"check": {
|
|
769
769
|
"type": "equal"
|
|
@@ -782,7 +782,7 @@
|
|
|
782
782
|
"torch",
|
|
783
783
|
"kornia"
|
|
784
784
|
],
|
|
785
|
-
"fixed_in_release":
|
|
785
|
+
"fixed_in_release": "0.9.0",
|
|
786
786
|
"repro": "import torch\nfrom kornia.geometry.epipolar import sampson_epipolar_distance\nF = torch.tensor([[[0.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]]]) # a pure horizontal shift: the epiline of (x, y) is y' = y\npts1 = torch.zeros(1, 1, 2)\npts2 = torch.tensor([[[2.0, 1.0]]]) # one pixel off its epiline\nactual = (sampson_epipolar_distance(pts1, pts2, 1e-4 * F) / sampson_epipolar_distance(pts1, pts2, F)).item()\nexpected = 1.0\n",
|
|
787
787
|
"check": {
|
|
788
788
|
"type": "allclose",
|
|
@@ -803,7 +803,7 @@
|
|
|
803
803
|
"torch",
|
|
804
804
|
"kornia"
|
|
805
805
|
],
|
|
806
|
-
"fixed_in_release":
|
|
806
|
+
"fixed_in_release": "0.9.0",
|
|
807
807
|
"repro": "import torch\nimport kornia\nfrom kornia.augmentation import RandomHue\ntorch.manual_seed(0)\nimage = torch.rand(1, 3, 4, 4, dtype=torch.float64)\nhue = kornia.color.rgb_to_hsv(image)[:, 0]\nshifted = kornia.color.rgb_to_hsv(RandomHue(hue=(0.5, 0.5), p=1.0)(image))[:, 0]\nactual = (torch.remainder(shifted - hue, 2 * torch.pi) - torch.pi).abs().max().item() # circular distance from a half turn\nexpected = 0.0\n",
|
|
808
808
|
"check": {
|
|
809
809
|
"type": "allclose",
|
|
@@ -824,7 +824,7 @@
|
|
|
824
824
|
"torch",
|
|
825
825
|
"kornia"
|
|
826
826
|
],
|
|
827
|
-
"fixed_in_release":
|
|
827
|
+
"fixed_in_release": "0.9.0",
|
|
828
828
|
"repro": "import torch\nfrom kornia.geometry.liegroup import So3\nzero = torch.zeros(3, dtype=torch.float64)\nactual = torch.autograd.functional.hessian(lambda v: So3.exp(v).q.data[0], zero).flatten().tolist()\nexpected = (-0.25 * torch.eye(3, dtype=torch.float64)).flatten().tolist()\n",
|
|
829
829
|
"check": {
|
|
830
830
|
"type": "allclose",
|
|
@@ -845,7 +845,7 @@
|
|
|
845
845
|
"torch",
|
|
846
846
|
"kornia"
|
|
847
847
|
],
|
|
848
|
-
"fixed_in_release":
|
|
848
|
+
"fixed_in_release": "0.9.0",
|
|
849
849
|
"repro": "import torch\nfrom kornia.losses import MS_SSIMLoss\ntorch.manual_seed(0)\nimg1 = torch.randint(0, 256, (1, 1, 48, 40), dtype=torch.uint8)\nimg2 = torch.randint(0, 256, (1, 1, 48, 40), dtype=torch.uint8)\nactual = MS_SSIMLoss(data_range=255.0)(img1, img2).item()\nexpected = MS_SSIMLoss()(img1.float() / 255, img2.float() / 255).item()\n",
|
|
850
850
|
"check": {
|
|
851
851
|
"type": "allclose",
|
|
@@ -866,7 +866,7 @@
|
|
|
866
866
|
"torch",
|
|
867
867
|
"kornia"
|
|
868
868
|
],
|
|
869
|
-
"fixed_in_release":
|
|
869
|
+
"fixed_in_release": "0.9.0",
|
|
870
870
|
"repro": "import torch\nfrom kornia.geometry.liegroup import So3\nomega = torch.tensor([[0.48, 0.6, 0.64]]) * 45.0 # 45 rad about a unit axis\nactual = So3.right_jacobian(omega.half()).flatten().tolist()\nexpected = So3.right_jacobian(omega.double()).flatten().tolist()\n",
|
|
871
871
|
"check": {
|
|
872
872
|
"type": "allclose",
|
|
@@ -887,7 +887,7 @@
|
|
|
887
887
|
"torch",
|
|
888
888
|
"kornia"
|
|
889
889
|
],
|
|
890
|
-
"fixed_in_release":
|
|
890
|
+
"fixed_in_release": "0.9.0",
|
|
891
891
|
"repro": "import math\nimport torch\nfrom kornia.geometry.quaternion import Quaternion, average_quaternions\nq1 = torch.tensor([1.0, 0.0, 0.0, 0.0])\nq2 = torch.tensor([1.0, 1.0, 0.0, 0.0]) / math.sqrt(2.0) # a quarter turn about x\nmean = average_quaternions(Quaternion(torch.stack([q1, 3.0 * q2]))).data.flatten()\nactual = (mean * torch.sign(mean[0])).tolist() # the sign of a quaternion is free\nexpected = [math.cos(math.pi / 8), math.sin(math.pi / 8), 0.0, 0.0] # the bisector, an eighth of a turn\n",
|
|
892
892
|
"check": {
|
|
893
893
|
"type": "allclose",
|
|
@@ -908,7 +908,7 @@
|
|
|
908
908
|
"torch",
|
|
909
909
|
"kornia"
|
|
910
910
|
],
|
|
911
|
-
"fixed_in_release":
|
|
911
|
+
"fixed_in_release": "0.9.0",
|
|
912
912
|
"repro": "import torch\nfrom kornia.geometry.plane import Hyperplane\nfrom kornia.geometry.vector import Vector3\np0 = Vector3(torch.tensor([0.0, 0.0, 0.0], dtype=torch.float16))\np1 = Vector3(torch.tensor([300.0, 0.0, 0.0], dtype=torch.float16))\np2 = Vector3(torch.tensor([0.0, 300.0, 0.0], dtype=torch.float16))\nactual = Hyperplane.through(p0, p1, p2).normal.data.flatten().tolist()\nexpected = [0.0, 0.0, -1.0] # (p2 - p0) x (p1 - p0)\n",
|
|
913
913
|
"check": {
|
|
914
914
|
"type": "allclose",
|
|
@@ -929,7 +929,7 @@
|
|
|
929
929
|
"torch",
|
|
930
930
|
"kornia"
|
|
931
931
|
],
|
|
932
|
-
"fixed_in_release":
|
|
932
|
+
"fixed_in_release": "0.9.0",
|
|
933
933
|
"repro": "import torch\nfrom kornia.filters import filter2d\ntorch.manual_seed(0)\nimage = torch.rand(2, 3, 6, 6)\nkernel = torch.rand(2, 3, 3) # one kernel per sample\nactual = (filter2d(image.to(memory_format=torch.channels_last), kernel) - filter2d(image, kernel)).abs().max().item()\nexpected = 0.0\n",
|
|
934
934
|
"check": {
|
|
935
935
|
"type": "equal"
|
|
@@ -948,7 +948,7 @@
|
|
|
948
948
|
"torch",
|
|
949
949
|
"kornia"
|
|
950
950
|
],
|
|
951
|
-
"fixed_in_release":
|
|
951
|
+
"fixed_in_release": "0.9.0",
|
|
952
952
|
"repro": "import torch\nfrom kornia.losses import lovasz_hinge_loss\ntorch.manual_seed(0)\npred = torch.randn(2, 1, 4, 4)\ntarget = torch.randint(0, 2, (2, 4, 4))\nactual = [str(lovasz_hinge_loss(pred.half(), target).dtype), str(lovasz_hinge_loss(pred.double(), target).dtype)]\nexpected = [\"torch.float16\", \"torch.float64\"]\n",
|
|
953
953
|
"check": {
|
|
954
954
|
"type": "equal"
|
|
@@ -967,7 +967,7 @@
|
|
|
967
967
|
"torch",
|
|
968
968
|
"kornia"
|
|
969
969
|
],
|
|
970
|
-
"fixed_in_release":
|
|
970
|
+
"fixed_in_release": "0.9.0",
|
|
971
971
|
"repro": "import torch\nfrom kornia.filters import get_box_kernel1d\nkernel = get_box_kernel1d(3)\nkernel[0, 0] = 0.0\nactual = kernel.flatten().tolist()\nexpected = [0.0, 1.0 / 3.0, 1.0 / 3.0]\n",
|
|
972
972
|
"check": {
|
|
973
973
|
"type": "allclose",
|
|
@@ -1136,7 +1136,7 @@
|
|
|
1136
1136
|
"torch",
|
|
1137
1137
|
"kornia"
|
|
1138
1138
|
],
|
|
1139
|
-
"fixed_in_release":
|
|
1139
|
+
"fixed_in_release": "0.9.0",
|
|
1140
1140
|
"repro": "import torch\nimport kornia\nR1 = kornia.geometry.axis_angle_to_rotation_matrix(torch.tensor([[0.3, -0.5, 0.8]], dtype=torch.float64))\nR2 = R1 @ kornia.geometry.axis_angle_to_rotation_matrix(torch.deg2rad(torch.tensor([[0.0, 0.0, 0.01]], dtype=torch.float64)))\nv1 = torch.tensor([[0.0, 0.6, 0.8]], dtype=torch.float64)\nv2 = (kornia.geometry.axis_angle_to_rotation_matrix(torch.deg2rad(torch.tensor([[0.01, 0.0, 0.0]], dtype=torch.float64))) @ v1[..., None])[..., 0]\nactual = [kornia.metrics.angle_error_mat(R1.float(), R2.float()).item(), kornia.metrics.angle_error_vec(v1.float(), v2.float()).item()]\nexpected = [0.01, 0.01]\n",
|
|
1141
1141
|
"check": {
|
|
1142
1142
|
"type": "allclose",
|
|
@@ -1186,6 +1186,46 @@
|
|
|
1186
1186
|
"type": "sign"
|
|
1187
1187
|
},
|
|
1188
1188
|
"before_fix": "[0.0] on peft main 91ca7945; with the fix the ten forwards spread by 0.56"
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
"id": "kornia-5652-gftt-response-flat-patch-nan-gradient",
|
|
1192
|
+
"repo": "kornia/kornia",
|
|
1193
|
+
"pr": 5653,
|
|
1194
|
+
"issue": 5652,
|
|
1195
|
+
"merged_at": "2026-10-09T11:16:37Z",
|
|
1196
|
+
"kind": "gradient",
|
|
1197
|
+
"title": "gftt_response had a nan gradient on every flat patch",
|
|
1198
|
+
"symptom": "The smaller eigenvalue of the structure tensor was 0.5 * (trace - sqrt((trace**2 - 4 * det).abs())). Wherever the 9 x 9 footprint is flat (zero padding, a black border, a saturated region) the blurred moments are exactly zero, the sqrt backward is inf * 0 = nan and the whole flat region gets a nan gradient, while harris_response and hessian_response stay finite. The patch writes the discriminant as the sum of squares (dx2 - dy2)**2 + 4 * dxy**2, which is never negative, and guards its sqrt with a where, so the gradient is zero where the discriminant is zero; the forward moves at rounding level only.",
|
|
1199
|
+
"requires": [
|
|
1200
|
+
"torch",
|
|
1201
|
+
"kornia"
|
|
1202
|
+
],
|
|
1203
|
+
"fixed_in_release": "0.9.0",
|
|
1204
|
+
"repro": "import torch\nimport kornia\ntorch.manual_seed(0)\nimg = torch.zeros(1, 1, 64, 64)\nimg[..., 16:48, :] = torch.rand(1, 1, 32, 64)\nimg.requires_grad_(True)\n(grad,) = torch.autograd.grad(kornia.feature.gftt_response(img).sum(), img)\nactual = [grad[0, 0, 0, 0].item(), grad[0, 0, 63, 63].item(), float(torch.isfinite(grad).all())]\nexpected = [0.0, 0.0, 1.0]\n",
|
|
1205
|
+
"check": {
|
|
1206
|
+
"type": "equal"
|
|
1207
|
+
},
|
|
1208
|
+
"before_fix": "[nan, nan, 0.0] on kornia 0.8.3, 2048 nan pixels in the flat rows"
|
|
1209
|
+
},
|
|
1210
|
+
{
|
|
1211
|
+
"id": "kornia-5654-equalize-clahe-residual-in-first-bins",
|
|
1212
|
+
"repo": "kornia/kornia",
|
|
1213
|
+
"pr": 5655,
|
|
1214
|
+
"issue": 5654,
|
|
1215
|
+
"merged_at": "2026-10-09T10:38:46Z",
|
|
1216
|
+
"kind": "redistribution",
|
|
1217
|
+
"title": "equalize_clahe wrote the clipping residual into the first histogram bins, small tiles came out tens of levels brighter than OpenCV",
|
|
1218
|
+
"symptom": "After clipping a tile histogram at the clip limit, the residual of the clipped pixels was written into the first `residual` bins instead of being spread over every max(256 // residual, 1)-th bin from bin 0 as OpenCV does. The residual piled onto the darkest levels and lifted the whole lookup table, so small tiles came out up to 38 levels brighter than cv2.createCLAHE (mean over a 96 x 96 image with an 8 x 8 grid and clip 2.0). On a 2 x 4 tile holding levels 0 and 100 with clip 40, level 100 mapped to 255 where the spread residual gives 159. The patch spreads the residual in one helper shared by the scalar clip path, the per-sample clip path of RandomClahe and the differentiable path.",
|
|
1219
|
+
"requires": [
|
|
1220
|
+
"torch",
|
|
1221
|
+
"kornia"
|
|
1222
|
+
],
|
|
1223
|
+
"fixed_in_release": "0.9.0",
|
|
1224
|
+
"repro": "import torch\nimport kornia\nimg = torch.tensor([[0.0] * 4, [100.0] * 4]).div(255.0)[None, None]\nout = (kornia.enhance.equalize_clahe(img, 40.0, (1, 1)) * 255).round()[0, 0]\nactual = [out[1, 0].item()]\nexpected = [159.0]\n",
|
|
1225
|
+
"check": {
|
|
1226
|
+
"type": "equal"
|
|
1227
|
+
},
|
|
1228
|
+
"before_fix": "[255.0] on kornia 0.8.3"
|
|
1189
1229
|
}
|
|
1190
1230
|
]
|
|
1191
1231
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|