dethdc 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.
- dethdc-0.1.0/LICENSE +21 -0
- dethdc-0.1.0/PKG-INFO +346 -0
- dethdc-0.1.0/README.md +326 -0
- dethdc-0.1.0/pyproject.toml +34 -0
- dethdc-0.1.0/setup.cfg +4 -0
- dethdc-0.1.0/src/dethdc/__init__.py +5 -0
- dethdc-0.1.0/src/dethdc/classifier.py +171 -0
- dethdc-0.1.0/src/dethdc/encoder.py +85 -0
- dethdc-0.1.0/src/dethdc.egg-info/PKG-INFO +346 -0
- dethdc-0.1.0/src/dethdc.egg-info/SOURCES.txt +13 -0
- dethdc-0.1.0/src/dethdc.egg-info/dependency_links.txt +1 -0
- dethdc-0.1.0/src/dethdc.egg-info/requires.txt +10 -0
- dethdc-0.1.0/src/dethdc.egg-info/top_level.txt +1 -0
- dethdc-0.1.0/tests/test_classifier.py +27 -0
- dethdc-0.1.0/tests/test_encoder.py +20 -0
dethdc-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abu Kaisar Mohammad Masum
|
|
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.
|
dethdc-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dethdc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic Hyperdimensional Learning with Sobol projections and rank refinement
|
|
5
|
+
Author: Abu Kaisar Mohammad Masum
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Paper, https://ojs.aaai.org/index.php/AAAI/article/view/42253
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: numpy>=1.24
|
|
12
|
+
Requires-Dist: torch>=2.0
|
|
13
|
+
Provides-Extra: examples
|
|
14
|
+
Requires-Dist: torchvision>=0.15; extra == "examples"
|
|
15
|
+
Requires-Dist: scikit-learn>=1.2; extra == "examples"
|
|
16
|
+
Requires-Dist: tqdm>=4.65; extra == "examples"
|
|
17
|
+
Provides-Extra: test
|
|
18
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
<div align="center">
|
|
22
|
+
|
|
23
|
+
# DetHDC
|
|
24
|
+
|
|
25
|
+
### Deterministic Hyperdimensional Learning with Rank Refinement
|
|
26
|
+
|
|
27
|
+
[](https://ojs.aaai.org/index.php/AAAI/article/view/42253)
|
|
28
|
+
[](https://www.python.org/)
|
|
29
|
+
[](https://pytorch.org/)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
|
|
32
|
+
**Official research implementation of the AAAI 2026 paper
|
|
33
|
+
“Deterministic Hyperdimensional Learning with Rank Refinement.”**
|
|
34
|
+
|
|
35
|
+
[Paper](https://ojs.aaai.org/index.php/AAAI/article/view/42253) · [Quick Start](#-quick-start) · [Citation](#-citation)
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ✨ Overview
|
|
42
|
+
|
|
43
|
+
**DetHDC** is a lightweight PyTorch library for deterministic hyperdimensional learning using:
|
|
44
|
+
|
|
45
|
+
- **Sobol quasi-random projections**
|
|
46
|
+
- **position–value binding**
|
|
47
|
+
- **prototype-based HDC classification**
|
|
48
|
+
- **rank-based refinement**
|
|
49
|
+
- **CPU and CUDA execution**
|
|
50
|
+
- **reproducible training through explicit random seeds**
|
|
51
|
+
|
|
52
|
+
The repository turns the method from our AAAI 2026 paper into a reusable Python API instead of a dataset-specific research script.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🧠 Method at a Glance
|
|
57
|
+
|
|
58
|
+
Given an input vector \(x \in \mathbb{R}^{L}\), DetHDC builds two deterministic projection spaces:
|
|
59
|
+
|
|
60
|
+
\[
|
|
61
|
+
P, V \in \mathbb{R}^{D \times L},
|
|
62
|
+
\]
|
|
63
|
+
|
|
64
|
+
where \(P\) and \(V\) are generated from scrambled Sobol sequences.
|
|
65
|
+
|
|
66
|
+
The projected representations are
|
|
67
|
+
|
|
68
|
+
\[
|
|
69
|
+
h_p = \frac{xP^\top}{\sqrt{L}},
|
|
70
|
+
\qquad
|
|
71
|
+
h_v = \frac{xV^\top}{\sqrt{L}},
|
|
72
|
+
\]
|
|
73
|
+
|
|
74
|
+
and the final hypervector is obtained through element-wise binding:
|
|
75
|
+
|
|
76
|
+
\[
|
|
77
|
+
h = \mathrm{norm}(h_p \odot h_v).
|
|
78
|
+
\]
|
|
79
|
+
|
|
80
|
+
Class prototypes are first constructed by bundling encoded samples. A rank-based refinement stage then updates prototypes when the true class is not sufficiently separated from the strongest competing class.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🚀 Quick Start
|
|
85
|
+
|
|
86
|
+
### Install from source
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/Abu-Kaisar-Mohammad-Masum/DetHDC.git
|
|
90
|
+
cd DetHDC
|
|
91
|
+
pip install -e .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Minimal example
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from dethdc import DetHDC
|
|
98
|
+
|
|
99
|
+
model = DetHDC(
|
|
100
|
+
dimensions=10000,
|
|
101
|
+
epochs=5,
|
|
102
|
+
lr=0.01,
|
|
103
|
+
margin=0.2,
|
|
104
|
+
seed=42,
|
|
105
|
+
device="auto",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
model.fit(X_train, y_train)
|
|
109
|
+
|
|
110
|
+
predictions = model.predict(X_test)
|
|
111
|
+
accuracy = model.score(X_test, y_test)
|
|
112
|
+
|
|
113
|
+
print(f"Accuracy: {accuracy * 100:.2f}%")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 🔥 Why DetHDC?
|
|
119
|
+
|
|
120
|
+
Traditional HDC implementations often rely on randomly generated hypervectors. That can introduce run-to-run variation and make reproducibility harder.
|
|
121
|
+
|
|
122
|
+
DetHDC instead uses **Sobol-based deterministic projections**, giving a controlled projection space while retaining the efficiency and robustness properties of hyperdimensional learning.
|
|
123
|
+
|
|
124
|
+
The library also exposes the refinement stage directly:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
model = DetHDC(
|
|
128
|
+
dimensions=10000,
|
|
129
|
+
refinement=True,
|
|
130
|
+
epochs=5,
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For a base model without rank refinement:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
model = DetHDC(
|
|
138
|
+
dimensions=10000,
|
|
139
|
+
refinement=False,
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 📦 Library API
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from dethdc import DetHDC, SobolEncoder
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### `DetHDC`
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
DetHDC(
|
|
155
|
+
dimensions=10000,
|
|
156
|
+
epochs=5,
|
|
157
|
+
lr=0.01,
|
|
158
|
+
margin=0.2,
|
|
159
|
+
refinement=True,
|
|
160
|
+
scramble=True,
|
|
161
|
+
seed=42,
|
|
162
|
+
device="auto",
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Main methods:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
model.fit(X, y)
|
|
170
|
+
model.encode(X)
|
|
171
|
+
model.predict(X)
|
|
172
|
+
model.predict_similarity(X)
|
|
173
|
+
model.score(X, y)
|
|
174
|
+
model.get_config()
|
|
175
|
+
model.save("model.pt")
|
|
176
|
+
DetHDC.load("model.pt")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 🧪 MNIST Example
|
|
182
|
+
|
|
183
|
+
Run:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python examples/mnist.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The example:
|
|
190
|
+
|
|
191
|
+
1. downloads MNIST,
|
|
192
|
+
2. flattens native \(28 \times 28\) images,
|
|
193
|
+
3. constructs Sobol projection matrices,
|
|
194
|
+
4. encodes the training/test sets,
|
|
195
|
+
5. builds class prototypes,
|
|
196
|
+
6. performs rank-based refinement,
|
|
197
|
+
7. reports classification accuracy.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🗂 Repository Structure
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
DetHDC/
|
|
205
|
+
├── README.md
|
|
206
|
+
├── LICENSE
|
|
207
|
+
├── CITATION.cff
|
|
208
|
+
├── pyproject.toml
|
|
209
|
+
├── src/
|
|
210
|
+
│ └── dethdc/
|
|
211
|
+
│ ├── __init__.py
|
|
212
|
+
│ ├── classifier.py
|
|
213
|
+
│ └── encoder.py
|
|
214
|
+
├── examples/
|
|
215
|
+
│ └── mnist.py
|
|
216
|
+
├── benchmarks/
|
|
217
|
+
│ └── reproduce_aaai2026.py
|
|
218
|
+
└── tests/
|
|
219
|
+
├── test_encoder.py
|
|
220
|
+
└── test_classifier.py
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## ⚡ GPU Support
|
|
226
|
+
|
|
227
|
+
DetHDC automatically uses CUDA when available:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
model = DetHDC(device="auto")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
You can also force a backend:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
model = DetHDC(device="cpu")
|
|
237
|
+
model = DetHDC(device="cuda")
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Classification stays in PyTorch and avoids unnecessary GPU → CPU → NumPy transfers.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 🔬 Reproducibility
|
|
245
|
+
|
|
246
|
+
DetHDC exposes the seed explicitly:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
model = DetHDC(seed=42)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
You can inspect the complete configuration:
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
print(model.get_config())
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Example:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
{
|
|
262
|
+
"dimensions": 10000,
|
|
263
|
+
"epochs": 5,
|
|
264
|
+
"lr": 0.01,
|
|
265
|
+
"margin": 0.2,
|
|
266
|
+
"refinement": True,
|
|
267
|
+
"scramble": True,
|
|
268
|
+
"seed": 42,
|
|
269
|
+
"device": "cuda"
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 🧪 Testing
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
pip install -e ".[test]"
|
|
279
|
+
pytest
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The test suite checks:
|
|
283
|
+
|
|
284
|
+
- output dimensions,
|
|
285
|
+
- deterministic Sobol generation,
|
|
286
|
+
- fitting and prediction,
|
|
287
|
+
- model save/load,
|
|
288
|
+
- CPU execution,
|
|
289
|
+
- CUDA execution when available.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 🧪 Library Sanity Check
|
|
294
|
+
|
|
295
|
+
Using the reproducible MNIST example included in this repository:
|
|
296
|
+
|
|
297
|
+
| Configuration | Result |
|
|
298
|
+
|---|---:|
|
|
299
|
+
| Dimension | 10,000 |
|
|
300
|
+
| Refinement iterations | 5 |
|
|
301
|
+
| Seed | 42 |
|
|
302
|
+
| Test split | 30% stratified |
|
|
303
|
+
| Accuracy | **95.46%** |
|
|
304
|
+
|
|
305
|
+
The packaged example uses a fixed deterministic split and seed and is
|
|
306
|
+
intended as a reproducible usage example rather than an exact recreation
|
|
307
|
+
of the paper's experimental split.
|
|
308
|
+
|
|
309
|
+
## 📄 Paper
|
|
310
|
+
|
|
311
|
+
**Deterministic Hyperdimensional Learning with Rank Refinement**
|
|
312
|
+
Abu Kaisar Mohammad Masum and Sercan Aygun
|
|
313
|
+
*Proceedings of the AAAI Conference on Artificial Intelligence*, 2026.
|
|
314
|
+
|
|
315
|
+
Paper:
|
|
316
|
+
|
|
317
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/42253
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 📚 Citation
|
|
322
|
+
|
|
323
|
+
If this repository helps your research, please cite our AAAI paper:
|
|
324
|
+
|
|
325
|
+
```bibtex
|
|
326
|
+
@inproceedings{masum2026deterministic,
|
|
327
|
+
title={Deterministic hyperdimensional learning with rank refinement (student abstract)},
|
|
328
|
+
author={Masum, Abu Kaisar Mohammad and Aygun, Sercan},
|
|
329
|
+
booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
|
|
330
|
+
volume={40},
|
|
331
|
+
number={48},
|
|
332
|
+
pages={41313--41315},
|
|
333
|
+
year={2026}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
## 📜 License
|
|
339
|
+
|
|
340
|
+
Released under the [MIT License](LICENSE).
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
**Deterministic projections. Lightweight learning. Reproducible HDC.**
|
|
345
|
+
|
|
346
|
+
</div>
|
dethdc-0.1.0/README.md
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# DetHDC
|
|
4
|
+
|
|
5
|
+
### Deterministic Hyperdimensional Learning with Rank Refinement
|
|
6
|
+
|
|
7
|
+
[](https://ojs.aaai.org/index.php/AAAI/article/view/42253)
|
|
8
|
+
[](https://www.python.org/)
|
|
9
|
+
[](https://pytorch.org/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
**Official research implementation of the AAAI 2026 paper
|
|
13
|
+
“Deterministic Hyperdimensional Learning with Rank Refinement.”**
|
|
14
|
+
|
|
15
|
+
[Paper](https://ojs.aaai.org/index.php/AAAI/article/view/42253) · [Quick Start](#-quick-start) · [Citation](#-citation)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ✨ Overview
|
|
22
|
+
|
|
23
|
+
**DetHDC** is a lightweight PyTorch library for deterministic hyperdimensional learning using:
|
|
24
|
+
|
|
25
|
+
- **Sobol quasi-random projections**
|
|
26
|
+
- **position–value binding**
|
|
27
|
+
- **prototype-based HDC classification**
|
|
28
|
+
- **rank-based refinement**
|
|
29
|
+
- **CPU and CUDA execution**
|
|
30
|
+
- **reproducible training through explicit random seeds**
|
|
31
|
+
|
|
32
|
+
The repository turns the method from our AAAI 2026 paper into a reusable Python API instead of a dataset-specific research script.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🧠 Method at a Glance
|
|
37
|
+
|
|
38
|
+
Given an input vector \(x \in \mathbb{R}^{L}\), DetHDC builds two deterministic projection spaces:
|
|
39
|
+
|
|
40
|
+
\[
|
|
41
|
+
P, V \in \mathbb{R}^{D \times L},
|
|
42
|
+
\]
|
|
43
|
+
|
|
44
|
+
where \(P\) and \(V\) are generated from scrambled Sobol sequences.
|
|
45
|
+
|
|
46
|
+
The projected representations are
|
|
47
|
+
|
|
48
|
+
\[
|
|
49
|
+
h_p = \frac{xP^\top}{\sqrt{L}},
|
|
50
|
+
\qquad
|
|
51
|
+
h_v = \frac{xV^\top}{\sqrt{L}},
|
|
52
|
+
\]
|
|
53
|
+
|
|
54
|
+
and the final hypervector is obtained through element-wise binding:
|
|
55
|
+
|
|
56
|
+
\[
|
|
57
|
+
h = \mathrm{norm}(h_p \odot h_v).
|
|
58
|
+
\]
|
|
59
|
+
|
|
60
|
+
Class prototypes are first constructed by bundling encoded samples. A rank-based refinement stage then updates prototypes when the true class is not sufficiently separated from the strongest competing class.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🚀 Quick Start
|
|
65
|
+
|
|
66
|
+
### Install from source
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/Abu-Kaisar-Mohammad-Masum/DetHDC.git
|
|
70
|
+
cd DetHDC
|
|
71
|
+
pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Minimal example
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from dethdc import DetHDC
|
|
78
|
+
|
|
79
|
+
model = DetHDC(
|
|
80
|
+
dimensions=10000,
|
|
81
|
+
epochs=5,
|
|
82
|
+
lr=0.01,
|
|
83
|
+
margin=0.2,
|
|
84
|
+
seed=42,
|
|
85
|
+
device="auto",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
model.fit(X_train, y_train)
|
|
89
|
+
|
|
90
|
+
predictions = model.predict(X_test)
|
|
91
|
+
accuracy = model.score(X_test, y_test)
|
|
92
|
+
|
|
93
|
+
print(f"Accuracy: {accuracy * 100:.2f}%")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 🔥 Why DetHDC?
|
|
99
|
+
|
|
100
|
+
Traditional HDC implementations often rely on randomly generated hypervectors. That can introduce run-to-run variation and make reproducibility harder.
|
|
101
|
+
|
|
102
|
+
DetHDC instead uses **Sobol-based deterministic projections**, giving a controlled projection space while retaining the efficiency and robustness properties of hyperdimensional learning.
|
|
103
|
+
|
|
104
|
+
The library also exposes the refinement stage directly:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
model = DetHDC(
|
|
108
|
+
dimensions=10000,
|
|
109
|
+
refinement=True,
|
|
110
|
+
epochs=5,
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For a base model without rank refinement:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
model = DetHDC(
|
|
118
|
+
dimensions=10000,
|
|
119
|
+
refinement=False,
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 📦 Library API
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from dethdc import DetHDC, SobolEncoder
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `DetHDC`
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
DetHDC(
|
|
135
|
+
dimensions=10000,
|
|
136
|
+
epochs=5,
|
|
137
|
+
lr=0.01,
|
|
138
|
+
margin=0.2,
|
|
139
|
+
refinement=True,
|
|
140
|
+
scramble=True,
|
|
141
|
+
seed=42,
|
|
142
|
+
device="auto",
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Main methods:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
model.fit(X, y)
|
|
150
|
+
model.encode(X)
|
|
151
|
+
model.predict(X)
|
|
152
|
+
model.predict_similarity(X)
|
|
153
|
+
model.score(X, y)
|
|
154
|
+
model.get_config()
|
|
155
|
+
model.save("model.pt")
|
|
156
|
+
DetHDC.load("model.pt")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🧪 MNIST Example
|
|
162
|
+
|
|
163
|
+
Run:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python examples/mnist.py
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The example:
|
|
170
|
+
|
|
171
|
+
1. downloads MNIST,
|
|
172
|
+
2. flattens native \(28 \times 28\) images,
|
|
173
|
+
3. constructs Sobol projection matrices,
|
|
174
|
+
4. encodes the training/test sets,
|
|
175
|
+
5. builds class prototypes,
|
|
176
|
+
6. performs rank-based refinement,
|
|
177
|
+
7. reports classification accuracy.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 🗂 Repository Structure
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
DetHDC/
|
|
185
|
+
├── README.md
|
|
186
|
+
├── LICENSE
|
|
187
|
+
├── CITATION.cff
|
|
188
|
+
├── pyproject.toml
|
|
189
|
+
├── src/
|
|
190
|
+
│ └── dethdc/
|
|
191
|
+
│ ├── __init__.py
|
|
192
|
+
│ ├── classifier.py
|
|
193
|
+
│ └── encoder.py
|
|
194
|
+
├── examples/
|
|
195
|
+
│ └── mnist.py
|
|
196
|
+
├── benchmarks/
|
|
197
|
+
│ └── reproduce_aaai2026.py
|
|
198
|
+
└── tests/
|
|
199
|
+
├── test_encoder.py
|
|
200
|
+
└── test_classifier.py
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## ⚡ GPU Support
|
|
206
|
+
|
|
207
|
+
DetHDC automatically uses CUDA when available:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
model = DetHDC(device="auto")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
You can also force a backend:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
model = DetHDC(device="cpu")
|
|
217
|
+
model = DetHDC(device="cuda")
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Classification stays in PyTorch and avoids unnecessary GPU → CPU → NumPy transfers.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 🔬 Reproducibility
|
|
225
|
+
|
|
226
|
+
DetHDC exposes the seed explicitly:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
model = DetHDC(seed=42)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
You can inspect the complete configuration:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
print(model.get_config())
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
{
|
|
242
|
+
"dimensions": 10000,
|
|
243
|
+
"epochs": 5,
|
|
244
|
+
"lr": 0.01,
|
|
245
|
+
"margin": 0.2,
|
|
246
|
+
"refinement": True,
|
|
247
|
+
"scramble": True,
|
|
248
|
+
"seed": 42,
|
|
249
|
+
"device": "cuda"
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 🧪 Testing
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
pip install -e ".[test]"
|
|
259
|
+
pytest
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The test suite checks:
|
|
263
|
+
|
|
264
|
+
- output dimensions,
|
|
265
|
+
- deterministic Sobol generation,
|
|
266
|
+
- fitting and prediction,
|
|
267
|
+
- model save/load,
|
|
268
|
+
- CPU execution,
|
|
269
|
+
- CUDA execution when available.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🧪 Library Sanity Check
|
|
274
|
+
|
|
275
|
+
Using the reproducible MNIST example included in this repository:
|
|
276
|
+
|
|
277
|
+
| Configuration | Result |
|
|
278
|
+
|---|---:|
|
|
279
|
+
| Dimension | 10,000 |
|
|
280
|
+
| Refinement iterations | 5 |
|
|
281
|
+
| Seed | 42 |
|
|
282
|
+
| Test split | 30% stratified |
|
|
283
|
+
| Accuracy | **95.46%** |
|
|
284
|
+
|
|
285
|
+
The packaged example uses a fixed deterministic split and seed and is
|
|
286
|
+
intended as a reproducible usage example rather than an exact recreation
|
|
287
|
+
of the paper's experimental split.
|
|
288
|
+
|
|
289
|
+
## 📄 Paper
|
|
290
|
+
|
|
291
|
+
**Deterministic Hyperdimensional Learning with Rank Refinement**
|
|
292
|
+
Abu Kaisar Mohammad Masum and Sercan Aygun
|
|
293
|
+
*Proceedings of the AAAI Conference on Artificial Intelligence*, 2026.
|
|
294
|
+
|
|
295
|
+
Paper:
|
|
296
|
+
|
|
297
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/42253
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## 📚 Citation
|
|
302
|
+
|
|
303
|
+
If this repository helps your research, please cite our AAAI paper:
|
|
304
|
+
|
|
305
|
+
```bibtex
|
|
306
|
+
@inproceedings{masum2026deterministic,
|
|
307
|
+
title={Deterministic hyperdimensional learning with rank refinement (student abstract)},
|
|
308
|
+
author={Masum, Abu Kaisar Mohammad and Aygun, Sercan},
|
|
309
|
+
booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
|
|
310
|
+
volume={40},
|
|
311
|
+
number={48},
|
|
312
|
+
pages={41313--41315},
|
|
313
|
+
year={2026}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
## 📜 License
|
|
319
|
+
|
|
320
|
+
Released under the [MIT License](LICENSE).
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
**Deterministic projections. Lightweight learning. Reproducible HDC.**
|
|
325
|
+
|
|
326
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dethdc"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Deterministic Hyperdimensional Learning with Sobol projections and rank refinement"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Abu Kaisar Mohammad Masum"}
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy>=1.24",
|
|
17
|
+
"torch>=2.0"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
examples = [
|
|
22
|
+
"torchvision>=0.15",
|
|
23
|
+
"scikit-learn>=1.2",
|
|
24
|
+
"tqdm>=4.65"
|
|
25
|
+
]
|
|
26
|
+
test = [
|
|
27
|
+
"pytest>=7.0"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Paper = "https://ojs.aaai.org/index.php/AAAI/article/view/42253"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
dethdc-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
import torch.nn.functional as F
|
|
5
|
+
|
|
6
|
+
from .encoder import SobolEncoder
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DetHDC:
|
|
10
|
+
"""Deterministic HDC classifier with optional rank-based refinement."""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
dimensions=10000,
|
|
15
|
+
epochs=5,
|
|
16
|
+
lr=0.01,
|
|
17
|
+
margin=0.2,
|
|
18
|
+
refinement=True,
|
|
19
|
+
scramble=True,
|
|
20
|
+
seed=42,
|
|
21
|
+
device="auto",
|
|
22
|
+
):
|
|
23
|
+
self.dimensions = int(dimensions)
|
|
24
|
+
self.epochs = int(epochs)
|
|
25
|
+
self.lr = float(lr)
|
|
26
|
+
self.margin = float(margin)
|
|
27
|
+
self.refinement = bool(refinement)
|
|
28
|
+
self.scramble = bool(scramble)
|
|
29
|
+
self.seed = int(seed)
|
|
30
|
+
|
|
31
|
+
self.encoder = SobolEncoder(
|
|
32
|
+
dimensions=self.dimensions,
|
|
33
|
+
scramble=self.scramble,
|
|
34
|
+
seed=self.seed,
|
|
35
|
+
device=device,
|
|
36
|
+
)
|
|
37
|
+
self.device = self.encoder.device
|
|
38
|
+
|
|
39
|
+
self.class_hypervectors_ = None
|
|
40
|
+
self.classes_ = None
|
|
41
|
+
|
|
42
|
+
def encode(self, X):
|
|
43
|
+
return self.encoder.transform(X)
|
|
44
|
+
|
|
45
|
+
def _initialize_prototypes(self, encoded, y):
|
|
46
|
+
y = torch.as_tensor(y, dtype=torch.long, device=self.device)
|
|
47
|
+
self.classes_ = torch.unique(y, sorted=True)
|
|
48
|
+
|
|
49
|
+
if not torch.equal(
|
|
50
|
+
self.classes_,
|
|
51
|
+
torch.arange(len(self.classes_), device=self.device),
|
|
52
|
+
):
|
|
53
|
+
raise ValueError(
|
|
54
|
+
"Current implementation expects integer class labels 0..C-1."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
prototypes = torch.zeros(
|
|
58
|
+
(len(self.classes_), self.dimensions),
|
|
59
|
+
dtype=torch.float32,
|
|
60
|
+
device=self.device,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
prototypes.index_add_(0, y, encoded)
|
|
64
|
+
return F.normalize(prototypes, p=2, dim=1, eps=1e-12)
|
|
65
|
+
|
|
66
|
+
def _rank_refine(self, encoded, y):
|
|
67
|
+
y = torch.as_tensor(y, dtype=torch.long, device=self.device)
|
|
68
|
+
|
|
69
|
+
prototypes = self.class_hypervectors_.clone().detach().requires_grad_(True)
|
|
70
|
+
optimizer = torch.optim.SGD([prototypes], lr=self.lr)
|
|
71
|
+
|
|
72
|
+
for _ in range(self.epochs):
|
|
73
|
+
order = torch.randperm(
|
|
74
|
+
len(encoded),
|
|
75
|
+
generator=torch.Generator(device="cpu").manual_seed(self.seed),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
for idx in order.tolist():
|
|
79
|
+
optimizer.zero_grad()
|
|
80
|
+
|
|
81
|
+
x = encoded[idx : idx + 1]
|
|
82
|
+
target = int(y[idx].item())
|
|
83
|
+
|
|
84
|
+
sims = F.cosine_similarity(x, prototypes)
|
|
85
|
+
pred = int(torch.argmax(sims).item())
|
|
86
|
+
|
|
87
|
+
if pred == target:
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
loss = torch.clamp(
|
|
91
|
+
self.margin - (sims[target] - sims[pred]),
|
|
92
|
+
min=0.0,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if loss.item() > 0:
|
|
96
|
+
loss.backward()
|
|
97
|
+
optimizer.step()
|
|
98
|
+
|
|
99
|
+
with torch.no_grad():
|
|
100
|
+
prototypes[:] = F.normalize(
|
|
101
|
+
prototypes, p=2, dim=1, eps=1e-12
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self.class_hypervectors_ = prototypes.detach()
|
|
105
|
+
|
|
106
|
+
def fit(self, X, y):
|
|
107
|
+
encoded = self.encoder.fit_transform(X)
|
|
108
|
+
self.class_hypervectors_ = self._initialize_prototypes(encoded, y)
|
|
109
|
+
|
|
110
|
+
if self.refinement and self.epochs > 0:
|
|
111
|
+
self._rank_refine(encoded, y)
|
|
112
|
+
|
|
113
|
+
return self
|
|
114
|
+
|
|
115
|
+
def predict_similarity(self, X):
|
|
116
|
+
self._check_fitted()
|
|
117
|
+
encoded = self.encode(X)
|
|
118
|
+
encoded = F.normalize(encoded, p=2, dim=1, eps=1e-12)
|
|
119
|
+
prototypes = F.normalize(
|
|
120
|
+
self.class_hypervectors_, p=2, dim=1, eps=1e-12
|
|
121
|
+
)
|
|
122
|
+
return encoded @ prototypes.T
|
|
123
|
+
|
|
124
|
+
def predict(self, X):
|
|
125
|
+
similarities = self.predict_similarity(X)
|
|
126
|
+
return torch.argmax(similarities, dim=1).detach().cpu().numpy()
|
|
127
|
+
|
|
128
|
+
def score(self, X, y):
|
|
129
|
+
pred = torch.as_tensor(self.predict(X))
|
|
130
|
+
target = torch.as_tensor(y).cpu()
|
|
131
|
+
return float((pred == target).float().mean().item())
|
|
132
|
+
|
|
133
|
+
def get_config(self):
|
|
134
|
+
return {
|
|
135
|
+
"dimensions": self.dimensions,
|
|
136
|
+
"epochs": self.epochs,
|
|
137
|
+
"lr": self.lr,
|
|
138
|
+
"margin": self.margin,
|
|
139
|
+
"refinement": self.refinement,
|
|
140
|
+
"scramble": self.scramble,
|
|
141
|
+
"seed": self.seed,
|
|
142
|
+
"device": str(self.device),
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
def save(self, path):
|
|
146
|
+
self._check_fitted()
|
|
147
|
+
payload = {
|
|
148
|
+
"config": self.get_config(),
|
|
149
|
+
"classes": self.classes_.detach().cpu(),
|
|
150
|
+
"class_hypervectors": self.class_hypervectors_.detach().cpu(),
|
|
151
|
+
"projection": self.encoder.projection_.detach().cpu(),
|
|
152
|
+
"input_dim": self.encoder.input_dim_,
|
|
153
|
+
}
|
|
154
|
+
torch.save(payload, Path(path))
|
|
155
|
+
|
|
156
|
+
@classmethod
|
|
157
|
+
def load(cls, path, device="auto"):
|
|
158
|
+
payload = torch.load(Path(path), map_location="cpu")
|
|
159
|
+
cfg = dict(payload["config"])
|
|
160
|
+
cfg["device"] = device
|
|
161
|
+
|
|
162
|
+
model = cls(**cfg)
|
|
163
|
+
model.classes_ = payload["classes"].to(model.device)
|
|
164
|
+
model.class_hypervectors_ = payload["class_hypervectors"].to(model.device)
|
|
165
|
+
model.encoder.projection_ = payload["projection"].to(model.device)
|
|
166
|
+
model.encoder.input_dim_ = payload["input_dim"]
|
|
167
|
+
return model
|
|
168
|
+
|
|
169
|
+
def _check_fitted(self):
|
|
170
|
+
if self.class_hypervectors_ is None:
|
|
171
|
+
raise RuntimeError("Call fit() before prediction.")
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import torch
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
from torch.quasirandom import SobolEngine
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SobolEncoder:
|
|
8
|
+
"""Sobol-based deterministic position/value hypervector encoder."""
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
dimensions=10000,
|
|
13
|
+
scramble=True,
|
|
14
|
+
seed=42,
|
|
15
|
+
device="auto",
|
|
16
|
+
):
|
|
17
|
+
self.dimensions = int(dimensions)
|
|
18
|
+
self.scramble = bool(scramble)
|
|
19
|
+
self.seed = int(seed)
|
|
20
|
+
self.device = self._resolve_device(device)
|
|
21
|
+
self.projection_ = None
|
|
22
|
+
self.input_dim_ = None
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def _resolve_device(device):
|
|
26
|
+
if device == "auto":
|
|
27
|
+
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
28
|
+
return torch.device(device)
|
|
29
|
+
|
|
30
|
+
def _build_projection(self, input_dim):
|
|
31
|
+
pos_engine = SobolEngine(
|
|
32
|
+
dimension=input_dim,
|
|
33
|
+
scramble=self.scramble,
|
|
34
|
+
seed=self.seed,
|
|
35
|
+
)
|
|
36
|
+
val_engine = SobolEngine(
|
|
37
|
+
dimension=input_dim,
|
|
38
|
+
scramble=self.scramble,
|
|
39
|
+
seed=self.seed + 1,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
position = 2.0 * pos_engine.draw(self.dimensions) - 1.0
|
|
43
|
+
value = 2.0 * val_engine.draw(self.dimensions) - 1.0
|
|
44
|
+
|
|
45
|
+
self.projection_ = torch.stack(
|
|
46
|
+
[position, value], dim=0
|
|
47
|
+
).to(self.device, dtype=torch.float32)
|
|
48
|
+
|
|
49
|
+
self.input_dim_ = input_dim
|
|
50
|
+
|
|
51
|
+
def fit(self, X):
|
|
52
|
+
X = torch.as_tensor(X)
|
|
53
|
+
input_dim = int(X[0].numel()) if X.ndim > 1 else int(X.numel())
|
|
54
|
+
self._build_projection(input_dim)
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def transform(self, X):
|
|
58
|
+
X = torch.as_tensor(X, dtype=torch.float32, device=self.device)
|
|
59
|
+
X = X.reshape(X.shape[0], -1)
|
|
60
|
+
|
|
61
|
+
if self.projection_ is None:
|
|
62
|
+
self._build_projection(X.shape[1])
|
|
63
|
+
|
|
64
|
+
if X.shape[1] != self.input_dim_:
|
|
65
|
+
raise ValueError(
|
|
66
|
+
f"Expected input dimension {self.input_dim_}, got {X.shape[1]}."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Match the original image preprocessing behavior when inputs are [0,1].
|
|
70
|
+
if torch.min(X) >= 0 and torch.max(X) <= 1:
|
|
71
|
+
X = X * 2.0 - 1.0
|
|
72
|
+
|
|
73
|
+
position = self.projection_[0]
|
|
74
|
+
value = self.projection_[1]
|
|
75
|
+
|
|
76
|
+
inv_sqrt_l = 1.0 / math.sqrt(float(self.input_dim_))
|
|
77
|
+
|
|
78
|
+
pos = torch.einsum("bi,di->bd", X, position) * inv_sqrt_l
|
|
79
|
+
val = torch.einsum("bi,di->bd", X, value) * inv_sqrt_l
|
|
80
|
+
|
|
81
|
+
hv = pos * val
|
|
82
|
+
return F.normalize(hv, p=2, dim=1, eps=1e-12)
|
|
83
|
+
|
|
84
|
+
def fit_transform(self, X):
|
|
85
|
+
return self.fit(X).transform(X)
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dethdc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic Hyperdimensional Learning with Sobol projections and rank refinement
|
|
5
|
+
Author: Abu Kaisar Mohammad Masum
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Paper, https://ojs.aaai.org/index.php/AAAI/article/view/42253
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: numpy>=1.24
|
|
12
|
+
Requires-Dist: torch>=2.0
|
|
13
|
+
Provides-Extra: examples
|
|
14
|
+
Requires-Dist: torchvision>=0.15; extra == "examples"
|
|
15
|
+
Requires-Dist: scikit-learn>=1.2; extra == "examples"
|
|
16
|
+
Requires-Dist: tqdm>=4.65; extra == "examples"
|
|
17
|
+
Provides-Extra: test
|
|
18
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
<div align="center">
|
|
22
|
+
|
|
23
|
+
# DetHDC
|
|
24
|
+
|
|
25
|
+
### Deterministic Hyperdimensional Learning with Rank Refinement
|
|
26
|
+
|
|
27
|
+
[](https://ojs.aaai.org/index.php/AAAI/article/view/42253)
|
|
28
|
+
[](https://www.python.org/)
|
|
29
|
+
[](https://pytorch.org/)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
|
|
32
|
+
**Official research implementation of the AAAI 2026 paper
|
|
33
|
+
“Deterministic Hyperdimensional Learning with Rank Refinement.”**
|
|
34
|
+
|
|
35
|
+
[Paper](https://ojs.aaai.org/index.php/AAAI/article/view/42253) · [Quick Start](#-quick-start) · [Citation](#-citation)
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ✨ Overview
|
|
42
|
+
|
|
43
|
+
**DetHDC** is a lightweight PyTorch library for deterministic hyperdimensional learning using:
|
|
44
|
+
|
|
45
|
+
- **Sobol quasi-random projections**
|
|
46
|
+
- **position–value binding**
|
|
47
|
+
- **prototype-based HDC classification**
|
|
48
|
+
- **rank-based refinement**
|
|
49
|
+
- **CPU and CUDA execution**
|
|
50
|
+
- **reproducible training through explicit random seeds**
|
|
51
|
+
|
|
52
|
+
The repository turns the method from our AAAI 2026 paper into a reusable Python API instead of a dataset-specific research script.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🧠 Method at a Glance
|
|
57
|
+
|
|
58
|
+
Given an input vector \(x \in \mathbb{R}^{L}\), DetHDC builds two deterministic projection spaces:
|
|
59
|
+
|
|
60
|
+
\[
|
|
61
|
+
P, V \in \mathbb{R}^{D \times L},
|
|
62
|
+
\]
|
|
63
|
+
|
|
64
|
+
where \(P\) and \(V\) are generated from scrambled Sobol sequences.
|
|
65
|
+
|
|
66
|
+
The projected representations are
|
|
67
|
+
|
|
68
|
+
\[
|
|
69
|
+
h_p = \frac{xP^\top}{\sqrt{L}},
|
|
70
|
+
\qquad
|
|
71
|
+
h_v = \frac{xV^\top}{\sqrt{L}},
|
|
72
|
+
\]
|
|
73
|
+
|
|
74
|
+
and the final hypervector is obtained through element-wise binding:
|
|
75
|
+
|
|
76
|
+
\[
|
|
77
|
+
h = \mathrm{norm}(h_p \odot h_v).
|
|
78
|
+
\]
|
|
79
|
+
|
|
80
|
+
Class prototypes are first constructed by bundling encoded samples. A rank-based refinement stage then updates prototypes when the true class is not sufficiently separated from the strongest competing class.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🚀 Quick Start
|
|
85
|
+
|
|
86
|
+
### Install from source
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/Abu-Kaisar-Mohammad-Masum/DetHDC.git
|
|
90
|
+
cd DetHDC
|
|
91
|
+
pip install -e .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Minimal example
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from dethdc import DetHDC
|
|
98
|
+
|
|
99
|
+
model = DetHDC(
|
|
100
|
+
dimensions=10000,
|
|
101
|
+
epochs=5,
|
|
102
|
+
lr=0.01,
|
|
103
|
+
margin=0.2,
|
|
104
|
+
seed=42,
|
|
105
|
+
device="auto",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
model.fit(X_train, y_train)
|
|
109
|
+
|
|
110
|
+
predictions = model.predict(X_test)
|
|
111
|
+
accuracy = model.score(X_test, y_test)
|
|
112
|
+
|
|
113
|
+
print(f"Accuracy: {accuracy * 100:.2f}%")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 🔥 Why DetHDC?
|
|
119
|
+
|
|
120
|
+
Traditional HDC implementations often rely on randomly generated hypervectors. That can introduce run-to-run variation and make reproducibility harder.
|
|
121
|
+
|
|
122
|
+
DetHDC instead uses **Sobol-based deterministic projections**, giving a controlled projection space while retaining the efficiency and robustness properties of hyperdimensional learning.
|
|
123
|
+
|
|
124
|
+
The library also exposes the refinement stage directly:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
model = DetHDC(
|
|
128
|
+
dimensions=10000,
|
|
129
|
+
refinement=True,
|
|
130
|
+
epochs=5,
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For a base model without rank refinement:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
model = DetHDC(
|
|
138
|
+
dimensions=10000,
|
|
139
|
+
refinement=False,
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 📦 Library API
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from dethdc import DetHDC, SobolEncoder
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### `DetHDC`
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
DetHDC(
|
|
155
|
+
dimensions=10000,
|
|
156
|
+
epochs=5,
|
|
157
|
+
lr=0.01,
|
|
158
|
+
margin=0.2,
|
|
159
|
+
refinement=True,
|
|
160
|
+
scramble=True,
|
|
161
|
+
seed=42,
|
|
162
|
+
device="auto",
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Main methods:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
model.fit(X, y)
|
|
170
|
+
model.encode(X)
|
|
171
|
+
model.predict(X)
|
|
172
|
+
model.predict_similarity(X)
|
|
173
|
+
model.score(X, y)
|
|
174
|
+
model.get_config()
|
|
175
|
+
model.save("model.pt")
|
|
176
|
+
DetHDC.load("model.pt")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 🧪 MNIST Example
|
|
182
|
+
|
|
183
|
+
Run:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python examples/mnist.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The example:
|
|
190
|
+
|
|
191
|
+
1. downloads MNIST,
|
|
192
|
+
2. flattens native \(28 \times 28\) images,
|
|
193
|
+
3. constructs Sobol projection matrices,
|
|
194
|
+
4. encodes the training/test sets,
|
|
195
|
+
5. builds class prototypes,
|
|
196
|
+
6. performs rank-based refinement,
|
|
197
|
+
7. reports classification accuracy.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🗂 Repository Structure
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
DetHDC/
|
|
205
|
+
├── README.md
|
|
206
|
+
├── LICENSE
|
|
207
|
+
├── CITATION.cff
|
|
208
|
+
├── pyproject.toml
|
|
209
|
+
├── src/
|
|
210
|
+
│ └── dethdc/
|
|
211
|
+
│ ├── __init__.py
|
|
212
|
+
│ ├── classifier.py
|
|
213
|
+
│ └── encoder.py
|
|
214
|
+
├── examples/
|
|
215
|
+
│ └── mnist.py
|
|
216
|
+
├── benchmarks/
|
|
217
|
+
│ └── reproduce_aaai2026.py
|
|
218
|
+
└── tests/
|
|
219
|
+
├── test_encoder.py
|
|
220
|
+
└── test_classifier.py
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## ⚡ GPU Support
|
|
226
|
+
|
|
227
|
+
DetHDC automatically uses CUDA when available:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
model = DetHDC(device="auto")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
You can also force a backend:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
model = DetHDC(device="cpu")
|
|
237
|
+
model = DetHDC(device="cuda")
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Classification stays in PyTorch and avoids unnecessary GPU → CPU → NumPy transfers.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 🔬 Reproducibility
|
|
245
|
+
|
|
246
|
+
DetHDC exposes the seed explicitly:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
model = DetHDC(seed=42)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
You can inspect the complete configuration:
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
print(model.get_config())
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Example:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
{
|
|
262
|
+
"dimensions": 10000,
|
|
263
|
+
"epochs": 5,
|
|
264
|
+
"lr": 0.01,
|
|
265
|
+
"margin": 0.2,
|
|
266
|
+
"refinement": True,
|
|
267
|
+
"scramble": True,
|
|
268
|
+
"seed": 42,
|
|
269
|
+
"device": "cuda"
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 🧪 Testing
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
pip install -e ".[test]"
|
|
279
|
+
pytest
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The test suite checks:
|
|
283
|
+
|
|
284
|
+
- output dimensions,
|
|
285
|
+
- deterministic Sobol generation,
|
|
286
|
+
- fitting and prediction,
|
|
287
|
+
- model save/load,
|
|
288
|
+
- CPU execution,
|
|
289
|
+
- CUDA execution when available.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 🧪 Library Sanity Check
|
|
294
|
+
|
|
295
|
+
Using the reproducible MNIST example included in this repository:
|
|
296
|
+
|
|
297
|
+
| Configuration | Result |
|
|
298
|
+
|---|---:|
|
|
299
|
+
| Dimension | 10,000 |
|
|
300
|
+
| Refinement iterations | 5 |
|
|
301
|
+
| Seed | 42 |
|
|
302
|
+
| Test split | 30% stratified |
|
|
303
|
+
| Accuracy | **95.46%** |
|
|
304
|
+
|
|
305
|
+
The packaged example uses a fixed deterministic split and seed and is
|
|
306
|
+
intended as a reproducible usage example rather than an exact recreation
|
|
307
|
+
of the paper's experimental split.
|
|
308
|
+
|
|
309
|
+
## 📄 Paper
|
|
310
|
+
|
|
311
|
+
**Deterministic Hyperdimensional Learning with Rank Refinement**
|
|
312
|
+
Abu Kaisar Mohammad Masum and Sercan Aygun
|
|
313
|
+
*Proceedings of the AAAI Conference on Artificial Intelligence*, 2026.
|
|
314
|
+
|
|
315
|
+
Paper:
|
|
316
|
+
|
|
317
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/42253
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 📚 Citation
|
|
322
|
+
|
|
323
|
+
If this repository helps your research, please cite our AAAI paper:
|
|
324
|
+
|
|
325
|
+
```bibtex
|
|
326
|
+
@inproceedings{masum2026deterministic,
|
|
327
|
+
title={Deterministic hyperdimensional learning with rank refinement (student abstract)},
|
|
328
|
+
author={Masum, Abu Kaisar Mohammad and Aygun, Sercan},
|
|
329
|
+
booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
|
|
330
|
+
volume={40},
|
|
331
|
+
number={48},
|
|
332
|
+
pages={41313--41315},
|
|
333
|
+
year={2026}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
## 📜 License
|
|
339
|
+
|
|
340
|
+
Released under the [MIT License](LICENSE).
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
**Deterministic projections. Lightweight learning. Reproducible HDC.**
|
|
345
|
+
|
|
346
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/dethdc/__init__.py
|
|
5
|
+
src/dethdc/classifier.py
|
|
6
|
+
src/dethdc/encoder.py
|
|
7
|
+
src/dethdc.egg-info/PKG-INFO
|
|
8
|
+
src/dethdc.egg-info/SOURCES.txt
|
|
9
|
+
src/dethdc.egg-info/dependency_links.txt
|
|
10
|
+
src/dethdc.egg-info/requires.txt
|
|
11
|
+
src/dethdc.egg-info/top_level.txt
|
|
12
|
+
tests/test_classifier.py
|
|
13
|
+
tests/test_encoder.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dethdc
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from dethdc import DetHDC
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_fit_predict():
|
|
7
|
+
rng = np.random.RandomState(42)
|
|
8
|
+
|
|
9
|
+
X0 = rng.normal(0.2, 0.05, size=(20, 8)).astype("float32")
|
|
10
|
+
X1 = rng.normal(0.8, 0.05, size=(20, 8)).astype("float32")
|
|
11
|
+
|
|
12
|
+
X = np.vstack([X0, X1])
|
|
13
|
+
y = np.array([0] * 20 + [1] * 20)
|
|
14
|
+
|
|
15
|
+
model = DetHDC(
|
|
16
|
+
dimensions=256,
|
|
17
|
+
epochs=1,
|
|
18
|
+
refinement=True,
|
|
19
|
+
seed=42,
|
|
20
|
+
device="cpu",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
model.fit(X, y)
|
|
24
|
+
pred = model.predict(X)
|
|
25
|
+
|
|
26
|
+
assert pred.shape == y.shape
|
|
27
|
+
assert model.score(X, y) >= 0.5
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
|
|
4
|
+
from dethdc import SobolEncoder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_encoder_shape():
|
|
8
|
+
X = np.random.RandomState(0).rand(8, 16).astype("float32")
|
|
9
|
+
encoder = SobolEncoder(dimensions=128, seed=42, device="cpu")
|
|
10
|
+
H = encoder.fit_transform(X)
|
|
11
|
+
assert H.shape == (8, 128)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_same_seed_same_projection():
|
|
15
|
+
X = np.random.RandomState(1).rand(4, 8).astype("float32")
|
|
16
|
+
|
|
17
|
+
a = SobolEncoder(dimensions=64, seed=7, device="cpu").fit_transform(X)
|
|
18
|
+
b = SobolEncoder(dimensions=64, seed=7, device="cpu").fit_transform(X)
|
|
19
|
+
|
|
20
|
+
assert torch.allclose(a, b)
|