PyHierarchicalTsetlinMachineCUDA 0.2.2__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.
- PyHierarchicalTsetlinMachineCUDA-0.2.2/LICENSE +21 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PKG-INFO +13 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA/__init__.py +1 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA/kernels.py +485 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA/tm.py +630 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA/tools.py +43 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA.egg-info/PKG-INFO +13 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA.egg-info/SOURCES.txt +16 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA.egg-info/dependency_links.txt +1 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA.egg-info/requires.txt +7 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/PyHierarchicalTsetlinMachineCUDA.egg-info/top_level.txt +1 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/README.md +107 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/setup.cfg +4 -0
- PyHierarchicalTsetlinMachineCUDA-0.2.2/setup.py +23 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ole-Christoffer Granmo and the University of Agder
|
|
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,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: PyHierarchicalTsetlinMachineCUDA
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Hierarchical Tsetlin Machine Architecture.
|
|
5
|
+
Home-page: https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/
|
|
6
|
+
Author: Ole-Christoffer Granmo
|
|
7
|
+
Author-email: ole.granmo@uia.no
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: pattern-recognition cuda machine-learning interpretable-machine-learning rule-based-machine-learning propositional-logic tsetlin-machine regression convolution classification multi-layer
|
|
10
|
+
Provides-Extra: examples
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
|
|
13
|
+
Hierarchical Tsetlin Machine Architecture.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
# Copyright (c) 2026 Ole-Christoffer Granmo and the University of Agder
|
|
2
|
+
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
# furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
# SOFTWARE.
|
|
20
|
+
|
|
21
|
+
code_header = """
|
|
22
|
+
#include <curand_kernel.h>
|
|
23
|
+
|
|
24
|
+
#define INT_SIZE 32ULL
|
|
25
|
+
|
|
26
|
+
#if (LITERALS_PER_LEAF % 32 != 0)
|
|
27
|
+
#define FILTER_HIERARCHICAL (~(0xffffffff << (LITERALS_PER_LEAF % INT_SIZE)))
|
|
28
|
+
#else
|
|
29
|
+
#define FILTER_HIERARCHICAL 0xffffffff
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
#define VANILLA_TM 0
|
|
33
|
+
|
|
34
|
+
#define WEIGHTED_TM 1
|
|
35
|
+
|
|
36
|
+
#define COALESCED_TM 2
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
code_update = """
|
|
40
|
+
extern "C"
|
|
41
|
+
{
|
|
42
|
+
// Increment the states of each of those 32 Tsetlin Automata flagged in the active bit vector.
|
|
43
|
+
__device__ inline void inc(unsigned int *ta_state, int chunk, unsigned int active)
|
|
44
|
+
{
|
|
45
|
+
unsigned int carry, carry_next;
|
|
46
|
+
int id = chunk*STATE_BITS;
|
|
47
|
+
carry = active;
|
|
48
|
+
for (int b = 0; b < STATE_BITS; ++b) {
|
|
49
|
+
if (carry == 0)
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
carry_next = ta_state[id + b] & carry; // Sets carry bits (overflow) passing on to next bit
|
|
53
|
+
ta_state[id + b] = ta_state[id + b] ^ carry; // Performs increments with XOR
|
|
54
|
+
carry = carry_next;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (carry > 0) {
|
|
58
|
+
for (int b = 0; b < STATE_BITS; ++b) {
|
|
59
|
+
ta_state[id + b] |= carry;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Decrement the states of each of those 32 Tsetlin Automata flagged in the active bit vector.
|
|
65
|
+
__device__ inline void dec(unsigned int *ta_state, int chunk, unsigned int active)
|
|
66
|
+
{
|
|
67
|
+
unsigned int carry, carry_next;
|
|
68
|
+
int id = chunk*STATE_BITS;
|
|
69
|
+
carry = active;
|
|
70
|
+
for (int b = 0; b < STATE_BITS; ++b) {
|
|
71
|
+
if (carry == 0)
|
|
72
|
+
break;
|
|
73
|
+
carry_next = (~ta_state[id + b]) & carry; // Sets carry bits (overflow) passing on to next bit
|
|
74
|
+
ta_state[id + b] = ta_state[id + b] ^ carry; // Performs increments with XOR
|
|
75
|
+
carry = carry_next;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (carry > 0) {
|
|
79
|
+
for (int b = 0; b < STATE_BITS; ++b) {
|
|
80
|
+
ta_state[id + b] &= ~carry;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
__device__ inline void update_clause_weight(curandState *localState, int tm_type, int number_of_outputs, int *clause_weight, int clause_output, int y, int class_sum)
|
|
86
|
+
{
|
|
87
|
+
int target = 1 - 2*(class_sum > y);
|
|
88
|
+
|
|
89
|
+
if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
94
|
+
|
|
95
|
+
int absolute_prediction_error = abs(y - class_sum);
|
|
96
|
+
if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
|
|
97
|
+
if (target*sign > 0) {
|
|
98
|
+
if (clause_output && abs(*clause_weight) < INT_MAX) {
|
|
99
|
+
(*clause_weight) += sign;
|
|
100
|
+
}
|
|
101
|
+
} else if (target*sign < 0 && clause_output) {
|
|
102
|
+
// Type II Feedback
|
|
103
|
+
|
|
104
|
+
(*clause_weight) -= sign;
|
|
105
|
+
|
|
106
|
+
#if FLIP_POLARITY == 0
|
|
107
|
+
if (*clause_weight == 0) {
|
|
108
|
+
*clause_weight += sign;
|
|
109
|
+
}
|
|
110
|
+
#endif
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
__device__ inline void update_component_hierarchy(curandState *localState, int number_of_outputs, int *clause_weight, unsigned int *ta_state, int component_output, int *X, int y, int class_sum)
|
|
116
|
+
{
|
|
117
|
+
int target = 1 - 2*(class_sum > y);
|
|
118
|
+
|
|
119
|
+
if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
int sign = (*clause_weight >= 0) - (*clause_weight < 0);
|
|
125
|
+
|
|
126
|
+
int absolute_prediction_error = abs(y - class_sum);
|
|
127
|
+
if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
|
|
128
|
+
if (target*sign > 0) {
|
|
129
|
+
// Type I Feedback
|
|
130
|
+
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
|
|
131
|
+
// Generate random bit values
|
|
132
|
+
unsigned int la_feedback = 0;
|
|
133
|
+
for (int b = 0; b < INT_SIZE; ++b) {
|
|
134
|
+
if (curand_uniform(localState) <= 1.0/S) {
|
|
135
|
+
la_feedback |= (1 << b);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (component_output) {
|
|
140
|
+
#if BOOST_TRUE_POSITIVE_FEEDBACK == 1
|
|
141
|
+
inc(ta_state, ta_chunk, X[ta_chunk]);
|
|
142
|
+
#else
|
|
143
|
+
inc(ta_state, ta_chunk, X[ta_chunk] & (~la_feedback));
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
dec(ta_state, ta_chunk, (~X[ta_chunk]) & la_feedback);
|
|
147
|
+
} else {
|
|
148
|
+
dec(ta_state, ta_chunk, la_feedback);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else if (target*sign < 0 && component_output) {
|
|
152
|
+
// Type II Feedback
|
|
153
|
+
|
|
154
|
+
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
|
|
155
|
+
inc(ta_state, ta_chunk, (~X[ta_chunk]) & (~ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Evaluate example
|
|
162
|
+
__global__ void evaluate_leaves(unsigned int *global_ta_state, int *component_weights, int *global_component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_alternatives, int *X, int example)
|
|
163
|
+
{
|
|
164
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
165
|
+
int stride = blockDim.x * gridDim.x;
|
|
166
|
+
|
|
167
|
+
int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
|
|
168
|
+
|
|
169
|
+
// Evaluate each clause component (leaf) in separate threads
|
|
170
|
+
for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
|
|
171
|
+
int component = clause_component % COMPONENTS;
|
|
172
|
+
|
|
173
|
+
// Get state of current clause component
|
|
174
|
+
unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
|
|
175
|
+
|
|
176
|
+
int component_remainder = component;
|
|
177
|
+
int ta_chunk_base = 0;
|
|
178
|
+
int size = 1;
|
|
179
|
+
for (int d = 0; d < depth-1; ++d) {
|
|
180
|
+
int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
|
|
181
|
+
component_remainder = component_remainder / hierarchy_structure_factors[d];
|
|
182
|
+
|
|
183
|
+
if (hierarchy_structure_alternatives[d] == 0) {
|
|
184
|
+
ta_chunk_base += size * depth_d_node_index * TA_CHUNKS_PER_LEAF;
|
|
185
|
+
size *= hierarchy_structure_factors[d];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Evaluate clause component
|
|
190
|
+
int component_output = 1;
|
|
191
|
+
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF-1; ++ta_chunk) {
|
|
192
|
+
// Compare the TA state of the component (leaf) against the corresponding part of the feature vector
|
|
193
|
+
if ((ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] & Xi[ta_chunk_base + ta_chunk]) != ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]) {
|
|
194
|
+
component_output = 0;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if ((ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & Xi[ta_chunk_base + TA_CHUNKS_PER_LEAF-1] & FILTER_HIERARCHICAL) != (ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & FILTER_HIERARCHICAL)) {
|
|
200
|
+
component_output = 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
global_component_output[clause_component] = component_output;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
__global__ void evaluate_or_groups(int *child_input, int *or_group_node_output, int number_of_or_group_nodes, int number_of_or_group_addends)
|
|
208
|
+
{
|
|
209
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
210
|
+
int stride = blockDim.x * gridDim.x;
|
|
211
|
+
|
|
212
|
+
// Add up the votes of each OR node child
|
|
213
|
+
for (int or_group_node = index; or_group_node < CLAUSES*number_of_or_group_nodes; or_group_node += stride) {
|
|
214
|
+
// Add OR addends
|
|
215
|
+
int or_group_vote_sum = 0;
|
|
216
|
+
for (int or_addend = 0; or_addend < number_of_or_group_addends; ++or_addend) {
|
|
217
|
+
// Aggregate votes from each child node through addition
|
|
218
|
+
or_group_vote_sum += child_input[or_group_node*number_of_or_group_addends + or_addend];
|
|
219
|
+
//if (child_input[or_group_node*number_of_or_group_addends + or_addend]) {
|
|
220
|
+
// or_group_vote_sum = 1;
|
|
221
|
+
//}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Store or group vote sum as node output
|
|
225
|
+
or_group_node_output[or_group_node] = or_group_vote_sum;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
__global__ void evaluate_and_groups(int *child_input, int *and_group_node_output, int number_of_and_group_nodes, int number_of_and_group_factors)
|
|
230
|
+
{
|
|
231
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
232
|
+
int stride = blockDim.x * gridDim.x;
|
|
233
|
+
|
|
234
|
+
// Multiply the votes from the children of each AND node
|
|
235
|
+
for (int and_group_node = index; and_group_node < CLAUSES*number_of_and_group_nodes; and_group_node += stride) {
|
|
236
|
+
// Multiply and factors
|
|
237
|
+
int and_group_vote_product = 1;
|
|
238
|
+
for (int and_factor = 0; and_factor < number_of_and_group_factors; ++and_factor) {
|
|
239
|
+
// Aggregate votes from each child node through multiplication
|
|
240
|
+
and_group_vote_product *= child_input[and_group_node*number_of_and_group_factors + and_factor];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Store and group product as node output
|
|
244
|
+
and_group_node_output[and_group_node] = and_group_vote_product;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
__global__ void propagate_and_group_false_truth_values(int *child_input, int *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
|
|
249
|
+
{
|
|
250
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
251
|
+
int stride = blockDim.x * gridDim.x;
|
|
252
|
+
|
|
253
|
+
// If a group node is false, all children are made false.
|
|
254
|
+
for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
|
|
255
|
+
if (group_node_output[group_node] == 0) {
|
|
256
|
+
for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
|
|
257
|
+
if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
|
|
258
|
+
child_input[group_node*number_of_group_node_children + and_factor] = 0;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
__global__ void evaluate_or_alternatives(int *child_input, int *or_alternatives_node_output, int number_of_or_alternatives_nodes, int number_of_or_alternatives)
|
|
266
|
+
{
|
|
267
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
268
|
+
int stride = blockDim.x * gridDim.x;
|
|
269
|
+
|
|
270
|
+
// Add up the votes from the children of each OR node
|
|
271
|
+
for (int or_alternatives_node = index; or_alternatives_node < CLAUSES*number_of_or_alternatives_nodes; or_alternatives_node += stride) {
|
|
272
|
+
// Sum up votes from each or alternative
|
|
273
|
+
int or_alternatives_vote_sum = 0;
|
|
274
|
+
for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
|
|
275
|
+
// Aggregate same input or alternatives through summation
|
|
276
|
+
or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
|
|
277
|
+
|
|
278
|
+
//if (child_input[or_alternatives_node * number_of_or_alternatives + or_alternative]) {
|
|
279
|
+
// or_alternatives_vote_sum = 1;
|
|
280
|
+
//}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Store vote sum as node output
|
|
284
|
+
or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
__global__ void evaluate_final(int number_of_outputs, int *child_input, int *clause_weights, int *class_sum)
|
|
289
|
+
{
|
|
290
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
291
|
+
int stride = blockDim.x * gridDim.x;
|
|
292
|
+
|
|
293
|
+
// Add up the votes from each clause
|
|
294
|
+
for (int clause = index; clause < CLAUSES; clause += stride) {
|
|
295
|
+
if (child_input[clause]) {
|
|
296
|
+
for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
297
|
+
int clause_weight = clause_weights[class_id*CLAUSES + clause];
|
|
298
|
+
atomicAdd(&class_sum[class_id], clause_weight * child_input[clause]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Update state of Tsetlin Automata team
|
|
305
|
+
__global__ void update_hierarchy(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, int *component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_alternatives, int *class_sum, int *X, int *y, int example)
|
|
306
|
+
{
|
|
307
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
308
|
+
int stride = blockDim.x * gridDim.x;
|
|
309
|
+
|
|
310
|
+
/* Copy state to local memory for efficiency */
|
|
311
|
+
curandState localState = state[index];
|
|
312
|
+
|
|
313
|
+
int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
|
|
314
|
+
|
|
315
|
+
// Calculate clause output first
|
|
316
|
+
for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
|
|
317
|
+
int clause = clause_component / COMPONENTS;
|
|
318
|
+
int component = clause_component % COMPONENTS;
|
|
319
|
+
|
|
320
|
+
// Get state of current clause component
|
|
321
|
+
unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
|
|
322
|
+
|
|
323
|
+
int component_remainder = component;
|
|
324
|
+
int ta_chunk_base = 0;
|
|
325
|
+
int size = 1;
|
|
326
|
+
for (int d = 0; d < depth-1; ++d) {
|
|
327
|
+
int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
|
|
328
|
+
component_remainder = component_remainder / hierarchy_structure_factors[d];
|
|
329
|
+
|
|
330
|
+
if (hierarchy_structure_alternatives[d] == 0) {
|
|
331
|
+
ta_chunk_base += size * depth_d_node_index * TA_CHUNKS_PER_LEAF;
|
|
332
|
+
size *= hierarchy_structure_factors[d];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
337
|
+
int local_class_sum = class_sum[class_id];
|
|
338
|
+
if (local_class_sum > THRESHOLD) {
|
|
339
|
+
local_class_sum = THRESHOLD;
|
|
340
|
+
} else if (local_class_sum < -THRESHOLD) {
|
|
341
|
+
local_class_sum = -THRESHOLD;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, component_output[clause_component], &Xi[ta_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
state[index] = localState;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Update state of Tsetlin Automata team
|
|
352
|
+
__global__ void update_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, int *clause_output, int *class_sum, int *y, int example)
|
|
353
|
+
{
|
|
354
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
355
|
+
int stride = blockDim.x * gridDim.x;
|
|
356
|
+
|
|
357
|
+
/* Copy state to local memory for efficiency */
|
|
358
|
+
curandState localState = state[index];
|
|
359
|
+
|
|
360
|
+
for (unsigned long long clause = index; clause < CLAUSES; clause += stride) {
|
|
361
|
+
for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
362
|
+
int local_class_sum = class_sum[class_id];
|
|
363
|
+
if (local_class_sum > THRESHOLD) {
|
|
364
|
+
local_class_sum = THRESHOLD;
|
|
365
|
+
} else if (local_class_sum < -THRESHOLD) {
|
|
366
|
+
local_class_sum = -THRESHOLD;
|
|
367
|
+
}
|
|
368
|
+
update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], clause_output[clause], y[example*number_of_outputs + class_id], local_class_sum);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
state[index] = localState;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
"""
|
|
376
|
+
|
|
377
|
+
code_prepare = """
|
|
378
|
+
extern "C"
|
|
379
|
+
{
|
|
380
|
+
__global__ void prepare_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, int *class_sum)
|
|
381
|
+
{
|
|
382
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
383
|
+
int stride = blockDim.x * gridDim.x;
|
|
384
|
+
|
|
385
|
+
curandState localState = state[index];
|
|
386
|
+
|
|
387
|
+
for (unsigned long long clause = index; clause < CLAUSES; clause += stride) {
|
|
388
|
+
for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
|
|
389
|
+
#if NEGATIVE_CLAUSES == 1
|
|
390
|
+
if (tm_type == COALESCED_TM) {
|
|
391
|
+
clause_weights[class_id*CLAUSES + clause] = 1 - 2 * (curand(&localState) % 2);
|
|
392
|
+
} else {
|
|
393
|
+
clause_weights[class_id*CLAUSES + clause] = 1 - 2 * (clause % 2);
|
|
394
|
+
}
|
|
395
|
+
#else
|
|
396
|
+
clause_weights[class_id*CLAUSES + clause] = 1;
|
|
397
|
+
#endif
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
state[index] = localState;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
__global__ void prepare_hierarchy(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, int *class_sum)
|
|
405
|
+
{
|
|
406
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
407
|
+
int stride = blockDim.x * gridDim.x;
|
|
408
|
+
|
|
409
|
+
curandState localState = state[index];
|
|
410
|
+
|
|
411
|
+
// Evaluate each clause component (leaf) in separate threads
|
|
412
|
+
for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
|
|
413
|
+
// Get state of current clause component
|
|
414
|
+
unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
|
|
415
|
+
for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
|
|
416
|
+
for (int b = 0; b < STATE_BITS-1; ++b) {
|
|
417
|
+
ta_state[ta_chunk*STATE_BITS + b] = ~0;
|
|
418
|
+
}
|
|
419
|
+
ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] = 0;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
state[index] = localState;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
"""
|
|
427
|
+
|
|
428
|
+
code_encode = """
|
|
429
|
+
#include <curand_kernel.h>
|
|
430
|
+
|
|
431
|
+
extern "C"
|
|
432
|
+
{
|
|
433
|
+
__global__ void prepare_encode_hierarchy(unsigned int *X, unsigned int *encoded_X, int number_of_literal_chunks, int number_of_examples)
|
|
434
|
+
{
|
|
435
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
436
|
+
int stride = blockDim.x * gridDim.x;
|
|
437
|
+
|
|
438
|
+
for (unsigned long long i = index; i < number_of_examples * number_of_literal_chunks; i += stride) {
|
|
439
|
+
encoded_X[i] = 0;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
__global__ void encode_hierarchy(unsigned int *X, unsigned int *encoded_X, int number_of_features, int number_of_literal_chunks, int number_of_leaves, int number_of_features_per_leaf, int number_of_literal_chunks_per_leaf, int append_negated, int number_of_examples)
|
|
444
|
+
{
|
|
445
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
446
|
+
int stride = blockDim.x * gridDim.x;
|
|
447
|
+
|
|
448
|
+
unsigned int *Xi;
|
|
449
|
+
unsigned int *encoded_Xi;
|
|
450
|
+
|
|
451
|
+
for (unsigned long long i = index; i < number_of_examples; i += stride) {
|
|
452
|
+
Xi = &X[i*number_of_features];
|
|
453
|
+
encoded_Xi = &encoded_X[i*number_of_literal_chunks];
|
|
454
|
+
|
|
455
|
+
for (int j = 0; j < number_of_features / number_of_features_per_leaf; ++j) {
|
|
456
|
+
for (int k = 0; k < number_of_features_per_leaf; ++k) {
|
|
457
|
+
if (Xi[j*number_of_features_per_leaf + k] == 1) {
|
|
458
|
+
int leaf_chunk_nr = k / 32;
|
|
459
|
+
int leaf_chunk_pos = k % 32;
|
|
460
|
+
encoded_Xi[j*number_of_literal_chunks_per_leaf + leaf_chunk_nr] |= (1 << leaf_chunk_pos);
|
|
461
|
+
} else if (append_negated) {
|
|
462
|
+
int leaf_chunk_nr = (k + number_of_features_per_leaf) / 32;
|
|
463
|
+
int leaf_chunk_pos = (k + number_of_features_per_leaf) % 32;
|
|
464
|
+
encoded_Xi[j*number_of_literal_chunks_per_leaf + leaf_chunk_nr] |= (1 << leaf_chunk_pos);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
"""
|
|
472
|
+
|
|
473
|
+
code_transform = """
|
|
474
|
+
extern "C"
|
|
475
|
+
{
|
|
476
|
+
// Transform examples
|
|
477
|
+
__global__ void transform(unsigned int *global_ta_state, int *X, int *transformed_X)
|
|
478
|
+
{
|
|
479
|
+
int index = blockIdx.x * blockDim.x + threadIdx.x;
|
|
480
|
+
int stride = blockDim.x * gridDim.x;
|
|
481
|
+
|
|
482
|
+
// To be updated
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
"""
|