torchnd 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.
torchnd-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: torchnd
3
+ Version: 0.1.0
4
+ Summary: ND Convolution for PyTorch
5
+ Author-email: Felix Zimmermann <fzimmermann89@gmail.com>
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/fzimmermann89/torch_conv_nd
8
+ Project-URL: Repository, https://github.com/fzimmermann89/torch_conv_nd
9
+ Project-URL: Issues, https://github.com/fzimmermann89/torch_conv_nd/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: torch>=2.0.0
23
+ Requires-Dist: einops>=0.6.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
27
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
28
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
29
+ Requires-Dist: pre-commit>=3.4.0; extra == "dev"
30
+ Requires-Dist: types-setuptools; extra == "dev"
31
+
32
+ # torchnd
33
+
34
+ N-dimensional convolution for PyTorch that works with any number of spatial dimensions, supporting groups, dilation, transposed convolution, complex numbers, and arbitrary dimension layouts.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install torchnd
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ **2D convolution:**
45
+ ```python
46
+ import torch
47
+ from torchnd import conv_nd
48
+
49
+ x = torch.randn(2, 4, 16, 16)
50
+ weight = torch.randn(8, 4, 3, 3)
51
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1, stride=2)
52
+ ```
53
+
54
+ **4D convolution** (batch × time × height × width):
55
+ ```python
56
+ x = torch.randn(2, 4, 10, 16, 16)
57
+ weight = torch.randn(8, 4, 3, 3, 3)
58
+ out = conv_nd(x, weight, dim=(-3, -2, -1), padding=1)
59
+ ```
60
+
61
+ **Channel-last layout:**
62
+ ```python
63
+ x = torch.randn(2, 16, 16, 4)
64
+ weight = torch.randn(8, 4, 3, 3)
65
+ out = conv_nd(x, weight, dim=(1, 2), channel_dim=-1, padding=1)
66
+ ```
67
+
68
+ **Transposed convolution:**
69
+ ```python
70
+ x = torch.randn(2, 4, 8, 8)
71
+ weight = torch.randn(4, 8, 3, 3)
72
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1, stride=2, transposed=True)
73
+ ```
74
+
75
+ **Complex numbers:**
76
+ ```python
77
+ x = torch.randn(2, 4, 16, 16, dtype=torch.complex64)
78
+ weight = torch.randn(8, 4, 3, 3, dtype=torch.complex64)
79
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1)
80
+ ```
81
+
82
+ **Asymmetric parameters per dimension:**
83
+ ```python
84
+ x = torch.randn(2, 4, 16, 16)
85
+ weight = torch.randn(8, 4, 3, 3)
86
+ out = conv_nd(
87
+ x, weight,
88
+ dim=(-2, -1),
89
+ stride=(2, 1),
90
+ padding=(1, 2),
91
+ dilation=(1, 2)
92
+ )
93
+ ```
94
+
95
+ **Modules:**
96
+ ```python
97
+ from torchnd import ConvNd, ConvTransposeNd
98
+
99
+ conv = ConvNd(4, 8, 3, dim=(-2, -1), padding=1)
100
+ out = conv(x)
101
+ ```
102
+
103
+ **Padding:**
104
+ ```python
105
+ from torchnd import pad_nd, adjoint_pad_nd
106
+
107
+ # Pad or crop arbitrary dimensions
108
+ padded = pad_nd(x, pad=(1, 1, 2, 2), dims=(-2, -1), mode="reflect")
109
+ cropped = pad_nd(x, pad=(-1, -1), dims=(0,)) # Negative values crop
110
+
111
+ # Adjoint of padding (unpads)
112
+ unpadded = adjoint_pad_nd(padded, pad=(1, 1, 2, 2), dims=(-2, -1))
113
+ ```
114
+
115
+ **Adjoint operators:**
116
+ ```python
117
+ from torchnd import ConvNd
118
+
119
+ conv = ConvNd(4, 8, 3, dim=(-2, -1), padding=1, bias=False)
120
+ x = torch.randn(2, 4, 16, 16)
121
+ y = torch.randn_like(conv(x))
122
+
123
+ # Adjoint satisfies: <conv(x), y> = <x, conv.adjoint(y)>
124
+ # For ConvNd: adjoint is transposed convolution with conjugated weights
125
+ adj_y = conv.adjoint(y, input_shape=(16, 16))
126
+ ```
127
+
128
+ ## Functions
129
+
130
+ ### pad_nd
131
+
132
+ N-dimensional padding and cropping with flexible dimension specification. Supports arbitrary dimension layouts, not limited to the last N dimensions. Negative padding values crop the tensor.
133
+
134
+ Modes: `constant`, `reflect`, `replicate`, `circular`. Each dimension can use a different mode. For constant mode, negative padding crops symmetrically. For non-constant modes, negative padding is not supported.
135
+
136
+ The `dims` parameter specifies which dimensions to pad. If `None`, pads the last N dimensions where N = len(pad) // 2. Padding is specified as pairs (left, right) per dimension.
137
+
138
+ ### adjoint_pad_nd
139
+
140
+ Computes the adjoint of `pad_nd` via autograd. For a padding operator P, the adjoint P* satisfies the inner product identity: `<Px, y> = <x, P*y>` for all x, y. The adjoint unpads the tensor, summing contributions from padded regions back into the original shape. For constant/zeros mode, the adjoint is equivalent to cropping. For other modes, it correctly handles the adjoint of the boundary extension.
141
+
142
+ ### Adjoint convolution
143
+
144
+ The `ConvNd` and `ConvTransposeNd` modules provide `adjoint()` methods. For `ConvNd`, the adjoint is the transposed convolution with conjugated weights (for complex) or identical weights (for real). For `ConvTransposeNd`, the adjoint is the forward convolution with conjugated weights.
145
+
146
+ The adjoint satisfies the inner product identity: `<Ax, y> = <x, A*y>` where A is the convolution operator and A* is its adjoint. This is verified via dot product tests. The adjoint is undefined when bias is present.
147
+
148
+ ## Implementation
149
+
150
+ For dimensions beyond 3D, `conv_nd` recursively decomposes the convolution into lower-dimensional operations. A 4D convolution becomes a sum of 3D convolutions applied to strided slices of the input.
151
+
152
+ Complex convolution is handled by decomposing into real operations: `(a+bi)*(c+di) = (ac-bd) + (ad+bc)i`.
153
+
154
+ The implementation uses native PyTorch operations when possible (1D, 2D, 3D) and falls back to recursion only for higher dimensions, minimizing memory overhead with strided views.
@@ -0,0 +1,123 @@
1
+ # torchnd
2
+
3
+ N-dimensional convolution for PyTorch that works with any number of spatial dimensions, supporting groups, dilation, transposed convolution, complex numbers, and arbitrary dimension layouts.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install torchnd
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ **2D convolution:**
14
+ ```python
15
+ import torch
16
+ from torchnd import conv_nd
17
+
18
+ x = torch.randn(2, 4, 16, 16)
19
+ weight = torch.randn(8, 4, 3, 3)
20
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1, stride=2)
21
+ ```
22
+
23
+ **4D convolution** (batch × time × height × width):
24
+ ```python
25
+ x = torch.randn(2, 4, 10, 16, 16)
26
+ weight = torch.randn(8, 4, 3, 3, 3)
27
+ out = conv_nd(x, weight, dim=(-3, -2, -1), padding=1)
28
+ ```
29
+
30
+ **Channel-last layout:**
31
+ ```python
32
+ x = torch.randn(2, 16, 16, 4)
33
+ weight = torch.randn(8, 4, 3, 3)
34
+ out = conv_nd(x, weight, dim=(1, 2), channel_dim=-1, padding=1)
35
+ ```
36
+
37
+ **Transposed convolution:**
38
+ ```python
39
+ x = torch.randn(2, 4, 8, 8)
40
+ weight = torch.randn(4, 8, 3, 3)
41
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1, stride=2, transposed=True)
42
+ ```
43
+
44
+ **Complex numbers:**
45
+ ```python
46
+ x = torch.randn(2, 4, 16, 16, dtype=torch.complex64)
47
+ weight = torch.randn(8, 4, 3, 3, dtype=torch.complex64)
48
+ out = conv_nd(x, weight, dim=(-2, -1), padding=1)
49
+ ```
50
+
51
+ **Asymmetric parameters per dimension:**
52
+ ```python
53
+ x = torch.randn(2, 4, 16, 16)
54
+ weight = torch.randn(8, 4, 3, 3)
55
+ out = conv_nd(
56
+ x, weight,
57
+ dim=(-2, -1),
58
+ stride=(2, 1),
59
+ padding=(1, 2),
60
+ dilation=(1, 2)
61
+ )
62
+ ```
63
+
64
+ **Modules:**
65
+ ```python
66
+ from torchnd import ConvNd, ConvTransposeNd
67
+
68
+ conv = ConvNd(4, 8, 3, dim=(-2, -1), padding=1)
69
+ out = conv(x)
70
+ ```
71
+
72
+ **Padding:**
73
+ ```python
74
+ from torchnd import pad_nd, adjoint_pad_nd
75
+
76
+ # Pad or crop arbitrary dimensions
77
+ padded = pad_nd(x, pad=(1, 1, 2, 2), dims=(-2, -1), mode="reflect")
78
+ cropped = pad_nd(x, pad=(-1, -1), dims=(0,)) # Negative values crop
79
+
80
+ # Adjoint of padding (unpads)
81
+ unpadded = adjoint_pad_nd(padded, pad=(1, 1, 2, 2), dims=(-2, -1))
82
+ ```
83
+
84
+ **Adjoint operators:**
85
+ ```python
86
+ from torchnd import ConvNd
87
+
88
+ conv = ConvNd(4, 8, 3, dim=(-2, -1), padding=1, bias=False)
89
+ x = torch.randn(2, 4, 16, 16)
90
+ y = torch.randn_like(conv(x))
91
+
92
+ # Adjoint satisfies: <conv(x), y> = <x, conv.adjoint(y)>
93
+ # For ConvNd: adjoint is transposed convolution with conjugated weights
94
+ adj_y = conv.adjoint(y, input_shape=(16, 16))
95
+ ```
96
+
97
+ ## Functions
98
+
99
+ ### pad_nd
100
+
101
+ N-dimensional padding and cropping with flexible dimension specification. Supports arbitrary dimension layouts, not limited to the last N dimensions. Negative padding values crop the tensor.
102
+
103
+ Modes: `constant`, `reflect`, `replicate`, `circular`. Each dimension can use a different mode. For constant mode, negative padding crops symmetrically. For non-constant modes, negative padding is not supported.
104
+
105
+ The `dims` parameter specifies which dimensions to pad. If `None`, pads the last N dimensions where N = len(pad) // 2. Padding is specified as pairs (left, right) per dimension.
106
+
107
+ ### adjoint_pad_nd
108
+
109
+ Computes the adjoint of `pad_nd` via autograd. For a padding operator P, the adjoint P* satisfies the inner product identity: `<Px, y> = <x, P*y>` for all x, y. The adjoint unpads the tensor, summing contributions from padded regions back into the original shape. For constant/zeros mode, the adjoint is equivalent to cropping. For other modes, it correctly handles the adjoint of the boundary extension.
110
+
111
+ ### Adjoint convolution
112
+
113
+ The `ConvNd` and `ConvTransposeNd` modules provide `adjoint()` methods. For `ConvNd`, the adjoint is the transposed convolution with conjugated weights (for complex) or identical weights (for real). For `ConvTransposeNd`, the adjoint is the forward convolution with conjugated weights.
114
+
115
+ The adjoint satisfies the inner product identity: `<Ax, y> = <x, A*y>` where A is the convolution operator and A* is its adjoint. This is verified via dot product tests. The adjoint is undefined when bias is present.
116
+
117
+ ## Implementation
118
+
119
+ For dimensions beyond 3D, `conv_nd` recursively decomposes the convolution into lower-dimensional operations. A 4D convolution becomes a sum of 3D convolutions applied to strided slices of the input.
120
+
121
+ Complex convolution is handled by decomposing into real operations: `(a+bi)*(c+di) = (ac-bd) + (ad+bc)i`.
122
+
123
+ The implementation uses native PyTorch operations when possible (1D, 2D, 3D) and falls back to recursion only for higher dimensions, minimizing memory overhead with strided views.
@@ -0,0 +1,146 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "torchnd"
7
+ version = "0.1.0"
8
+ description = "ND Convolution for PyTorch"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "GPL-3.0-or-later"}
12
+ authors = [
13
+ {name = "Felix Zimmermann", email = "fzimmermann89@gmail.com"}
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Intended Audience :: Science/Research",
19
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
26
+ ]
27
+ dependencies = [
28
+ "torch>=2.0.0",
29
+ "einops>=0.6.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=7.4.0",
35
+ "pytest-cov>=4.1.0",
36
+ "ruff>=0.1.0",
37
+ "mypy>=1.5.0",
38
+ "pre-commit>=3.4.0",
39
+ "types-setuptools",
40
+ ]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/fzimmermann89/torch_conv_nd"
44
+ Repository = "https://github.com/fzimmermann89/torch_conv_nd"
45
+ Issues = "https://github.com/fzimmermann89/torch_conv_nd/issues"
46
+
47
+ [tool.setuptools]
48
+ package-dir = {"" = "src"}
49
+ py-modules = []
50
+
51
+ [tool.setuptools.packages.find]
52
+ where = ["src"]
53
+
54
+ [tool.ruff]
55
+ target-version = "py39"
56
+ line-length = 130
57
+
58
+ [tool.ruff.lint]
59
+ select = [
60
+ "E", # pycodestyle errors
61
+ "W", # pycodestyle warnings
62
+ "F", # pyflakes
63
+ "I", # isort
64
+ "B", # flake8-bugbear
65
+ "C4", # flake8-comprehensions
66
+ "UP", # pyupgrade
67
+ "ARG", # flake8-unused-arguments
68
+ "SIM", # flake8-simplify
69
+ "TCH", # flake8-type-checking
70
+ "PTH", # flake8-use-pathlib
71
+ ]
72
+ ignore = [
73
+ "E501", # line too long (handled by formatter)
74
+ "B008", # do not perform function calls in argument defaults
75
+ "C901", # too complex
76
+ ]
77
+
78
+ [tool.ruff.lint.isort]
79
+ known-first-party = ["torchnd"]
80
+
81
+ [tool.ruff.format]
82
+ quote-style = "double"
83
+ indent-style = "space"
84
+ skip-magic-trailing-comma = false
85
+ line-ending = "auto"
86
+
87
+ [tool.ty.rules]
88
+ unresolved-attribute = "ignore"
89
+
90
+ [tool.mypy]
91
+ python_version = "3.10"
92
+ warn_return_any = true
93
+ warn_unused_configs = true
94
+ disallow_untyped_defs = true
95
+ disallow_incomplete_defs = true
96
+ check_untyped_defs = true
97
+ disallow_untyped_decorators = true
98
+ no_implicit_optional = true
99
+ warn_redundant_casts = true
100
+ warn_unused_ignores = true
101
+ warn_no_return = true
102
+ strict_equality = true
103
+ show_error_codes = true
104
+ pretty = true
105
+
106
+ [[tool.mypy.overrides]]
107
+ module = [
108
+ "torch.*",
109
+ ]
110
+ ignore_missing_imports = true
111
+
112
+ [tool.pytest.ini_options]
113
+ testpaths = ["tests"]
114
+ python_files = ["test_*.py", "*_test.py"]
115
+ python_classes = ["Test*"]
116
+ python_functions = ["test_*"]
117
+ addopts = [
118
+ "-ra",
119
+ "--strict-markers",
120
+ "--strict-config",
121
+ "--cov=torchnd",
122
+ "--cov-report=term-missing",
123
+ "--cov-report=html",
124
+ ]
125
+ markers = [
126
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
127
+ "integration: marks tests as integration tests",
128
+ ]
129
+
130
+ [tool.coverage.run]
131
+ source = ["src"]
132
+ omit = [
133
+ "*/tests/*",
134
+ "*/test_*.py",
135
+ ]
136
+
137
+ [tool.coverage.report]
138
+ exclude_lines = [
139
+ "pragma: no cover",
140
+ "def __repr__",
141
+ "raise AssertionError",
142
+ "raise NotImplementedError",
143
+ "if __name__ == .__main__.:",
144
+ "if TYPE_CHECKING:",
145
+ "@abstractmethod",
146
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ __version__ = "0.1.0"
2
+
3
+ from torchnd.functional import adjoint_pad_nd, conv_nd, pad_nd, pad_or_crop_to_size
4
+ from torchnd.modules import ConvNd, ConvTransposeNd
5
+
6
+ __all__ = [
7
+ "adjoint_pad_nd",
8
+ "conv_nd",
9
+ "pad_nd",
10
+ "pad_or_crop_to_size",
11
+ "ConvNd",
12
+ "ConvTransposeNd",
13
+ "__version__",
14
+ ]