keras-hexagdly 0.1.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.
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 ai4iacts (HexagDLy authors: Tim Lukas Holch, Constantin Steppa)
4
+ Copyright (c) 2026 Tanguy Dietrich, HEPIA, SST-1M Collaboration (keras-hexagdly port)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ # Tests are a dev-only artifact (need extra deps: torch, tensorflow, the
2
+ # upstream hexagdly package, conftest.py for sys.path setup). setuptools'
3
+ # default sdist heuristic sweeps up top-level test_*.py files but not their
4
+ # shared, non-test_-prefixed helper module (tests/_hex_reference.py), which
5
+ # would leave a source download with broken tests. Exclude the whole
6
+ # directory instead of half-including it -- clone the repo to run tests.
7
+ prune tests
@@ -0,0 +1,53 @@
1
+ # Notice
2
+
3
+ `keras-hexagdly` is a derivative work of
4
+ [HexagDLy](https://github.com/ai4iacts/hexagdly) by Tim Lukas Holch and
5
+ Constantin Steppa (ai4iacts), originally developed for hexagonal convolution
6
+ and pooling on PyTorch in the context of Imaging Atmospheric Cherenkov
7
+ Telescope analysis with H.E.S.S.
8
+
9
+ This package re-implements the same `HexBase` sub-kernel decomposition and
10
+ addressing arithmetic on top of [Keras 3](https://keras.io) (TensorFlow / JAX
11
+ / PyTorch backends), with a channels-last tensor layout. It is bit-for-bit
12
+ numerically equivalent to the original for every layer HexagDLy provides
13
+ (`Conv2d`, `Conv3d`, `Conv2d_CustomKernel`, `Conv3d_CustomKernel`,
14
+ `MaxPool2d`, `MaxPool3d`) -- see `tests/test_vs_pytorch_hexagdly.py`, which
15
+ checks this directly against the upstream PyTorch `hexagdly` PyPI package.
16
+
17
+ Two functionalities are new in this port and have no equivalent in upstream
18
+ HexagDLy:
19
+
20
+ - `share_neighbors`: ties the weights of a hexagonal kernel by ring (ring 0 =
21
+ center, ring *r* = the 6*r* cells at hex-distance *r*), instead of giving
22
+ every cell its own weight.
23
+ - `depth_padding` (`Conv3d` only): `"same"` zero-pads the depth/time axis so
24
+ the temporal kernel is centred and output depth equals input depth, instead
25
+ of HexagDLy's `"valid"`-only behaviour.
26
+
27
+ This work was developed as part of the SST-1M Collaboration / HEPIA TDSCAN
28
+ triggering project.
29
+
30
+ ## License
31
+
32
+ Both the original HexagDLy code and this port are distributed under the MIT
33
+ license; see [LICENSE](LICENSE). The original copyright notice (Copyright (c)
34
+ 2018 ai4iacts) is preserved alongside the copyright notice for this port, as
35
+ required by the MIT license.
36
+
37
+ ## Citing
38
+
39
+ If you use this package, please cite the original HexagDLy paper:
40
+
41
+ ```bibtex
42
+ @article{hexagdly_paper,
43
+ title = "HexagDLy—Processing hexagonally sampled data with CNNs in PyTorch",
44
+ author = "Constantin Steppa and Tim L. Holch",
45
+ journal = "SoftwareX",
46
+ volume = "9",
47
+ pages = "193 - 198",
48
+ year = "2019",
49
+ issn = "2352-7110",
50
+ doi = "https://doi.org/10.1016/j.softx.2019.02.010",
51
+ url = "https://www.sciencedirect.com/science/article/pii/S2352711018302723",
52
+ }
53
+ ```
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: keras-hexagdly
3
+ Version: 0.1.0
4
+ Summary: Keras 3 port of HexagDLy: hexagonal convolution and pooling for hexagonally sampled data
5
+ Author: Tanguy Dietrich
6
+ License: MIT License
7
+
8
+ Copyright (c) 2018 ai4iacts (HexagDLy authors: Tim Lukas Holch, Constantin Steppa)
9
+ Copyright (c) 2026 Tanguy Dietrich, HEPIA, SST-1M Collaboration (keras-hexagdly port)
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ Project-URL: Homepage, https://github.com/YugnatD/keras-hexagdly
30
+ Project-URL: Original, https://github.com/ai4iacts/hexagdly
31
+ Keywords: keras,tensorflow,hexagonal,convolution,cnn,astroparticle physics
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
37
+ Requires-Python: >=3.9
38
+ Description-Content-Type: text/markdown
39
+ License-File: LICENSE
40
+ License-File: NOTICE.md
41
+ Requires-Dist: keras>=3.0
42
+ Requires-Dist: numpy
43
+ Provides-Extra: dev
44
+ Requires-Dist: pytest; extra == "dev"
45
+ Requires-Dist: tensorflow; extra == "dev"
46
+ Requires-Dist: torch; extra == "dev"
47
+ Requires-Dist: hexagdly; extra == "dev"
48
+ Dynamic: license-file
49
+
50
+ # keras-hexagdly
51
+
52
+ Keras 3 port of [HexagDLy](https://github.com/ai4iacts/hexagdly): convolution
53
+ and pooling methods for hexagonally sampled data, originally written for
54
+ PyTorch by Tim Lukas Holch and Constantin Steppa (ai4iacts).
55
+
56
+ This port reproduces HexagDLy's hexagonal addressing scheme and sub-kernel
57
+ decomposition exactly (bit-for-bit equivalent outputs, see
58
+ [tests/test_vs_pytorch_hexagdly.py](tests/test_vs_pytorch_hexagdly.py)), but
59
+ is built on [Keras 3](https://keras.io) so it runs on any backend
60
+ (TensorFlow, JAX, PyTorch) and uses a channels-last (`NHWC`/`NDHWC`) tensor
61
+ layout instead of PyTorch's channels-first.
62
+
63
+ It also adds two functionalities that do not exist in upstream HexagDLy:
64
+
65
+ - **`share_neighbors`** (`Conv2d`, `Conv3d`): ties the weights of a hexagonal
66
+ kernel by ring (ring 0 = center cell, ring *r* = the `6*r` cells at hex
67
+ distance *r*), instead of every cell having its own independent weight.
68
+ Reduces parameter count and enforces exact 6-fold rotational symmetry of
69
+ the learned kernel.
70
+ - **`depth_padding="same"`** (`Conv3d` only): zero-pads the depth/time axis
71
+ so the temporal kernel is centred on each time step and the output depth
72
+ equals the input depth, instead of HexagDLy's `"valid"`-only behaviour
73
+ (output depth shrinks by `kernel - 1`).
74
+
75
+ See [NOTICE.md](NOTICE.md) for attribution details and citation information.
76
+
77
+ ## Installation
78
+
79
+ ```
80
+ pip install keras-hexagdly
81
+ ```
82
+
83
+ For development (running the test suite, which also checks parity against
84
+ upstream PyTorch HexagDLy, and the example notebooks):
85
+
86
+ ```
87
+ pip install keras-hexagdly[dev]
88
+ ```
89
+
90
+ ## Usage
91
+
92
+ ```python
93
+ import keras
94
+ import keras_hexagdly as hgly
95
+
96
+ kernel_size, stride = 1, 4
97
+ in_channels, out_channels = 1, 3
98
+
99
+ hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size, stride)
100
+ x = keras.random.uniform((1, 21, 21, 1)) # channels-last: (N, H, W, C)
101
+ y = hexconv(x)
102
+ ```
103
+
104
+ `in_channels` can be omitted; it is then inferred from the input on first
105
+ call, like a standard Keras layer: `hgly.Conv2d(out_channels, kernel_size=kernel_size, stride=stride)`.
106
+
107
+ ### New: weight sharing by hexagonal ring
108
+
109
+ ```python
110
+ hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size=3, share_neighbors=True)
111
+ ```
112
+
113
+ ### New: same-padded temporal convolution (Conv3d)
114
+
115
+ ```python
116
+ conv3d = hgly.Conv3d(in_channels, out_channels, kernel_size=(depth_k, hex_k),
117
+ depth_padding="same") # output depth == input depth
118
+ ```
119
+
120
+ Before applying these layers, your data must already be arranged on the
121
+ square-tensor layout HexagDLy expects (zig-zag columns); see
122
+ [notebooks/keras_hexagdly_addressing_scheme.ipynb](notebooks/keras_hexagdly_addressing_scheme.ipynb)
123
+ for how to get there from raw detector coordinates, and
124
+ [notebooks/keras_hexagdly_2d_example.ipynb](notebooks/keras_hexagdly_2d_example.ipynb)
125
+ for a worked convolution/pooling example, including the new features above.
126
+
127
+ ## Notebooks
128
+
129
+ Ported from [HexagDLy's own notebooks](https://github.com/ai4iacts/hexagdly/tree/master/notebooks), one-to-one where the content is framework-specific, lightly adapted where it depends on a torch-specific dataloader/training loop:
130
+
131
+ - [`keras_hexagdly_2d_example.ipynb`](notebooks/keras_hexagdly_2d_example.ipynb) -- basic `Conv2d`/`MaxPool2d` usage, hex-vs-square symmetry, and the new `share_neighbors`/`depth_padding` features.
132
+ - [`keras_hexagdly_addressing_scheme.ipynb`](notebooks/keras_hexagdly_addressing_scheme.ipynb) -- how to map raw hexagonal detector coordinates onto the square-tensor layout the layers expect (backend-independent; near-identical to upstream).
133
+ - [`keras_hexagdly_custom_kernels_example.ipynb`](notebooks/keras_hexagdly_custom_kernels_example.ipynb) -- building a custom Gaussian smoothing kernel with `Conv2d_CustomKernel`.
134
+ - [`keras_hexagdly_cnn_example.ipynb`](notebooks/keras_hexagdly_cnn_example.ipynb) -- a small CNN classifying toy hexagonal shapes, trained with `model.fit`.
135
+ - [`keras_hexagdly_hex_vs_square.ipynb`](notebooks/keras_hexagdly_hex_vs_square.ipynb) -- parameter-count and timing benchmark of hex vs. square kernels, plus a hex-CNN-vs-square-CNN classification comparison.
136
+
137
+ ## Testing
138
+
139
+ ```
140
+ pip install -e .[dev] --no-build-isolation # see note below
141
+ pytest tests/
142
+ ```
143
+
144
+ (`--no-build-isolation`: only needed if your `pip` is old -- pip 22.0.2's
145
+ isolated build environment was observed to pick up a `setuptools` version
146
+ that mis-names the built wheel `UNKNOWN`. Verified clean with a modern pip
147
+ (>=23) in a fresh venv: plain `pip install .` works with no workaround.
148
+ Either way, `pytest tests/` works without installing anything -- `conftest.py`
149
+ puts `src/` and `tests/` on `sys.path`.)
150
+
151
+ Verified to pass on all three Keras 3 backends (set `KERAS_BACKEND=tensorflow|torch|jax`
152
+ before importing keras; tensorflow is the default if unset):
153
+
154
+ ```
155
+ KERAS_BACKEND=tensorflow pytest tests/ # 272 passed, 7 skipped
156
+ KERAS_BACKEND=torch pytest tests/ # 269 passed, 10 skipped
157
+ KERAS_BACKEND=jax pytest tests/ # 269 passed, 10 skipped (slower: per-shape JIT compile)
158
+ ```
159
+
160
+ A GitHub Actions workflow ([.github/workflows/test.yml](.github/workflows/test.yml))
161
+ runs this matrix (3 backends x 3 Python versions) plus `ruff check`/`ruff format --check`
162
+ on every push and PR.
163
+
164
+ The test suite has six parts:
165
+
166
+ - `test_Conv2d.py`, `test_Conv3d.py`, `test_*_CustomKernel.py`,
167
+ `test_MaxPool2d.py`, `test_MaxPool3d.py`: standalone tests with
168
+ hand-computed expected outputs, ported from
169
+ [HexagDLy's own test suite](https://github.com/ai4iacts/hexagdly/tree/master/tests).
170
+ - `test_vs_pytorch_hexagdly.py`: cross-checks every layer against the
171
+ upstream PyTorch `hexagdly` PyPI package (random inputs, weights copied
172
+ across frameworks, gradients, batch independence, odd/even column parity,
173
+ large strides, asymmetric 3D kernels) -- the oracle that proves this port
174
+ faithful. Also includes two *forward-compatibility* tests that stay
175
+ skipped today (upstream hexagdly 2.0.2 has neither feature) but will
176
+ automatically start cross-checking `share_neighbors`/`depth_padding`
177
+ against upstream the day a future hexagdly release adds them.
178
+ - `test_mixed_precision.py`: `keras.mixed_precision` / per-layer `dtype=`
179
+ policies -- variables stay float32, compute happens in float16, on every
180
+ backend.
181
+ - `test_share_neighbors.py`, `test_depth_padding.py`: standalone tests for
182
+ the two new functionalities, which have no PyTorch equivalent to check
183
+ against.
184
+ - `test_edge_cases.py`, `test_serialization.py`, `test_geometry.py`: input
185
+ validation, minimum viable sizes, dtype handling, NaN/Inf checks, and
186
+ `get_config`/`from_config` + full `model.save`/`load_model` round-trips.
187
+
188
+ ## Disclaimer
189
+
190
+ Like upstream HexagDLy, this is a prototyping tool: it favors flexibility
191
+ over performance. Once a model's architecture (kernel size, stride, input
192
+ shape) is fixed, hard-coding those parameters would yield a faster
193
+ implementation.
194
+
195
+ ## Performance
196
+
197
+ See [benchmarks/](benchmarks/) for a speed comparison against upstream
198
+ PyTorch HexagDLy. Short version: run eagerly on CPU, this port is 1-7x
199
+ slower than upstream for the same reason upstream itself is slow (the hex
200
+ sub-kernel decomposition costs several op-dispatches per call -- a design
201
+ choice, not a regression). Wrapped in a compiled call (`jax.jit`/
202
+ `tf.function`, which `model.fit`/`model.predict` do automatically) it is
203
+ typically *faster* than upstream's eager PyTorch, sometimes by an order of
204
+ magnitude. `torch.compile` support is currently unreliable for this layer
205
+ (see the benchmarks README for why); eager execution on a GPU is the
206
+ recommended way to get speed on the torch backend.
207
+
208
+ ## Changelog
209
+
210
+ See [CHANGELOG.md](CHANGELOG.md).
211
+
212
+ ## License
213
+
214
+ MIT, see [LICENSE](LICENSE). This is a derivative work of HexagDLy
215
+ (Copyright (c) 2018 ai4iacts); see [NOTICE.md](NOTICE.md).
@@ -0,0 +1,166 @@
1
+ # keras-hexagdly
2
+
3
+ Keras 3 port of [HexagDLy](https://github.com/ai4iacts/hexagdly): convolution
4
+ and pooling methods for hexagonally sampled data, originally written for
5
+ PyTorch by Tim Lukas Holch and Constantin Steppa (ai4iacts).
6
+
7
+ This port reproduces HexagDLy's hexagonal addressing scheme and sub-kernel
8
+ decomposition exactly (bit-for-bit equivalent outputs, see
9
+ [tests/test_vs_pytorch_hexagdly.py](tests/test_vs_pytorch_hexagdly.py)), but
10
+ is built on [Keras 3](https://keras.io) so it runs on any backend
11
+ (TensorFlow, JAX, PyTorch) and uses a channels-last (`NHWC`/`NDHWC`) tensor
12
+ layout instead of PyTorch's channels-first.
13
+
14
+ It also adds two functionalities that do not exist in upstream HexagDLy:
15
+
16
+ - **`share_neighbors`** (`Conv2d`, `Conv3d`): ties the weights of a hexagonal
17
+ kernel by ring (ring 0 = center cell, ring *r* = the `6*r` cells at hex
18
+ distance *r*), instead of every cell having its own independent weight.
19
+ Reduces parameter count and enforces exact 6-fold rotational symmetry of
20
+ the learned kernel.
21
+ - **`depth_padding="same"`** (`Conv3d` only): zero-pads the depth/time axis
22
+ so the temporal kernel is centred on each time step and the output depth
23
+ equals the input depth, instead of HexagDLy's `"valid"`-only behaviour
24
+ (output depth shrinks by `kernel - 1`).
25
+
26
+ See [NOTICE.md](NOTICE.md) for attribution details and citation information.
27
+
28
+ ## Installation
29
+
30
+ ```
31
+ pip install keras-hexagdly
32
+ ```
33
+
34
+ For development (running the test suite, which also checks parity against
35
+ upstream PyTorch HexagDLy, and the example notebooks):
36
+
37
+ ```
38
+ pip install keras-hexagdly[dev]
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ```python
44
+ import keras
45
+ import keras_hexagdly as hgly
46
+
47
+ kernel_size, stride = 1, 4
48
+ in_channels, out_channels = 1, 3
49
+
50
+ hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size, stride)
51
+ x = keras.random.uniform((1, 21, 21, 1)) # channels-last: (N, H, W, C)
52
+ y = hexconv(x)
53
+ ```
54
+
55
+ `in_channels` can be omitted; it is then inferred from the input on first
56
+ call, like a standard Keras layer: `hgly.Conv2d(out_channels, kernel_size=kernel_size, stride=stride)`.
57
+
58
+ ### New: weight sharing by hexagonal ring
59
+
60
+ ```python
61
+ hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size=3, share_neighbors=True)
62
+ ```
63
+
64
+ ### New: same-padded temporal convolution (Conv3d)
65
+
66
+ ```python
67
+ conv3d = hgly.Conv3d(in_channels, out_channels, kernel_size=(depth_k, hex_k),
68
+ depth_padding="same") # output depth == input depth
69
+ ```
70
+
71
+ Before applying these layers, your data must already be arranged on the
72
+ square-tensor layout HexagDLy expects (zig-zag columns); see
73
+ [notebooks/keras_hexagdly_addressing_scheme.ipynb](notebooks/keras_hexagdly_addressing_scheme.ipynb)
74
+ for how to get there from raw detector coordinates, and
75
+ [notebooks/keras_hexagdly_2d_example.ipynb](notebooks/keras_hexagdly_2d_example.ipynb)
76
+ for a worked convolution/pooling example, including the new features above.
77
+
78
+ ## Notebooks
79
+
80
+ Ported from [HexagDLy's own notebooks](https://github.com/ai4iacts/hexagdly/tree/master/notebooks), one-to-one where the content is framework-specific, lightly adapted where it depends on a torch-specific dataloader/training loop:
81
+
82
+ - [`keras_hexagdly_2d_example.ipynb`](notebooks/keras_hexagdly_2d_example.ipynb) -- basic `Conv2d`/`MaxPool2d` usage, hex-vs-square symmetry, and the new `share_neighbors`/`depth_padding` features.
83
+ - [`keras_hexagdly_addressing_scheme.ipynb`](notebooks/keras_hexagdly_addressing_scheme.ipynb) -- how to map raw hexagonal detector coordinates onto the square-tensor layout the layers expect (backend-independent; near-identical to upstream).
84
+ - [`keras_hexagdly_custom_kernels_example.ipynb`](notebooks/keras_hexagdly_custom_kernels_example.ipynb) -- building a custom Gaussian smoothing kernel with `Conv2d_CustomKernel`.
85
+ - [`keras_hexagdly_cnn_example.ipynb`](notebooks/keras_hexagdly_cnn_example.ipynb) -- a small CNN classifying toy hexagonal shapes, trained with `model.fit`.
86
+ - [`keras_hexagdly_hex_vs_square.ipynb`](notebooks/keras_hexagdly_hex_vs_square.ipynb) -- parameter-count and timing benchmark of hex vs. square kernels, plus a hex-CNN-vs-square-CNN classification comparison.
87
+
88
+ ## Testing
89
+
90
+ ```
91
+ pip install -e .[dev] --no-build-isolation # see note below
92
+ pytest tests/
93
+ ```
94
+
95
+ (`--no-build-isolation`: only needed if your `pip` is old -- pip 22.0.2's
96
+ isolated build environment was observed to pick up a `setuptools` version
97
+ that mis-names the built wheel `UNKNOWN`. Verified clean with a modern pip
98
+ (>=23) in a fresh venv: plain `pip install .` works with no workaround.
99
+ Either way, `pytest tests/` works without installing anything -- `conftest.py`
100
+ puts `src/` and `tests/` on `sys.path`.)
101
+
102
+ Verified to pass on all three Keras 3 backends (set `KERAS_BACKEND=tensorflow|torch|jax`
103
+ before importing keras; tensorflow is the default if unset):
104
+
105
+ ```
106
+ KERAS_BACKEND=tensorflow pytest tests/ # 272 passed, 7 skipped
107
+ KERAS_BACKEND=torch pytest tests/ # 269 passed, 10 skipped
108
+ KERAS_BACKEND=jax pytest tests/ # 269 passed, 10 skipped (slower: per-shape JIT compile)
109
+ ```
110
+
111
+ A GitHub Actions workflow ([.github/workflows/test.yml](.github/workflows/test.yml))
112
+ runs this matrix (3 backends x 3 Python versions) plus `ruff check`/`ruff format --check`
113
+ on every push and PR.
114
+
115
+ The test suite has six parts:
116
+
117
+ - `test_Conv2d.py`, `test_Conv3d.py`, `test_*_CustomKernel.py`,
118
+ `test_MaxPool2d.py`, `test_MaxPool3d.py`: standalone tests with
119
+ hand-computed expected outputs, ported from
120
+ [HexagDLy's own test suite](https://github.com/ai4iacts/hexagdly/tree/master/tests).
121
+ - `test_vs_pytorch_hexagdly.py`: cross-checks every layer against the
122
+ upstream PyTorch `hexagdly` PyPI package (random inputs, weights copied
123
+ across frameworks, gradients, batch independence, odd/even column parity,
124
+ large strides, asymmetric 3D kernels) -- the oracle that proves this port
125
+ faithful. Also includes two *forward-compatibility* tests that stay
126
+ skipped today (upstream hexagdly 2.0.2 has neither feature) but will
127
+ automatically start cross-checking `share_neighbors`/`depth_padding`
128
+ against upstream the day a future hexagdly release adds them.
129
+ - `test_mixed_precision.py`: `keras.mixed_precision` / per-layer `dtype=`
130
+ policies -- variables stay float32, compute happens in float16, on every
131
+ backend.
132
+ - `test_share_neighbors.py`, `test_depth_padding.py`: standalone tests for
133
+ the two new functionalities, which have no PyTorch equivalent to check
134
+ against.
135
+ - `test_edge_cases.py`, `test_serialization.py`, `test_geometry.py`: input
136
+ validation, minimum viable sizes, dtype handling, NaN/Inf checks, and
137
+ `get_config`/`from_config` + full `model.save`/`load_model` round-trips.
138
+
139
+ ## Disclaimer
140
+
141
+ Like upstream HexagDLy, this is a prototyping tool: it favors flexibility
142
+ over performance. Once a model's architecture (kernel size, stride, input
143
+ shape) is fixed, hard-coding those parameters would yield a faster
144
+ implementation.
145
+
146
+ ## Performance
147
+
148
+ See [benchmarks/](benchmarks/) for a speed comparison against upstream
149
+ PyTorch HexagDLy. Short version: run eagerly on CPU, this port is 1-7x
150
+ slower than upstream for the same reason upstream itself is slow (the hex
151
+ sub-kernel decomposition costs several op-dispatches per call -- a design
152
+ choice, not a regression). Wrapped in a compiled call (`jax.jit`/
153
+ `tf.function`, which `model.fit`/`model.predict` do automatically) it is
154
+ typically *faster* than upstream's eager PyTorch, sometimes by an order of
155
+ magnitude. `torch.compile` support is currently unreliable for this layer
156
+ (see the benchmarks README for why); eager execution on a GPU is the
157
+ recommended way to get speed on the torch backend.
158
+
159
+ ## Changelog
160
+
161
+ See [CHANGELOG.md](CHANGELOG.md).
162
+
163
+ ## License
164
+
165
+ MIT, see [LICENSE](LICENSE). This is a derivative work of HexagDLy
166
+ (Copyright (c) 2018 ai4iacts); see [NOTICE.md](NOTICE.md).
@@ -0,0 +1,52 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "keras-hexagdly"
7
+ version = "0.1.0"
8
+ description = "Keras 3 port of HexagDLy: hexagonal convolution and pooling for hexagonally sampled data"
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ authors = [
12
+ { name = "Tanguy Dietrich" },
13
+ ]
14
+ requires-python = ">=3.9"
15
+ keywords = ["keras", "tensorflow", "hexagonal", "convolution", "cnn", "astroparticle physics"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Science/Research",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ ]
23
+ dependencies = [
24
+ "keras>=3.0",
25
+ "numpy",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest",
31
+ "tensorflow",
32
+ "torch",
33
+ "hexagdly",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/YugnatD/keras-hexagdly"
38
+ Original = "https://github.com/ai4iacts/hexagdly"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.ruff]
44
+ line-length = 100
45
+ target-version = "py39"
46
+
47
+ [tool.ruff.lint]
48
+ select = ["E", "F", "W", "I"]
49
+ ignore = [
50
+ "E741", # ambiguous variable name -- the layers mirror PyTorch HexagDLy's
51
+ # math-notation variable names (i, l, kh, kw) on purpose
52
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,21 @@
1
+ from .layers import (
2
+ Conv2d,
3
+ Conv2d_CustomKernel,
4
+ Conv3d,
5
+ Conv3d_CustomKernel,
6
+ MaxPool2d,
7
+ MaxPool3d,
8
+ ring_maps_2d,
9
+ )
10
+
11
+ __all__ = [
12
+ "Conv2d",
13
+ "Conv2d_CustomKernel",
14
+ "Conv3d",
15
+ "Conv3d_CustomKernel",
16
+ "MaxPool2d",
17
+ "MaxPool3d",
18
+ "ring_maps_2d",
19
+ ]
20
+
21
+ __version__ = "0.1.0"