sparsepixels 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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ho Fung Tsoi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: sparsepixels
3
+ Version: 0.1.0
4
+ Summary: Efficient convolution for sparse data on FPGAs
5
+ Home-page: https://github.com/hftsoi/sparse-pixels
6
+ Author: Ho Fung Tsoi
7
+ Author-email: ho.fung.tsoi@cern.ch
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: tensorflow<2.15.0,>=2.14.0
15
+ Requires-Dist: keras<2.15.0,>=2.14.0
16
+ Requires-Dist: qkeras<0.10.0,>=0.9.0
17
+ Dynamic: license-file
18
+
19
+ <p align="center">
20
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/logo.png" width="300" />
21
+ </p>
22
+
23
+ <p align="center">
24
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/sparsepixels.png" width="900"/>
25
+ </p>
26
+
27
+ <p align="center">
28
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_standard.gif" width="400" />
29
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_sparse.gif" width="400" />
30
+ </p>
31
+
32
+ # SparsePixels: Efficient convolution for sparse data on FPGAs
33
+
34
+ [![arXiv](https://img.shields.io/badge/arXiv-2512.06208-b31b1b.svg?style=flat-square)](https://arxiv.org/abs/2512.06208)
35
+
36
+ > **Note:** code packaging in preparation, stay tuned :)
37
+
38
+ ## Installation
39
+
40
+ ## Getting Started
41
+
42
+ ## Documentation
43
+
44
+ ## Citation
45
+ If you find this useful in your research, please consider citing:
46
+ ```
47
+ @article{Tsoi:2025nvg,
48
+ author = "Tsoi, Ho Fung and Rankin, Dylan and Loncar, Vladimir and Harris, Philip",
49
+ title = "{SparsePixels: Efficient Convolution for Sparse Data on FPGAs}",
50
+ eprint = "2512.06208",
51
+ archivePrefix = "arXiv",
52
+ primaryClass = "cs.AR",
53
+ month = "12",
54
+ year = "2025"
55
+ }
56
+ ```
@@ -0,0 +1,38 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/logo.png" width="300" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/sparsepixels.png" width="900"/>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_standard.gif" width="400" />
11
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_sparse.gif" width="400" />
12
+ </p>
13
+
14
+ # SparsePixels: Efficient convolution for sparse data on FPGAs
15
+
16
+ [![arXiv](https://img.shields.io/badge/arXiv-2512.06208-b31b1b.svg?style=flat-square)](https://arxiv.org/abs/2512.06208)
17
+
18
+ > **Note:** code packaging in preparation, stay tuned :)
19
+
20
+ ## Installation
21
+
22
+ ## Getting Started
23
+
24
+ ## Documentation
25
+
26
+ ## Citation
27
+ If you find this useful in your research, please consider citing:
28
+ ```
29
+ @article{Tsoi:2025nvg,
30
+ author = "Tsoi, Ho Fung and Rankin, Dylan and Loncar, Vladimir and Harris, Philip",
31
+ title = "{SparsePixels: Efficient Convolution for Sparse Data on FPGAs}",
32
+ eprint = "2512.06208",
33
+ archivePrefix = "arXiv",
34
+ primaryClass = "cs.AR",
35
+ month = "12",
36
+ year = "2025"
37
+ }
38
+ ```
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,31 @@
1
+ [metadata]
2
+ name = sparsepixels
3
+ version = 0.1.0
4
+ description = Efficient convolution for sparse data on FPGAs
5
+ author = Ho Fung Tsoi
6
+ author_email = ho.fung.tsoi@cern.ch
7
+ license = MIT
8
+ license_files = LICENSE
9
+ long_description = file: README.md
10
+ long_description_content_type = text/markdown
11
+ url = https://github.com/hftsoi/sparse-pixels
12
+ classifiers =
13
+ Programming Language :: Python :: 3
14
+ License :: OSI Approved :: MIT License
15
+
16
+ [options]
17
+ packages = find_namespace:
18
+ python_requires = >=3.10
19
+ install_requires =
20
+ tensorflow>=2.14.0,<2.15.0
21
+ keras>=2.14.0,<2.15.0
22
+ qkeras>=0.9.0,<0.10.0
23
+ include_package_data = True
24
+
25
+ [options.package_data]
26
+ sparsepixels = img/logo.png
27
+
28
+ [egg_info]
29
+ tag_build =
30
+ tag_date = 0
31
+
@@ -0,0 +1,4 @@
1
+ from setuptools import setup
2
+
3
+ if __name__ == "__main__":
4
+ setup()
File without changes
@@ -0,0 +1,153 @@
1
+ import tensorflow as tf
2
+ from qkeras import QConv2D, quantizers
3
+ from tensorflow.keras.layers import AveragePooling2D, MaxPooling2D
4
+
5
+ class InputReduce(tf.keras.layers.Layer):
6
+ def __init__(self, n_max_pixels, threshold, **kwargs):
7
+ super(InputReduce, self).__init__(**kwargs)
8
+ self.n_max_pixels = n_max_pixels
9
+ self.threshold = threshold
10
+
11
+ def call(self, inputs):
12
+ batch_size = tf.shape(inputs)[0]
13
+ h = tf.shape(inputs)[1]
14
+ w = tf.shape(inputs)[2]
15
+
16
+ '''
17
+ if self.threshold is not None:
18
+ cond = inputs > self.threshold
19
+ else:
20
+ cond = inputs != 0
21
+ active_flag = tf.cast(tf.reduce_any(cond, axis=-1), tf.int32)
22
+ '''
23
+
24
+ # to be consistent with hls, check only the first input channel
25
+ if self.threshold is not None:
26
+ active_flag = tf.cast(inputs[..., 0] > self.threshold, tf.int32)
27
+ else:
28
+ active_flag = tf.cast(inputs[..., 0] != 0, tf.int32)
29
+
30
+ active_flag_flat = tf.reshape(active_flag, [batch_size, h * w])
31
+ active_count = tf.cumsum(active_flag_flat, axis=1)
32
+
33
+ keep_mask_flat = tf.cast(tf.logical_and(active_flag_flat == 1, active_count <= self.n_max_pixels), inputs.dtype)
34
+ keep_mask = tf.reshape(keep_mask_flat, [batch_size, h, w, 1])
35
+
36
+ inputs_reduced = inputs * keep_mask
37
+ return inputs_reduced, keep_mask
38
+
39
+ def get_config(self):
40
+ config = super(InputReduce, self).get_config()
41
+ config.update({
42
+ "n_max_pixels": self.n_max_pixels,
43
+ "threshold": self.threshold
44
+ })
45
+ return config
46
+
47
+
48
+ class RemoveDilatedPixels(tf.keras.layers.Layer):
49
+ def __init__(self, **kwargs):
50
+ super(RemoveDilatedPixels, self).__init__(**kwargs)
51
+
52
+ def call(self, inputs):
53
+ x, mask = inputs
54
+ mask = tf.cast(mask, x.dtype)
55
+ removed = x * mask
56
+ return removed
57
+
58
+ def get_config(self):
59
+ config = super(RemoveDilatedPixels, self).get_config()
60
+ return config
61
+
62
+
63
+ class QConv2DSparse(tf.keras.layers.Layer):
64
+ def __init__(self, *conv_args, **conv_kwargs):
65
+ super().__init__(name=conv_kwargs.get("name", None))
66
+ self._bias_quant_cfg = conv_kwargs.pop("bias_quantizer", None)
67
+ self._bias_quantizer = (quantizers.get_quantizer(self._bias_quant_cfg) if self._bias_quant_cfg is not None else None)
68
+
69
+ conv_kwargs["use_bias"] = False
70
+ self.conv = QConv2D(*conv_args, **conv_kwargs)
71
+ self.bias = self.add_weight(
72
+ name = "bias",
73
+ shape = (self.conv.filters,),
74
+ initializer = "zeros",
75
+ trainable = True,
76
+ dtype = self.conv.dtype,
77
+ )
78
+ self.masker = RemoveDilatedPixels()
79
+
80
+ def call(self, inputs, **kwargs):
81
+ x, keep_mask = inputs
82
+ x = self.masker((x, keep_mask))
83
+ y = self.conv(x, **kwargs)
84
+
85
+ b = self.bias
86
+ if self._bias_quantizer is not None:
87
+ b = self._bias_quantizer(b)
88
+ b = tf.reshape(b, shape=(1, 1, 1, -1))
89
+
90
+ non_zero = tf.cast(tf.not_equal(y, 0), y.dtype)
91
+ y = y + b * non_zero
92
+
93
+ y = self.masker((y, keep_mask))
94
+ return y
95
+
96
+ def get_config(self):
97
+ cfg = super().get_config()
98
+ cfg["conv_config"] = self.conv.get_config()
99
+ cfg["bias_quantizer"] = self._bias_quant_cfg
100
+ return cfg
101
+
102
+ @classmethod
103
+ def from_config(cls, config):
104
+ conv_cfg = config.pop("conv_config")
105
+ bias_quant_cfg = config.pop("bias_quantizer", None)
106
+ layer = cls(**conv_cfg, bias_quantizer=bias_quant_cfg)
107
+ return layer
108
+
109
+
110
+ class AveragePooling2DSparse(tf.keras.layers.Layer):
111
+ def __init__(self, *pool_args, **pool_kwargs):
112
+ super().__init__(name=pool_kwargs.get("name", None))
113
+ self.avg_pool = AveragePooling2D(*pool_args, **pool_kwargs)
114
+ self.max_pool = MaxPooling2D(*pool_args, **pool_kwargs)
115
+
116
+ def call(self, inputs, **kwargs):
117
+ x, keep_mask = inputs
118
+ y = self.avg_pool(x, **kwargs)
119
+ keep_mask_pooled = self.max_pool(keep_mask)
120
+ return y, keep_mask_pooled
121
+
122
+ def get_config(self):
123
+ cfg = super().get_config()
124
+ cfg["pool_config"] = self.avg_pool.get_config()
125
+ return cfg
126
+
127
+ @classmethod
128
+ def from_config(cls, config):
129
+ pool_cfg = config.pop("pool_config")
130
+ return cls(**pool_cfg)
131
+
132
+
133
+ class MaxPooling2DSparse(tf.keras.layers.Layer):
134
+ def __init__(self, *pool_args, **pool_kwargs):
135
+ super().__init__(name=pool_kwargs.get("name", None))
136
+ self.max_pool = MaxPooling2D(*pool_args, **pool_kwargs)
137
+
138
+ def call(self, inputs, **kwargs):
139
+ x, keep_mask = inputs
140
+ y = self.max_pool(x, **kwargs)
141
+ keep_mask_pooled = self.max_pool(keep_mask)
142
+ return y, keep_mask_pooled
143
+
144
+ def get_config(self):
145
+ cfg = super().get_config()
146
+ cfg["pool_config"] = self.max_pool.get_config()
147
+ return cfg
148
+
149
+ @classmethod
150
+ def from_config(cls, config):
151
+ pool_cfg = config.pop("pool_config")
152
+ return cls(**pool_cfg)
153
+
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: sparsepixels
3
+ Version: 0.1.0
4
+ Summary: Efficient convolution for sparse data on FPGAs
5
+ Home-page: https://github.com/hftsoi/sparse-pixels
6
+ Author: Ho Fung Tsoi
7
+ Author-email: ho.fung.tsoi@cern.ch
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: tensorflow<2.15.0,>=2.14.0
15
+ Requires-Dist: keras<2.15.0,>=2.14.0
16
+ Requires-Dist: qkeras<0.10.0,>=0.9.0
17
+ Dynamic: license-file
18
+
19
+ <p align="center">
20
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/logo.png" width="300" />
21
+ </p>
22
+
23
+ <p align="center">
24
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/sparsepixels.png" width="900"/>
25
+ </p>
26
+
27
+ <p align="center">
28
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_standard.gif" width="400" />
29
+ <img src="https://raw.githubusercontent.com/hftsoi/sparse-pixels/main/docs/figs/cnn_sparse.gif" width="400" />
30
+ </p>
31
+
32
+ # SparsePixels: Efficient convolution for sparse data on FPGAs
33
+
34
+ [![arXiv](https://img.shields.io/badge/arXiv-2512.06208-b31b1b.svg?style=flat-square)](https://arxiv.org/abs/2512.06208)
35
+
36
+ > **Note:** code packaging in preparation, stay tuned :)
37
+
38
+ ## Installation
39
+
40
+ ## Getting Started
41
+
42
+ ## Documentation
43
+
44
+ ## Citation
45
+ If you find this useful in your research, please consider citing:
46
+ ```
47
+ @article{Tsoi:2025nvg,
48
+ author = "Tsoi, Ho Fung and Rankin, Dylan and Loncar, Vladimir and Harris, Philip",
49
+ title = "{SparsePixels: Efficient Convolution for Sparse Data on FPGAs}",
50
+ eprint = "2512.06208",
51
+ archivePrefix = "arXiv",
52
+ primaryClass = "cs.AR",
53
+ month = "12",
54
+ year = "2025"
55
+ }
56
+ ```
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ setup.py
6
+ sparsepixels/__init__.py
7
+ sparsepixels/layers.py
8
+ sparsepixels.egg-info/PKG-INFO
9
+ sparsepixels.egg-info/SOURCES.txt
10
+ sparsepixels.egg-info/dependency_links.txt
11
+ sparsepixels.egg-info/requires.txt
12
+ sparsepixels.egg-info/top_level.txt
13
+ sparsepixels/img/logo.png
@@ -0,0 +1,3 @@
1
+ tensorflow<2.15.0,>=2.14.0
2
+ keras<2.15.0,>=2.14.0
3
+ qkeras<0.10.0,>=0.9.0
@@ -0,0 +1,8 @@
1
+ datasets
2
+ dist
3
+ docs
4
+ hls_proj
5
+ hls_templates
6
+ plots
7
+ sparsepixels
8
+ weights