Serron
Mathematical Morphology module for PyTorch (CUDA), providing differentiable operators and learnable network layers.
Install
Prebuilt wheels are published for CPython 3.12–3.14 on Linux (x86_64, aarch64) and Windows (x86_64).
pip install serron
The wheels are built against torch 2.14 and require it (torch>=2.14,<2.15): the torch C++
ABI changes between minor releases. They load on both CUDA and CPU-only torch builds; the
CUDA kernels are only loaded when the installed torch has CUDA.
Usage
Serron works on standard PyTorch tensors laid out as (N, C, H, W) and living on a CUDA
or CPU device.
Functional operators
Stateless operators live in serron.functional and are re-exported at the top level.
Each takes an input tensor, a structuring element, and an optional border mode:
import torch
import serron
from serron import BorderMode
from serron import structuring_element as se
x = torch.rand(1, 1, 256, 256, device="cuda")
kernel = se.disk(3, device="cuda")
eroded = serron.erosion(x, kernel)
dilated = serron.dilation(x, kernel)
opened = serron.opening(x, kernel)
closed = serron.closing(x, kernel)
# Derived operators
grad = serron.gradient(x, kernel) # dilate(x) - erode(x)
white = serron.top_hat(x, kernel) # x - open(x)
black = serron.black_hat(x, kernel) # close(x) - x
# Control border handling
eroded_reflect = serron.erosion(x, kernel, border=BorderMode.REFLECT)
Available operators: erosion, dilation, opening, closing, gradient,
top_hat, black_hat, reconstruction_by_dilation, reconstruction_by_erosion.
Geodesic reconstruction
reconstruction_by_dilation floods a marker outwards until it settles, held down by a
mask at every step; reconstruction_by_erosion is its dual. Both iterate the compiled
erode / dilate ops to a fixed point and default to BorderMode.CONSTANT, which is the
geodesic reading of the image boundary.
marker = torch.zeros_like(x)
marker[..., 128, 128] = x[..., 128, 128]
with torch.no_grad(): # no backward pass yet
flooded = serron.reconstruction_by_dilation(marker, x, se.cross(3, device="cuda"))
The loop runs on the device, but its convergence test reads one flag back to the host every
check_every steps (16 by default). Raise it to trade a few wasted steps for fewer syncs.
Structuring elements
serron.structuring_element builds common SE shapes on the requested device:
from serron import structuring_element as se
se.square(5, device="cuda") # (5, 5) full square
se.cross(5, device="cuda") # (5, 5) plus shape
se.disk(3, device="cuda") # (7, 7) disk, radius 3
se.diamond(3, device="cuda") # (7, 7) diamond, radius 3
se.from_tensor(my_weights) # wrap an arbitrary 2-D tensor as a grayscale SE
Border modes
BorderMode controls how out-of-bounds neighbors are handled:
| Mode | Behavior |
|---|---|
BorderMode.REPLICATE |
Repeat the edge value (default) |
BorderMode.REFLECT |
Mirror across the edge |
BorderMode.CONSTANT |
Pad with a constant |
Learnable layers
serron also exposes torch.nn.Module layers with a learnable structuring element,
so morphology can be trained end-to-end inside a network. Each layer takes the number
of channels and a kernel_size:
import torch
from serron import Erosion2d, Dilation2d, Opening2d, Closing2d
from serron import BorderMode
layer = Erosion2d(channels=3, kernel_size=5, border=BorderMode.REPLICATE).cuda()
x = torch.rand(8, 3, 64, 64, device="cuda")
y = layer(x) # forward pass; layer.weight is a trainable (C, k, k) SE
y.sum().backward() # gradients flow into layer.weight
Available layers: Erosion2d, Dilation2d, Opening2d, Closing2d.
Implementation
Every operator picks one of a few kernels at call time. The structuring element and the device's shared memory decide which one.
Which path runs
| Path | Runs when | Cost per output |
|---|---|---|
| Separable van Herk–Gil–Werman | Flat SE and max(kH, kW) >= SERRON_SEPARABLE_MIN_K |
O(1) in the window length |
| Tiled 2-D | Otherwise, when the halo tile and the SE fit in shared memory | O(kH × kW) |
| Element-wise | Otherwise; reads through global memory (CUDA only) | O(kH × kW) |
SERRON_SEPARABLE_MIN_K is the window length where the separable path takes over. It
accepts any positive integer. The default differs per backend because it marks where the
separable path starts beating the 2-D one, and that point is not the same on both: 11 on
CUDA, 5 on CPU, where there is no tiled 2-D kernel to soften the kH × kW window.
The separable path
Splitting a flat kH × kW window into a 1 × kW row pass and a kH × 1 column pass
already drops the per-pixel work from kH × kW to kH + kW, and the Van Herk–Gil–Werman algorithm
drops it further to a constant three operations per ouput, no matter the sequence length.
On CUDA both scans sit in shared memory. A chunk at least a warp wide gets a warp to
itself and the lanes cooperate through shuffles; anything shorter gets a single thread.
On CPU the lines go through at::parallel_for.
Backward
Backward needs to know where the winning sample was, not just what it was, so its scans
carry a (value, offset) pair rather than a bare value. Combining two of those keeps the
lower offset on a tie, which is the rule the direct kernel gets from its strict-improvement
loop — reproducing it exactly is what makes the two paths agree on which tap receives the
gradient. The window is one pair-combine as before, so the search is O(1) in the window
length on both the row and the column pass.
It splits on the same condition: a separable row and column argreduce for a flat SE at or above the threshold, and a direct recompute of the winning tap otherwise. The direct recompute stages its window in shared memory the same way the forward's tiled path does.
Benchmarks
Per-operator throughput and the cross-library comparison live in
benchmarks/README.md.
Erosion with a flat SE, 8x3x512x512 float32 on an H100 PCIe (with Intel Xeon Platinum 8480+), in milliseconds:
| k | serron | PyTorch | Kornia | CuPy | SciPy (CPU) |
|---|---|---|---|---|---|
| 7 | 0.30 | 0.42 | 2.80 | 0.20 | 159 |
| 31 | 0.23 | 5.46 | 41.87 | 0.58 | 151 |
| 63 | 0.31 | 21.48 | OOM | 1.05 | 144 |
| 127 | 0.25 | 81.03 | OOM | 2.00 | 142 |
Building from source
Clone repo
git clone git@github.com:vhrabar/serron.git
cd serron
Choosing a torch build
torch is pulled from a specific wheel index via mutually-exclusive extras. Pick the
one matching your machine, plain uv sync (no extra) falls back to the default
CUDA-enabled wheel from PyPI:
uv sync --extra cu132 # CUDA 13.2 build
uv sync --extra cpu # CPU-only build
Building the wheel
Building the CUDA extension from source needs the CUDA 13.X toolkit (nvcc):
uv sync --package serron --no-dev --group build --extra cu132
uv build --package serron --wheel --no-build-isolation
On a GPU-less machine, sync the CPU torch build instead; the extension then builds
C++ only (no nvcc required):
uv sync --package serron --no-dev --group build --extra cpu
uv build --package serron --wheel --no-build-isolation
License
MIT
Copyright © 2026 Vedran Hrabar.
Metadata
Release files for serron 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| serron-0.4.0.tar.gz | 38.6 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| serron-0.4.0-cp314-cp314-win_amd64.whl | CPython 3.14 | CPython 3.14 | Windows x86-64 | Details |
| serron-0.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| serron-0.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.28+ ARM64, Linux glibc 2.24+ ARM64 | Details |
| serron-0.4.0-cp313-cp313-win_amd64.whl | CPython 3.13 | CPython 3.13 | Windows x86-64 | Details |
| serron-0.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| serron-0.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.24+ ARM64, Linux glibc 2.28+ ARM64 | Details |
| serron-0.4.0-cp312-cp312-win_amd64.whl | CPython 3.12 | CPython 3.12 | Windows x86-64 | Details |
| serron-0.4.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| serron-0.4.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.24+ ARM64, Linux glibc 2.28+ ARM64 | Details |
Total release size: 310.7 MB
Release files / serron-0.4.0.tar.gz
| Download URL | serron-0.4.0.tar.gz |
|---|---|
| Size | 38.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3dcc6d97f3fc6ed9c1e20b1cf6bf7a7b280c93b90dc3a0e31f89d61d1134a9af
|
|
BLAKE2b-256 checksum How to use checksums |
2c42ebaf85df3e8e103503fc2333e5a842d3ca18cdd75fbace34dee1000757d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp314-cp314-win_amd64.whl
| Download URL | serron-0.4.0-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
54a78364ab6a78d8ca7f29329bfe3b7b517d59d7f5d0a00799ec4193c1d92537
|
|
BLAKE2b-256 checksum How to use checksums |
f32858094ac95c28861c3622ac724a5ef8da1d8fbc67c85d27ce0f3dd6653532
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | serron-0.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 50.6 MB |
| Tags | CPython 3.14 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
c254630417d1ef32eca38b8f360cf1eda91b6133eea38667f2502ca7e3f0dd29
|
|
BLAKE2b-256 checksum How to use checksums |
6d1f87aeaaced68f19d49b8622ac8fe29b3fd79ffa892ecb24c9dff3d4baf942
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
| Download URL | serron-0.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 48.3 MB |
| Tags | CPython 3.14 Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
95fa0d9205f397b0a0be060a1d6d6d36959e20cd5c2dd4770afa60d77ab43faa
|
|
BLAKE2b-256 checksum How to use checksums |
31241429423beb0b9f4519b47c627c3f9181157f06a59aa482e3ef7af48202a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp313-cp313-win_amd64.whl
| Download URL | serron-0.4.0-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
d47063128d87e46bbedfc552227952bd7214dfa23184cf2e334b24faf83a0509
|
|
BLAKE2b-256 checksum How to use checksums |
3674ca24fb6030ebe0ab85dc8844bc8cb5746fe15c73b43c8ae2281e196cf07f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | serron-0.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 50.6 MB |
| Tags | CPython 3.13 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
b5df5e8237a3db10af75aa5b74c1c54bf5db82f86b75d1a82d9e73c30f8bfa71
|
|
BLAKE2b-256 checksum How to use checksums |
273c989c15242fbe2b513b49d144d50fd30f2c9b4f115b05f468f6696b5b620d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
| Download URL | serron-0.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 48.3 MB |
| Tags | CPython 3.13 Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
267200ac6e9459ef3646c94d562697ac1faca0f779ef77a6d8ad6e702ecc3e81
|
|
BLAKE2b-256 checksum How to use checksums |
d47473e19b3e75494c24a5b9ca2e5526a029fe1858145e0441cb43bd9032115e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp312-cp312-win_amd64.whl
| Download URL | serron-0.4.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
b1bcb216df6e28b09a405f13103a7e18732f2ebbdd8e8c1bc9be216dc9fa194f
|
|
BLAKE2b-256 checksum How to use checksums |
895db117ccbca45104cef235a389dd4c9a7caf3418c77b91dfd2b19eeb32db9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | serron-0.4.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 50.6 MB |
| Tags | CPython 3.12 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
5b25a5a398b1605ade054481ae4739a9799510988d8242bd9579fc32aa693819
|
|
BLAKE2b-256 checksum How to use checksums |
0cc0d67410bd54a2201ead77e7d5e62378353a09ef46d445166a7a667869b685
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / serron-0.4.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
| Download URL | serron-0.4.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 48.3 MB |
| Tags | CPython 3.12 Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
341b8068ec05b30816a819c770fd8d0d7e9f47db1d7f8ba8d9381d123c7db109
|
|
BLAKE2b-256 checksum How to use checksums |
2d6fc74eb86c730d66c7f15e63e53fcc17ed019e07d1e618c54f15442fc07bb1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency log