Keras 3 port of HexagDLy: hexagonal convolution and pooling for hexagonally sampled data
Project description
keras-hexagdly
Keras 3 port of HexagDLy: convolution and pooling methods for hexagonally sampled data, originally written for PyTorch by Tim Lukas Holch and Constantin Steppa (ai4iacts).
This port reproduces HexagDLy's hexagonal addressing scheme and sub-kernel
decomposition exactly (bit-for-bit equivalent outputs, see
tests/test_vs_pytorch_hexagdly.py), but
is built on Keras 3 so it runs on any backend
(TensorFlow, JAX, PyTorch) and uses a channels-last (NHWC/NDHWC) tensor
layout instead of PyTorch's channels-first.
It also adds two functionalities that do not exist in upstream HexagDLy:
share_neighbors(Conv2d,Conv3d): ties the weights of a hexagonal kernel by ring (ring 0 = center cell, ring r = the6*rcells at hex distance r), instead of every cell having its own independent weight. Reduces parameter count and enforces exact 6-fold rotational symmetry of the learned kernel.depth_padding="same"(Conv3donly): zero-pads the depth/time axis so the temporal kernel is centred on each time step and the output depth equals the input depth, instead of HexagDLy's"valid"-only behaviour (output depth shrinks bykernel - 1).
See NOTICE.md for attribution details and citation information.
Installation
pip install keras-hexagdly
For development (running the test suite, which also checks parity against upstream PyTorch HexagDLy, and the example notebooks):
pip install keras-hexagdly[dev]
Usage
import keras
import keras_hexagdly as hgly
kernel_size, stride = 1, 4
in_channels, out_channels = 1, 3
hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size, stride)
x = keras.random.uniform((1, 21, 21, 1)) # channels-last: (N, H, W, C)
y = hexconv(x)
in_channels can be omitted; it is then inferred from the input on first
call, like a standard Keras layer: hgly.Conv2d(out_channels, kernel_size=kernel_size, stride=stride).
New: weight sharing by hexagonal ring
hexconv = hgly.Conv2d(in_channels, out_channels, kernel_size=3, share_neighbors=True)
New: same-padded temporal convolution (Conv3d)
conv3d = hgly.Conv3d(in_channels, out_channels, kernel_size=(depth_k, hex_k),
depth_padding="same") # output depth == input depth
Before applying these layers, your data must already be arranged on the square-tensor layout HexagDLy expects (zig-zag columns); see notebooks/keras_hexagdly_addressing_scheme.ipynb for how to get there from raw detector coordinates, and notebooks/keras_hexagdly_2d_example.ipynb for a worked convolution/pooling example, including the new features above.
Notebooks
Ported from HexagDLy's own notebooks, one-to-one where the content is framework-specific, lightly adapted where it depends on a torch-specific dataloader/training loop:
keras_hexagdly_2d_example.ipynb-- basicConv2d/MaxPool2dusage, hex-vs-square symmetry, and the newshare_neighbors/depth_paddingfeatures.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).keras_hexagdly_custom_kernels_example.ipynb-- building a custom Gaussian smoothing kernel withConv2d_CustomKernel.keras_hexagdly_cnn_example.ipynb-- a small CNN classifying toy hexagonal shapes, trained withmodel.fit.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.
Testing
pip install -e .[dev] --no-build-isolation # see note below
pytest tests/
(--no-build-isolation: only needed if your pip is old -- pip 22.0.2's
isolated build environment was observed to pick up a setuptools version
that mis-names the built wheel UNKNOWN. Verified clean with a modern pip
(>=23) in a fresh venv: plain pip install . works with no workaround.
Either way, pytest tests/ works without installing anything -- conftest.py
puts src/ and tests/ on sys.path.)
Verified to pass on all three Keras 3 backends (set KERAS_BACKEND=tensorflow|torch|jax
before importing keras; tensorflow is the default if unset):
KERAS_BACKEND=tensorflow pytest tests/ # 272 passed, 7 skipped
KERAS_BACKEND=torch pytest tests/ # 269 passed, 10 skipped
KERAS_BACKEND=jax pytest tests/ # 269 passed, 10 skipped (slower: per-shape JIT compile)
A GitHub Actions workflow (.github/workflows/test.yml)
runs this matrix (3 backends x 3 Python versions) plus ruff check/ruff format --check
on every push and PR.
The test suite has six parts:
test_Conv2d.py,test_Conv3d.py,test_*_CustomKernel.py,test_MaxPool2d.py,test_MaxPool3d.py: standalone tests with hand-computed expected outputs, ported from HexagDLy's own test suite.test_vs_pytorch_hexagdly.py: cross-checks every layer against the upstream PyTorchhexagdlyPyPI package (random inputs, weights copied across frameworks, gradients, batch independence, odd/even column parity, large strides, asymmetric 3D kernels) -- the oracle that proves this port faithful. Also includes two forward-compatibility tests that stay skipped today (upstream hexagdly 2.0.2 has neither feature) but will automatically start cross-checkingshare_neighbors/depth_paddingagainst upstream the day a future hexagdly release adds them.test_mixed_precision.py:keras.mixed_precision/ per-layerdtype=policies -- variables stay float32, compute happens in float16, on every backend.test_share_neighbors.py,test_depth_padding.py: standalone tests for the two new functionalities, which have no PyTorch equivalent to check against.test_edge_cases.py,test_serialization.py,test_geometry.py: input validation, minimum viable sizes, dtype handling, NaN/Inf checks, andget_config/from_config+ fullmodel.save/load_modelround-trips.
Disclaimer
Like upstream HexagDLy, this is a prototyping tool: it favors flexibility over performance. Once a model's architecture (kernel size, stride, input shape) is fixed, hard-coding those parameters would yield a faster implementation.
Performance
See benchmarks/ for a speed comparison against upstream
PyTorch HexagDLy. Short version: run eagerly on CPU, this port is 1-7x
slower than upstream for the same reason upstream itself is slow (the hex
sub-kernel decomposition costs several op-dispatches per call -- a design
choice, not a regression). Wrapped in a compiled call (jax.jit/
tf.function, which model.fit/model.predict do automatically) it is
typically faster than upstream's eager PyTorch, sometimes by an order of
magnitude. torch.compile support is currently unreliable for this layer
(see the benchmarks README for why); eager execution on a GPU is the
recommended way to get speed on the torch backend.
Changelog
See CHANGELOG.md.
License
MIT, see LICENSE. This is a derivative work of HexagDLy (Copyright (c) 2018 ai4iacts); see NOTICE.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keras_hexagdly-0.1.0.tar.gz.
File metadata
- Download URL: keras_hexagdly-0.1.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dfbe4ecd9967df7af52ca6a442949b44c3fa6418f9fa3b5dd1de2f636fee921
|
|
| MD5 |
3cbfa4b6b5661e44ca2469d25120303c
|
|
| BLAKE2b-256 |
a7ca18b21122faf2c958ba02f7c1ee76684553e8ae3cbca26c5f1e9c91de557f
|
Provenance
The following attestation bundles were made for keras_hexagdly-0.1.0.tar.gz:
Publisher:
publish.yml on YugnatD/keras-hexagdly
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keras_hexagdly-0.1.0.tar.gz -
Subject digest:
7dfbe4ecd9967df7af52ca6a442949b44c3fa6418f9fa3b5dd1de2f636fee921 - Sigstore transparency entry: 2011019322
- Sigstore integration time:
-
Permalink:
YugnatD/keras-hexagdly@97a94a556461cb72bdc6ce9c932e95f4cfe69801 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/YugnatD
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@97a94a556461cb72bdc6ce9c932e95f4cfe69801 -
Trigger Event:
push
-
Statement type:
File details
Details for the file keras_hexagdly-0.1.0-py3-none-any.whl.
File metadata
- Download URL: keras_hexagdly-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98ef682cf669672b73966fe50262e6de2cc8f2b9934fe32e1a3a7e7ae7a40f9d
|
|
| MD5 |
f76273e87d7aab623c69788ae91b0e0d
|
|
| BLAKE2b-256 |
4675a0771f9e596c233518945b367d8b09a93c844ac9e75d5910e54332bb2300
|
Provenance
The following attestation bundles were made for keras_hexagdly-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on YugnatD/keras-hexagdly
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keras_hexagdly-0.1.0-py3-none-any.whl -
Subject digest:
98ef682cf669672b73966fe50262e6de2cc8f2b9934fe32e1a3a7e7ae7a40f9d - Sigstore transparency entry: 2011019350
- Sigstore integration time:
-
Permalink:
YugnatD/keras-hexagdly@97a94a556461cb72bdc6ce9c932e95f4cfe69801 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/YugnatD
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@97a94a556461cb72bdc6ce9c932e95f4cfe69801 -
Trigger Event:
push
-
Statement type: