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.
- keras_hexagdly-0.1.0/LICENSE +22 -0
- keras_hexagdly-0.1.0/MANIFEST.in +7 -0
- keras_hexagdly-0.1.0/NOTICE.md +53 -0
- keras_hexagdly-0.1.0/PKG-INFO +215 -0
- keras_hexagdly-0.1.0/README.md +166 -0
- keras_hexagdly-0.1.0/pyproject.toml +52 -0
- keras_hexagdly-0.1.0/setup.cfg +4 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly/__init__.py +21 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly/layers.py +1281 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly.egg-info/PKG-INFO +215 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly.egg-info/SOURCES.txt +12 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly.egg-info/dependency_links.txt +1 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly.egg-info/requires.txt +8 -0
- keras_hexagdly-0.1.0/src/keras_hexagdly.egg-info/top_level.txt +1 -0
|
@@ -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,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"
|