PyHierarchicalTsetlinMachineCUDA 0.2.8__tar.gz → 0.2.9__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.
Files changed (15) hide show
  1. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PKG-INFO +1 -1
  2. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA/kernels.py +46 -393
  3. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA/tm.py +130 -136
  4. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA.egg-info/PKG-INFO +1 -1
  5. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/README.md +1 -1
  6. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/setup.py +1 -1
  7. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/LICENSE +0 -0
  8. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA/__init__.py +0 -0
  9. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA/tools.py +0 -0
  10. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA/utils.py +0 -0
  11. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA.egg-info/SOURCES.txt +0 -0
  12. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA.egg-info/dependency_links.txt +0 -0
  13. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA.egg-info/requires.txt +0 -0
  14. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/PyHierarchicalTsetlinMachineCUDA.egg-info/top_level.txt +0 -0
  15. {PyHierarchicalTsetlinMachineCUDA-0.2.8 → PyHierarchicalTsetlinMachineCUDA-0.2.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyHierarchicalTsetlinMachineCUDA
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Hierarchical Tsetlin Machine Architecture.
5
5
  Home-page: https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/
6
6
  Author: Ole-Christoffer Granmo
@@ -114,36 +114,6 @@ code_update = """
114
114
  }
115
115
  }
116
116
 
117
- __device__ inline void update_clause_weight_old(curandState *localState, int tm_type, int number_of_outputs, int *clause_weight, int clause_output, int y, int class_sum)
118
- {
119
- int target = 1 - 2*(class_sum > y);
120
-
121
- if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
122
- return;
123
- }
124
-
125
- int sign = (*clause_weight >= 0) - (*clause_weight < 0);
126
-
127
- int absolute_prediction_error = abs(y - class_sum);
128
- if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
129
- if (target*sign > 0) {
130
- if (clause_output && abs(*clause_weight) < INT_MAX) {
131
- (*clause_weight) += sign;
132
- }
133
- } else if (target*sign < 0 && clause_output) {
134
- // Type II Feedback
135
-
136
- (*clause_weight) -= sign;
137
-
138
- #if FLIP_POLARITY == 0
139
- if (*clause_weight == 0) {
140
- *clause_weight += sign;
141
- }
142
- #endif
143
- }
144
- }
145
- }
146
-
147
117
  __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, float class_sum)
148
118
  {
149
119
  int target = 1 - 2*(class_sum > y);
@@ -189,52 +159,6 @@ code_update = """
189
159
  }
190
160
  }
191
161
 
192
- __device__ inline void update_component_hierarchy_old(curandState *localState, int number_of_outputs, int *clause_weight, unsigned int *ta_state, int component_output, int *X, int y, int class_sum)
193
- {
194
- int target = 1 - 2*(class_sum > y);
195
-
196
- if (target == -1 && curand_uniform(localState) > 1.0*Q/max(1, number_of_outputs-1)) {
197
- return;
198
- }
199
-
200
-
201
- int sign = (*clause_weight >= 0) - (*clause_weight < 0);
202
-
203
- int absolute_prediction_error = abs(y - class_sum);
204
- if (curand_uniform(localState) <= 1.0*absolute_prediction_error/(2*THRESHOLD)) {
205
- if (target*sign > 0) {
206
- // Type I Feedback
207
- for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
208
- // Generate random bit values
209
- unsigned int la_feedback = 0;
210
- for (int b = 0; b < INT_SIZE; ++b) {
211
- if (curand_uniform(localState) <= 1.0/S) {
212
- la_feedback |= (1 << b);
213
- }
214
- }
215
-
216
- if (component_output) {
217
- #if BOOST_TRUE_POSITIVE_FEEDBACK == 1
218
- inc(ta_state, ta_chunk, X[ta_chunk]);
219
- #else
220
- inc(ta_state, ta_chunk, X[ta_chunk] & (~la_feedback));
221
- #endif
222
-
223
- dec(ta_state, ta_chunk, (~X[ta_chunk]) & la_feedback);
224
- } else {
225
- dec(ta_state, ta_chunk, la_feedback);
226
- }
227
- }
228
- } else if (target*sign < 0 && component_output) {
229
- // Type II Feedback
230
-
231
- for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
232
- inc(ta_state, ta_chunk, (~X[ta_chunk]) & (~ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]));
233
- }
234
- }
235
- }
236
- }
237
-
238
162
  // Evaluate example
239
163
  __global__ void evaluate_leaves(unsigned int *global_ta_state, int *component_weights, float *global_component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_type, int *X, int example)
240
164
  {
@@ -254,22 +178,24 @@ code_update = """
254
178
  int size_feature_chunk_base = 1;
255
179
  int size_ta_chunk_base = 1;
256
180
  for (int d = 0; d < depth-1; ++d) {
257
- int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
258
- component_remainder = component_remainder / hierarchy_structure_factors[d];
181
+ int depth_d_node_index = component_remainder % hierarchy_structure_factors[d]; // Extract local index of node at depth d (the child index)
182
+ component_remainder = component_remainder / hierarchy_structure_factors[d]; // Move up the hierarchy to prepare for finding the local node index at depth d+1
259
183
 
260
- if (hierarchy_structure_type[d] != 1) {
261
- feature_chunk_base += size_feature_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
262
- size_feature_chunk_base *= hierarchy_structure_factors[d];
184
+ // Support multiple Tsetlin Automata teams operating on the same feature chunks to create alternatives.
185
+ if ((hierarchy_structure_type[d] != OR_ALTERNATIVES) && (hierarchy_structure_type[d] != AND_ALTERNATIVES)) {
186
+ feature_chunk_base += size_feature_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF; // Identify correct part of the sub-hierarchy (through flattening)
187
+ size_feature_chunk_base *= hierarchy_structure_factors[d]; // Identify how many nodes to jump to skip from one child to the next when indexing at the next depth level
263
188
  }
264
189
 
265
- if (hierarchy_structure_type[d] != 2) {
190
+ // Support reuse of the same Tsetlin Automata when doing OR to group different feature chunks
191
+ if (hierarchy_structure_type[d] != OR_GROUP) {
266
192
  ta_chunk_base += size_ta_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
267
193
  size_ta_chunk_base *= hierarchy_structure_factors[d];
268
194
  }
269
195
  }
270
196
 
271
197
  // Get state of current ta team component
272
- unsigned int *ta_state = &global_ta_state[clause*COMPONENTS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
198
+ unsigned int *ta_state = &global_ta_state[clause*TA_TEAMS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
273
199
 
274
200
  // Evaluate clause component
275
201
 
@@ -304,60 +230,6 @@ code_update = """
304
230
  }
305
231
  }
306
232
 
307
- // Evaluate example
308
- __global__ void evaluate_leaves_old(unsigned int *global_ta_state, int *component_weights, float *global_component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_type, int *X, int example)
309
- {
310
- int index = blockIdx.x * blockDim.x + threadIdx.x;
311
- int stride = blockDim.x * gridDim.x;
312
-
313
- int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
314
-
315
- // Evaluate each clause component (leaf) in separate threads
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
- int component_remainder = component;
321
- int feature_chunk_base = 0;
322
- int ta_chunk_base = 0;
323
- int size_feature_chunk_base = 1;
324
- int size_ta_chunk_base = 1;
325
- for (int d = 0; d < depth-1; ++d) {
326
- int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
327
- component_remainder = component_remainder / hierarchy_structure_factors[d];
328
-
329
- if (hierarchy_structure_type[d] != 1) {
330
- feature_chunk_base += size_feature_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
331
- size_feature_chunk_base *= hierarchy_structure_factors[d];
332
- }
333
-
334
- if (hierarchy_structure_type[d] != 2) {
335
- ta_chunk_base += size_ta_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
336
- size_ta_chunk_base *= hierarchy_structure_factors[d];
337
- }
338
- }
339
-
340
- // Get state of current ta team component
341
- unsigned int *ta_state = &global_ta_state[clause*COMPONENTS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
342
-
343
- // Evaluate clause component
344
- int component_output = 1;
345
- for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF-1; ++ta_chunk) {
346
- // Compare the TA state of the component (leaf) against the corresponding part of the feature vector
347
- if ((ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] & Xi[feature_chunk_base + ta_chunk]) != ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1]) {
348
- component_output = 0;
349
- break;
350
- }
351
- }
352
-
353
- if ((ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & Xi[feature_chunk_base + TA_CHUNKS_PER_LEAF-1] & FILTER_HIERARCHICAL) != (ta_state[(TA_CHUNKS_PER_LEAF-1)*STATE_BITS + STATE_BITS - 1] & FILTER_HIERARCHICAL)) {
354
- component_output = 0;
355
- }
356
-
357
- global_component_output[clause_component] = component_output;
358
- }
359
- }
360
-
361
233
  __global__ void evaluate_or_groups(float *child_input, float *or_group_node_output, int number_of_or_group_nodes, int number_of_or_group_addends)
362
234
  {
363
235
  int index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -410,38 +282,6 @@ code_update = """
410
282
  }
411
283
  }
412
284
 
413
- __global__ void evaluate_and_groups_old(float *child_input, float *and_group_node_output, int number_of_and_group_nodes, int number_of_and_group_factors)
414
- {
415
- int index = blockIdx.x * blockDim.x + threadIdx.x;
416
- int stride = blockDim.x * gridDim.x;
417
-
418
- // Multiply the votes from the children of each AND node
419
- for (int and_group_node = index; and_group_node < CLAUSES*number_of_and_group_nodes; and_group_node += stride) {
420
- // Multiply and factors
421
- int and_group_vote_product = 1;
422
- int max_vote_sum = 0;
423
- for (int and_factor = 0; and_factor < number_of_and_group_factors; ++and_factor) {
424
- // Aggregate votes from each child node through multiplication
425
-
426
- int previous_and_group_vote_product = and_group_vote_product;
427
- and_group_vote_product *= child_input[and_group_node*number_of_and_group_factors + and_factor];
428
-
429
- if (child_input[and_group_node*number_of_and_group_factors + and_factor] > max_vote_sum) {
430
- max_vote_sum = child_input[and_group_node*number_of_and_group_factors + and_factor];
431
- }
432
-
433
- if (and_group_vote_product < 0) {
434
- printf("AND OVERFLOW %d -> %d\\n", previous_and_group_vote_product, and_group_vote_product);
435
- and_group_vote_product = previous_and_group_vote_product;
436
- }
437
- }
438
-
439
- // Store and group product as node output
440
- and_group_node_output[and_group_node] = and_group_vote_product;
441
- //and_group_node_output[and_group_node] = max_vote_sum;
442
- }
443
- }
444
-
445
285
  __global__ void propagate_and_group_false_truth_values(float *child_input, float *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
446
286
  //__global__ void propagate_and_group_false_truth_values_log(int *child_input, int *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
447
287
  {
@@ -476,23 +316,6 @@ code_update = """
476
316
  }
477
317
  }
478
318
 
479
- __global__ void propagate_and_group_false_truth_values_old(float *child_input, float *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
480
- {
481
- int index = blockIdx.x * blockDim.x + threadIdx.x;
482
- int stride = blockDim.x * gridDim.x;
483
-
484
- // If a group node is false, all children are made false.
485
- for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
486
- if (group_node_output[group_node] == 0) {
487
- for (int and_factor = 0; and_factor < number_of_group_node_children; ++and_factor) {
488
- if (child_input[group_node*number_of_group_node_children + and_factor] > 0) {
489
- child_input[group_node*number_of_group_node_children + and_factor] = 0;
490
- }
491
- }
492
- }
493
- }
494
- }
495
-
496
319
  __global__ void propagate_or_group_false_truth_values(curandState *state, float *child_input, float *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
497
320
  {
498
321
  int index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -539,7 +362,7 @@ code_update = """
539
362
  }
540
363
  } else {
541
364
  for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
542
- if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
365
+ if (child_input[group_node*number_of_group_node_children + or_addend] > 0) { // Or pick the largest.... picking randomly when a tie
543
366
  non_zero_children[number_of_non_zero_children] = or_addend;
544
367
  number_of_non_zero_children++;
545
368
  }
@@ -566,58 +389,6 @@ code_update = """
566
389
  state[index] = localState;
567
390
  }
568
391
 
569
- __global__ void propagate_or_group_false_truth_values_old(curandState *state, float *child_input, float *group_node_output, int number_of_group_nodes, int number_of_group_node_children)
570
- {
571
- int index = blockIdx.x * blockDim.x + threadIdx.x;
572
- int stride = blockDim.x * gridDim.x;
573
-
574
- int non_zero_children[361];
575
-
576
- /* Copy state to local memory for efficiency */
577
- curandState localState = state[index];
578
-
579
- // If a group node is false, all children are made false.
580
- for (int group_node = index; group_node < CLAUSES*number_of_group_nodes; group_node += stride) {
581
- int number_of_non_zero_children = 0;
582
-
583
- if (group_node_output[group_node] == -1) {
584
- for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
585
- child_input[group_node*number_of_group_node_children + or_addend] = -1;
586
- }
587
- } else if (group_node_output[group_node] == 0) {
588
- for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
589
- if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
590
- child_input[group_node*number_of_group_node_children + or_addend] = 0;
591
- }
592
- }
593
- } else {
594
- for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
595
- if (child_input[group_node*number_of_group_node_children + or_addend] > 0) {
596
- non_zero_children[number_of_non_zero_children] = or_addend;
597
- number_of_non_zero_children++;
598
- }
599
- }
600
- }
601
-
602
- if (group_node_output[group_node] != -1) {
603
- int selected_child;
604
- if (number_of_non_zero_children > 0) {
605
- selected_child = non_zero_children[curand(&localState) % number_of_non_zero_children];
606
- } else {
607
- selected_child = curand(&localState) % number_of_group_node_children;
608
- }
609
-
610
- for (int or_addend = 0; or_addend < number_of_group_node_children; ++or_addend) {
611
- if (selected_child != or_addend) {
612
- child_input[group_node*number_of_group_node_children + or_addend] = -1;
613
- }
614
- }
615
- }
616
- }
617
-
618
- state[index] = localState;
619
- }
620
-
621
392
  __global__ void evaluate_or_alternatives(float *child_input, float *or_alternatives_node_output, int number_of_or_alternatives_nodes, int number_of_or_alternatives)
622
393
  //__global__ void evaluate_or_alternatives_log(int *child_input, int *or_alternatives_node_output, int number_of_or_alternatives_nodes, int number_of_or_alternatives)
623
394
  {
@@ -662,34 +433,6 @@ code_update = """
662
433
  }
663
434
  }
664
435
 
665
- __global__ void evaluate_or_alternatives_old(float *child_input, float *or_alternatives_node_output, int number_of_or_alternatives_nodes, int number_of_or_alternatives)
666
- {
667
- int index = blockIdx.x * blockDim.x + threadIdx.x;
668
- int stride = blockDim.x * gridDim.x;
669
-
670
- // Add up the votes from the children of each OR node
671
- for (int or_alternatives_node = index; or_alternatives_node < CLAUSES*number_of_or_alternatives_nodes; or_alternatives_node += stride) {
672
- // Sum up votes from each or alternative
673
- int or_alternatives_vote_sum = 0;
674
- for (int or_alternative = 0; or_alternative < number_of_or_alternatives; ++or_alternative) {
675
- // Aggregate same input or alternatives through summation
676
-
677
-
678
- int previous_or_alternatives_vote_sum = or_alternatives_vote_sum;
679
- or_alternatives_vote_sum += child_input[or_alternatives_node * number_of_or_alternatives + or_alternative];
680
-
681
- if (or_alternatives_vote_sum < 0) {
682
- printf("OR OVERFLOW %d -> %d\\n", previous_or_alternatives_vote_sum, or_alternatives_vote_sum);
683
- or_alternatives_vote_sum = previous_or_alternatives_vote_sum;
684
- }
685
- }
686
-
687
- // Store vote sum as node output
688
- or_alternatives_node_output[or_alternatives_node] = or_alternatives_vote_sum;
689
- }
690
- }
691
-
692
-
693
436
  __global__ void max_clause_output(int number_of_outputs, float *clause_output, float *clause_output_max)
694
437
  {
695
438
  int index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -701,19 +444,36 @@ code_update = """
701
444
  }
702
445
  }
703
446
 
704
- __global__ void evaluate_final(int number_of_outputs, float *clause_output, float *clause_output_max, int *clause_weights, float *class_sum)
447
+ __global__ void evaluate_final(int number_of_outputs, float *clause_output, int *clause_weights, float *class_sum)
705
448
  {
706
449
  int index = blockIdx.x * blockDim.x + threadIdx.x;
707
450
  int stride = blockDim.x * gridDim.x;
708
451
 
709
452
  // Add up the votes from each clause
710
453
  #if LOG_SCALE == 1
711
- if (clause_output_max[0] != NEG_INFINITY) {
712
- for (int clause = index; clause < CLAUSES; clause += stride) {
713
- int output = exp2f(clause_output[clause] - clause_output_max[0]);
714
- for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
715
- atomicAdd(&class_sum[class_id], (float) clause_weights[class_id*CLAUSES + clause] * output);
454
+ // Add up the votes from each clause
455
+ for (int class_id = index; class_id < number_of_outputs; class_id += stride) {
456
+ float clause_output_max = NEG_INFINITY;
457
+ for (int clause = 0; clause < CLAUSES; ++clause) {
458
+ if (clause_output[clause] > clause_output_max) {
459
+ clause_output_max = clause_output[clause];
460
+ }
461
+ }
462
+
463
+ if (clause_output_max != NEG_INFINITY) {
464
+ float weighted_clause_output_sum = 0;
465
+ for (int clause = 0; clause < CLAUSES; ++clause) {
466
+ weighted_clause_output_sum += clause_weights[class_id*CLAUSES + clause] * exp2f(clause_output[clause] - clause_output_max);
467
+ }
468
+
469
+ if (log2f(fabs(weighted_clause_output_sum)) + clause_output_max >= log2f(THRESHOLD)) {
470
+ float sign = (1 - 2 * (weighted_clause_output_sum < 0));
471
+ class_sum[class_id] = sign*THRESHOLD;
472
+ } else {
473
+ class_sum[class_id] = weighted_clause_output_sum * exp2f(clause_output_max);
716
474
  }
475
+ } else {
476
+ class_sum[class_id] = 0;
717
477
  }
718
478
  }
719
479
  #else
@@ -727,22 +487,6 @@ code_update = """
727
487
  #endif
728
488
  }
729
489
 
730
- __global__ void evaluate_final_old(int number_of_outputs, float *child_input, int *clause_weights, int *class_sum)
731
- {
732
- int index = blockIdx.x * blockDim.x + threadIdx.x;
733
- int stride = blockDim.x * gridDim.x;
734
-
735
- // Add up the votes from each clause
736
- for (int clause = index; clause < CLAUSES; clause += stride) {
737
- if (child_input[clause]) {
738
- for (int class_id = 0; class_id < number_of_outputs; ++class_id) {
739
- int clause_weight = clause_weights[class_id*CLAUSES + clause];
740
- atomicAdd(&class_sum[class_id], (int) clause_weight * child_input[clause]);
741
- }
742
- }
743
- }
744
- }
745
-
746
490
  __global__ void rescale_final(int number_of_outputs, float *clause_output_max, float *class_sum)
747
491
  {
748
492
  int index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -797,19 +541,19 @@ code_update = """
797
541
  int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
798
542
  component_remainder = component_remainder / hierarchy_structure_factors[d];
799
543
 
800
- if (hierarchy_structure_type[d] != 1) {
544
+ if ((hierarchy_structure_type[d] != OR_ALTERNATIVES) && (hierarchy_structure_type[d] != AND_ALTERNATIVES)) {
801
545
  feature_chunk_base += size_feature_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
802
546
  size_feature_chunk_base *= hierarchy_structure_factors[d];
803
547
  }
804
548
 
805
- if (hierarchy_structure_type[d] != 2) {
549
+ if (hierarchy_structure_type[d] != OR_GROUP) {
806
550
  ta_chunk_base += size_ta_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
807
551
  size_ta_chunk_base *= hierarchy_structure_factors[d];
808
552
  }
809
553
  }
810
554
 
811
555
  // Get state of current ta team component
812
- unsigned int *ta_state = &global_ta_state[clause*COMPONENTS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
556
+ unsigned int *ta_state = &global_ta_state[clause*TA_TEAMS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
813
557
 
814
558
  for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
815
559
  float local_class_sum = class_sum[class_id];
@@ -830,68 +574,6 @@ code_update = """
830
574
  state[index] = localState;
831
575
  }
832
576
 
833
- // Update state of Tsetlin Automata team
834
- __global__ void update_hierarchy_old(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, float *component_output, int depth, int *hierarchy_structure_factors, int *hierarchy_structure_type, int *class_sum, int *X, int *y, int example)
835
- {
836
- int index = blockIdx.x * blockDim.x + threadIdx.x;
837
- int stride = blockDim.x * gridDim.x;
838
-
839
- /* Copy state to local memory for efficiency */
840
- curandState localState = state[index];
841
-
842
- int *Xi = &X[(unsigned long long)example*LITERAL_CHUNKS];
843
-
844
- // Calculate clause output first
845
- for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
846
- if (component_output[clause_component] == -1) {
847
- continue;
848
- }
849
-
850
- int clause = clause_component / COMPONENTS;
851
- int component = clause_component % COMPONENTS;
852
-
853
- // Get state of current clause component
854
- // This one must be updated for reuse of TAs within OR group
855
-
856
- int component_remainder = component;
857
- int feature_chunk_base = 0;
858
- int ta_chunk_base = 0;
859
- int size_feature_chunk_base = 1;
860
- int size_ta_chunk_base = 1;
861
- for (int d = 0; d < depth-1; ++d) {
862
- int depth_d_node_index = component_remainder % hierarchy_structure_factors[d];
863
- component_remainder = component_remainder / hierarchy_structure_factors[d];
864
-
865
- if (hierarchy_structure_type[d] != 1) {
866
- feature_chunk_base += size_feature_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
867
- size_feature_chunk_base *= hierarchy_structure_factors[d];
868
- }
869
-
870
- if (hierarchy_structure_type[d] != 2) {
871
- ta_chunk_base += size_ta_chunk_base * depth_d_node_index * TA_CHUNKS_PER_LEAF;
872
- size_ta_chunk_base *= hierarchy_structure_factors[d];
873
- }
874
- }
875
-
876
- // Get state of current ta team component
877
- unsigned int *ta_state = &global_ta_state[clause*COMPONENTS*TA_CHUNKS_PER_LEAF*STATE_BITS + ta_chunk_base*STATE_BITS];
878
-
879
- for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
880
- int local_class_sum = class_sum[class_id];
881
- if (local_class_sum > THRESHOLD) {
882
- local_class_sum = THRESHOLD;
883
- } else if (local_class_sum < -THRESHOLD) {
884
- local_class_sum = -THRESHOLD;
885
- }
886
-
887
- update_component_hierarchy(&localState, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], ta_state, (int) component_output[clause_component], &Xi[feature_chunk_base], y[example*number_of_outputs + class_id], local_class_sum);
888
- }
889
- }
890
-
891
- state[index] = localState;
892
- }
893
-
894
-
895
577
  // Update state of Tsetlin Automata team
896
578
  __global__ void update_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, float *clause_output, float *class_sum, int *y, int example)
897
579
  {
@@ -920,37 +602,13 @@ code_update = """
920
602
 
921
603
  state[index] = localState;
922
604
  }
923
-
924
- // Update state of Tsetlin Automata team
925
- __global__ void update_weights_old(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, float *clause_output, int *class_sum, int *y, int example)
926
- {
927
- int index = blockIdx.x * blockDim.x + threadIdx.x;
928
- int stride = blockDim.x * gridDim.x;
929
-
930
- /* Copy state to local memory for efficiency */
931
- curandState localState = state[index];
932
-
933
- for (unsigned long long clause = index; clause < CLAUSES; clause += stride) {
934
- for (unsigned long long class_id = 0; class_id < number_of_outputs; ++class_id) {
935
- int local_class_sum = class_sum[class_id];
936
- if (local_class_sum > THRESHOLD) {
937
- local_class_sum = THRESHOLD;
938
- } else if (local_class_sum < -THRESHOLD) {
939
- local_class_sum = -THRESHOLD;
940
- }
941
- update_clause_weight(&localState, tm_type, number_of_outputs, &clause_weights[class_id*CLAUSES + clause], (int) clause_output[clause], y[example*number_of_outputs + class_id], local_class_sum);
942
- }
943
- }
944
-
945
- state[index] = localState;
946
- }
947
605
  }
948
606
  """
949
607
 
950
608
  code_prepare = """
951
609
  extern "C"
952
610
  {
953
- __global__ void prepare_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights, int *class_sum)
611
+ __global__ void prepare_weights(curandState *state, int tm_type, int number_of_outputs, int *clause_weights)
954
612
  {
955
613
  int index = blockIdx.x * blockDim.x + threadIdx.x;
956
614
  int stride = blockDim.x * gridDim.x;
@@ -974,17 +632,14 @@ code_prepare = """
974
632
  state[index] = localState;
975
633
  }
976
634
 
977
- __global__ void prepare_hierarchy(curandState *state, int number_of_outputs, unsigned int *global_ta_state, int *clause_weights, int *class_sum)
635
+ __global__ void prepare_hierarchy(int number_of_outputs, unsigned int *global_ta_state)
978
636
  {
979
637
  int index = blockIdx.x * blockDim.x + threadIdx.x;
980
638
  int stride = blockDim.x * gridDim.x;
981
639
 
982
- curandState localState = state[index];
983
-
984
- // Evaluate each clause component (leaf) in separate threads
985
- for (int clause_component = index; clause_component < CLAUSES*COMPONENTS; clause_component += stride) {
986
- // Get state of current clause component
987
- unsigned int *ta_state = &global_ta_state[clause_component*TA_CHUNKS_PER_LEAF*STATE_BITS];
640
+ for (int clause_team = index; clause_team < CLAUSES*TA_TEAMS; clause_team += stride) {
641
+ // Get state of current ta team
642
+ unsigned int *ta_state = &global_ta_state[clause_team*TA_CHUNKS_PER_LEAF*STATE_BITS];
988
643
  for (int ta_chunk = 0; ta_chunk < TA_CHUNKS_PER_LEAF; ++ta_chunk) {
989
644
  for (int b = 0; b < STATE_BITS-1; ++b) {
990
645
  ta_state[ta_chunk*STATE_BITS + b] = ~0;
@@ -992,8 +647,6 @@ code_prepare = """
992
647
  ta_state[ta_chunk*STATE_BITS + STATE_BITS - 1] = 0;
993
648
  }
994
649
  }
995
-
996
- state[index] = localState;
997
650
  }
998
651
  }
999
652
  """
@@ -1062,9 +715,9 @@ code_clauses = """
1062
715
  int index = blockIdx.x * blockDim.x + threadIdx.x;
1063
716
  int stride = blockDim.x * gridDim.x;
1064
717
 
1065
- for (unsigned long long i = index; i < 1LLU * CLAUSES * COMPONENTS * LITERALS_PER_LEAF; i += stride) {
1066
- unsigned long long clause = i / (COMPONENTS * LITERALS_PER_LEAF);
1067
- unsigned long long comp = (i / LITERALS_PER_LEAF) % COMPONENTS;
718
+ for (unsigned long long i = index; i < 1LLU * CLAUSES * TA_TEAMS * LITERALS_PER_LEAF; i += stride) {
719
+ unsigned long long clause = i / (TA_TEAMS * LITERALS_PER_LEAF);
720
+ unsigned long long comp = (i / LITERALS_PER_LEAF) % TA_TEAMS;
1068
721
  unsigned long long ta_idx = i % LITERALS_PER_LEAF;
1069
722
 
1070
723
  int chunk = ta_idx / 32;
@@ -1073,14 +726,14 @@ code_clauses = """
1073
726
  unsigned int state = 0;
1074
727
  for (int b = 0; b < STATE_BITS; ++b) {
1075
728
  unsigned int plane = global_ta_state[
1076
- (clause * COMPONENTS * TA_CHUNKS_PER_LEAF * STATE_BITS) +
729
+ (clause * TA_TEAMS * TA_CHUNKS_PER_LEAF * STATE_BITS) +
1077
730
  (comp * TA_CHUNKS_PER_LEAF * STATE_BITS) +
1078
731
  (chunk * STATE_BITS) + b
1079
732
  ];
1080
733
  if (plane & (1U << bit_pos)) state |= (1U << b);
1081
734
  }
1082
735
 
1083
- unpacked_states[(clause * COMPONENTS * LITERALS_PER_LEAF) + (comp * LITERALS_PER_LEAF) + ta_idx] = state;
736
+ unpacked_states[(clause * TA_TEAMS * LITERALS_PER_LEAF) + (comp * LITERALS_PER_LEAF) + ta_idx] = state;
1084
737
  }
1085
738
  }
1086
739
  """
@@ -33,15 +33,15 @@ import sys
33
33
 
34
34
  from time import time
35
35
 
36
- OR_GROUP = " ∨* "
37
- OR_ALTERNATIVES = " ∨ "
38
- AND_GROUP = " ∧ "
36
+ AND_GROUP = 0
37
+ AND_ALTERNATIVES = 1
38
+ OR_GROUP = 2
39
+ OR_ALTERNATIVES = 3
39
40
 
40
41
  VANILLA_TM = 0
41
42
  WEIGHTED_TM = 1
42
43
  COALESCED_TM = 2
43
44
 
44
-
45
45
  class CommonTsetlinMachine():
46
46
 
47
47
  def __init__(self, number_of_clauses, T, s, q=1.0, log_scale=False, hierarchy_structure=None, boost_true_positive_feedback=1, number_of_state_bits=8, append_negated=True, grid=(16*13,1,1), block=(128,1,1), seed=None):
@@ -69,11 +69,8 @@ class CommonTsetlinMachine():
69
69
  self.hierarchy_structure_factors = [0] * (self.depth - 1)
70
70
  self.hierarchy_structure_type = [0] * (self.depth - 1)
71
71
  for d in range(1, self.depth):
72
+ self.hierarchy_structure_type[d-1] = self.hierarchy_structure[d][0]
72
73
  self.hierarchy_structure_factors[d-1] = self.hierarchy_structure[d][1]
73
- if self.hierarchy_structure[d][0] == OR_ALTERNATIVES:
74
- self.hierarchy_structure_type[d-1] = 1
75
- elif self.hierarchy_structure[d][0] == OR_GROUP:
76
- self.hierarchy_structure_type[d-1] = 2
77
74
 
78
75
  # Calculates total number of features spanned by the hierarchy
79
76
  self.number_of_features_hierarchy = 1
@@ -95,7 +92,12 @@ class CommonTsetlinMachine():
95
92
  # Calculates the number of literal chunks for the full hierarchy
96
93
  self.hierarchy_size[0] = self.number_of_literal_chunks_per_leaf * self.hierarchy_size[1]
97
94
 
98
- # Calculates number of literal chunks overall for the feature vector (ignores OR alternatives)
95
+ self.number_of_ta_teams = 1
96
+ for d in range(self.depth - 1):
97
+ if self.hierarchy_structure[d][0] != OR_GROUP: # OR_GROUP reuses the same TA
98
+ self.number_of_ta_teams = self.hierarchy_structure[self.depth - d - 1][1] * self.number_of_ta_teams
99
+
100
+ # Calculates number of literal chunks overall for the feature vector (ignores OR- and AND alternatives)
99
101
  self.number_of_literal_chunks = self.number_of_literal_chunks_per_leaf
100
102
  for d in range(self.depth - 1, 0, -1):
101
103
  if (self.hierarchy_structure[d][0] == OR_GROUP or self.hierarchy_structure[d][0] == AND_GROUP):
@@ -116,6 +118,7 @@ class CommonTsetlinMachine():
116
118
  #define CLAUSES %d
117
119
  #define DEPTH %d
118
120
  #define COMPONENTS %d
121
+ #define TA_TEAMS %d
119
122
  #define LITERALS_PER_LEAF %d
120
123
  #define TA_CHUNKS_PER_LEAF %d
121
124
  #define LITERAL_CHUNKS %d
@@ -126,9 +129,14 @@ class CommonTsetlinMachine():
126
129
  #define Q %f
127
130
  #define LOG_SCALE %d
128
131
 
132
+ #define AND_GROUP %d
133
+ #define AND_ALTERNATIVES %d
134
+ #define OR_GROUP %d
135
+ #define OR_ALTERNATIVES %d
136
+
129
137
  #define NEGATIVE_CLAUSES %d
130
138
  #define FLIP_POLARITY %d
131
- """ % (self.number_of_clauses, self.depth, self.hierarchy_size[1], self.number_of_literals_per_leaf, self.number_of_literal_chunks_per_leaf, self.number_of_literal_chunks, self.number_of_state_bits, self.boost_true_positive_feedback, self.s, self.T, self.q, self.log_scale, self.negative_clauses, self.flip_polarity)
139
+ """ % (self.number_of_clauses, self.depth, self.hierarchy_size[1], self.number_of_ta_teams, self.number_of_literals_per_leaf, self.number_of_literal_chunks_per_leaf, self.number_of_literal_chunks, self.number_of_state_bits, self.boost_true_positive_feedback, self.s, self.T, self.q, self.log_scale, AND_GROUP, AND_ALTERNATIVES, OR_GROUP, OR_ALTERNATIVES, self.negative_clauses, self.flip_polarity)
132
140
 
133
141
  mod_prepare = SourceModule(parameters + kernels.code_header + kernels.code_prepare, no_extern_c=True)
134
142
  self.prepare_weights = mod_prepare.get_function("prepare_weights")
@@ -148,7 +156,7 @@ class CommonTsetlinMachine():
148
156
  self.max_clause_output.prepare("iPP")
149
157
 
150
158
  self.evaluate_final = mod_update.get_function("evaluate_final")
151
- self.evaluate_final.prepare("iPPPP")
159
+ self.evaluate_final.prepare("iPPP")
152
160
 
153
161
  self.rescale_final = mod_update.get_function("rescale_final")
154
162
  self.rescale_final.prepare("iPP")
@@ -186,11 +194,9 @@ class CommonTsetlinMachine():
186
194
 
187
195
  # Prepares for leaf encoding of the input data
188
196
  self.prepare_encode_hierarchy(X_gpu, encoded_X_hierarchy_gpu, np.int32(self.number_of_literal_chunks), np.int32(number_of_examples), grid=self.grid, block=self.block)
189
- cuda.Context.synchronize()
190
197
 
191
198
  # Encodes the input data split across the leaves
192
199
  self.encode_hierarchy(X_gpu, encoded_X_hierarchy_gpu, np.int32(self.number_of_features_hierarchy), np.int32(self.number_of_literal_chunks), np.int32(self.hierarchy_size[1]), np.int32(self.number_of_features_per_leaf), np.int32(self.number_of_literal_chunks_per_leaf), np.int32(self.append_negated), np.int32(number_of_examples), grid=self.grid, block=self.block)
193
- cuda.Context.synchronize()
194
200
 
195
201
  def allocate_gpu_memory(self):
196
202
  # GPU memory for accumulating votes, level by level
@@ -209,7 +215,7 @@ class CommonTsetlinMachine():
209
215
  cuda.memcpy_htod(self.hierarchy_structure_type_gpu, np.array(self.hierarchy_structure_type, dtype=np.int32))
210
216
 
211
217
  # GPU memory for storing Tsetlin Automata states
212
- self.ta_state_hierarchy_gpu = cuda.mem_alloc(self.number_of_clauses*self.hierarchy_size[0]*self.number_of_state_bits*4)
218
+ self.ta_state_hierarchy_gpu = cuda.mem_alloc(self.number_of_clauses*self.number_of_ta_teams*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits*4)
213
219
  self.clause_weights_gpu = cuda.mem_alloc(self.number_of_outputs*self.number_of_clauses*4)
214
220
  self.component_weights_gpu = cuda.mem_alloc(self.number_of_clauses*self.hierarchy_size[1]*4) # Only positive weights...
215
221
  self.class_sum_gpu = cuda.mem_alloc(self.number_of_outputs*4)
@@ -218,16 +224,16 @@ class CommonTsetlinMachine():
218
224
  self.clause_output_max = np.ascontiguousarray(np.empty(1)).astype(np.float32)
219
225
 
220
226
  def ta_action(self, clause, leaf, ta):
221
- ta_state_hierarchy = np.empty(self.number_of_clauses*self.hierarchy_size[1]*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
227
+ ta_state_hierarchy = np.empty(self.number_of_clauses*self.number_of_ta_teams*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
222
228
  cuda.memcpy_dtoh(ta_state_hierarchy, self.ta_state_hierarchy_gpu)
223
- ta_state_hierarchy = ta_state_hierarchy.reshape((self.number_of_clauses, self.hierarchy_size[1], self.number_of_literal_chunks_per_leaf, self.number_of_state_bits))
229
+ ta_state_hierarchy = ta_state_hierarchy.reshape((self.number_of_clauses, self.number_of_ta_teams, self.number_of_literal_chunks_per_leaf, self.number_of_state_bits))
224
230
 
225
231
  return (ta_state_hierarchy[clause, leaf, ta // 32, self.number_of_state_bits-1] & (1 << (ta % 32))) > 0
226
232
 
227
233
  def ta_state(self, clause, leaf, ta):
228
- ta_state_hierarchy = np.empty(self.number_of_clauses*self.hierarchy_size[1]*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
234
+ ta_state_hierarchy = np.empty(self.number_of_clauses*self.number_of_ta_teams*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
229
235
  cuda.memcpy_dtoh(ta_state_hierarchy, self.ta_state_hierarchy_gpu)
230
- ta_state_hierarchy = ta_state_hierarchy.reshape((self.number_of_clauses, self.hierarchy_size[1], self.number_of_literal_chunks_per_leaf, self.number_of_state_bits))
236
+ ta_state_hierarchy = ta_state_hierarchy.reshape((self.number_of_clauses, self.number_of_ta_teams, self.number_of_literal_chunks_per_leaf, self.number_of_state_bits))
231
237
 
232
238
  state = 0
233
239
  for b in range(self.number_of_state_bits):
@@ -238,7 +244,7 @@ class CommonTsetlinMachine():
238
244
 
239
245
  def get_state(self):
240
246
  # To be updated
241
- ta_state_hierarchy = np.empty(self.number_of_clauses*self.hierarchy_size[1]*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
247
+ ta_state_hierarchy = np.empty(self.number_of_clauses*self.number_of_ta_teams*self.number_of_literal_chunks_per_leaf*self.number_of_state_bits, dtype=np.uint32)
242
248
  cuda.memcpy_dtoh(self.ta_state_hierarchy, self.ta_state_hierarchy_gpu)
243
249
  clause_weights = np.empty(self.number_of_outputs*self.number_of_clauses).astype(np.int32)
244
250
  cuda.memcpy_dtoh(self.clause_weights, self.clause_weights_gpu)
@@ -255,7 +261,7 @@ class CommonTsetlinMachine():
255
261
  self.min_y = state[8]
256
262
  self.max_y = state[9]
257
263
 
258
- self.ta_state_hierarchy_gpu = cuda.mem_alloc(self.number_of_clauses*self.hierarchy_size[0]*self.number_of_state_bits*4)
264
+ self.ta_state_hierarchy_gpu = cuda.mem_alloc(self.number_of_clauses*self.number_of_ta_teams*self.number_of_state_bits*4)
259
265
  self.clause_weights_gpu = cuda.mem_alloc(self.number_of_outputs*self.number_of_clauses*4)
260
266
  cuda.memcpy_htod(self.ta_state_hierarchy_gpu, state[0])
261
267
  cuda.memcpy_htod(self.clause_weights_gpu, state[1])
@@ -265,15 +271,13 @@ class CommonTsetlinMachine():
265
271
  None # To be updated
266
272
 
267
273
  def initialize_weights_and_ta_states(self):
268
- self.prepare_weights(self.cuda_rng.state, np.int32(self.tm_type), np.int32(self.number_of_outputs), self.clause_weights_gpu, self.class_sum_gpu, grid=self.grid, block=self.block)
269
- cuda.Context.synchronize()
274
+ self.prepare_weights(self.cuda_rng.state, np.int32(self.tm_type), np.int32(self.number_of_outputs), self.clause_weights_gpu, grid=self.grid, block=self.block)
270
275
 
271
- self.prepare_hierarchy(self.cuda_rng.state, np.int32(self.number_of_outputs), self.ta_state_hierarchy_gpu, self.clause_weights_gpu, self.class_sum_gpu, grid=self.grid, block=self.block)
272
- cuda.Context.synchronize()
276
+ self.prepare_hierarchy(np.int32(self.number_of_outputs), self.ta_state_hierarchy_gpu, grid=self.grid, block=self.block)
273
277
 
274
278
  def evaluate_hierarchy(self, encoded_X_hierarchy, e):
275
279
  # Initializes class sums to zero
276
- class_sum = np.ascontiguousarray(np.zeros(self.number_of_outputs)).astype(np.int32)
280
+ class_sum = np.zeros(self.number_of_outputs, dtype=np.float32)
277
281
  cuda.memcpy_htod(self.class_sum_gpu, class_sum)
278
282
 
279
283
  # Evaluates all the hierarchy leaves in parallel
@@ -289,11 +293,10 @@ class CommonTsetlinMachine():
289
293
  encoded_X_hierarchy,
290
294
  np.int32(e)
291
295
  )
292
- cuda.Context.synchronize()
293
296
 
294
297
  # Propagates votes bottom-up in the hierarchy, starting from the clause components (leaves)
295
298
  for d in range(1, self.depth):
296
- if (self.hierarchy_structure[d][0] == AND_GROUP):
299
+ if (self.hierarchy_structure[d][0] == AND_GROUP or self.hierarchy_structure[d][0] == AND_ALTERNATIVES):
297
300
  self.evaluate_and_groups.prepared_call(
298
301
  self.grid,
299
302
  self.block,
@@ -302,7 +305,6 @@ class CommonTsetlinMachine():
302
305
  self.hierarchy_size[d + 1],
303
306
  self.hierarchy_structure[d][1]
304
307
  )
305
- cuda.Context.synchronize()
306
308
  elif self.hierarchy_structure[d][0] == OR_GROUP:
307
309
  self.evaluate_or_groups.prepared_call(
308
310
  self.grid,
@@ -312,7 +314,6 @@ class CommonTsetlinMachine():
312
314
  self.hierarchy_size[d + 1],
313
315
  self.hierarchy_structure[d][1]
314
316
  )
315
- cuda.Context.synchronize()
316
317
  elif self.hierarchy_structure[d][0] == OR_ALTERNATIVES:
317
318
  self.evaluate_or_alternatives.prepared_call(
318
319
  self.grid,
@@ -322,23 +323,20 @@ class CommonTsetlinMachine():
322
323
  self.hierarchy_size[d + 1],
323
324
  self.hierarchy_structure[d][1]
324
325
  )
325
- cuda.Context.synchronize()
326
326
  else:
327
- printf("Unknown node type!")
328
- sys.exit()
327
+ raise ValueError("Unknown Node Type!")
329
328
 
330
329
  self.clause_output_max[:] = np.finfo(np.float32).min
331
330
  cuda.memcpy_htod(self.clause_output_max_gpu, self.clause_output_max)
332
331
 
333
- if self.log_scale:
334
- self.max_clause_output.prepared_call(
335
- self.grid,
336
- self.block,
337
- np.int32(self.number_of_outputs),
338
- self.hierarchy_votes[self.depth-1],
339
- self.clause_output_max_gpu
340
- )
341
- cuda.Context.synchronize()
332
+ # if self.log_scale:
333
+ # self.max_clause_output.prepared_call(
334
+ # self.grid,
335
+ # self.block,
336
+ # np.int32(self.number_of_outputs),
337
+ # self.hierarchy_votes[self.depth-1],
338
+ # self.clause_output_max_gpu
339
+ # )
342
340
 
343
341
  # Adds up the votes from each clause (hierarchy root)
344
342
  self.evaluate_final.prepared_call(
@@ -346,23 +344,20 @@ class CommonTsetlinMachine():
346
344
  self.block,
347
345
  np.int32(self.number_of_outputs),
348
346
  self.hierarchy_votes[self.depth-1],
349
- self.clause_output_max_gpu,
350
347
  self.clause_weights_gpu,
351
348
  self.class_sum_gpu
352
349
  )
353
- cuda.Context.synchronize()
354
350
 
355
- if self.log_scale:
356
- self.rescale_final.prepared_call(
357
- self.grid,
358
- self.block,
359
- np.int32(self.number_of_outputs),
360
- self.clause_output_max_gpu,
361
- self.class_sum_gpu
362
- )
363
- cuda.Context.synchronize()
351
+ # if self.log_scale:
352
+ # self.rescale_final.prepared_call(
353
+ # self.grid,
354
+ # self.block,
355
+ # np.int32(self.number_of_outputs),
356
+ # self.clause_output_max_gpu,
357
+ # self.class_sum_gpu
358
+ # )
364
359
 
365
- def _fit(self, X, encoded_Y, epochs=100, incremental=False):
360
+ def _fit(self, X, encoded_Y):
366
361
  if self.number_of_features_hierarchy != X.shape[1]:
367
362
  print("The number of features spanned by hierarchy does not align with the input data.")
368
363
  sys.exit(-1)
@@ -376,10 +371,7 @@ class CommonTsetlinMachine():
376
371
  self.initialize_weights_and_ta_states()
377
372
 
378
373
  self.first = False
379
- elif not incremental:
380
- # Re-initializes weights and Tsetlin automata states if training is not incremental
381
- self.initialize_weights_and_ta_states()
382
-
374
+
383
375
  # Allocates GPU memory for training data
384
376
  encoded_X_hierarchy_training_gpu = cuda.mem_alloc(int(number_of_examples * self.number_of_literal_chunks * 4))
385
377
  Y_gpu = cuda.mem_alloc(encoded_Y.nbytes)
@@ -387,69 +379,64 @@ class CommonTsetlinMachine():
387
379
  self.encode_X(X, encoded_X_hierarchy_training_gpu)
388
380
  cuda.memcpy_htod(Y_gpu, encoded_Y)
389
381
 
390
- for epoch in range(epochs):
391
- for e in range(number_of_examples):
392
- self.evaluate_hierarchy(encoded_X_hierarchy_training_gpu, e)
393
-
394
- # Propagates the root value and any intermittent node values back to the leaves.
395
- # The purpose is to determine which leaves only has True nodes on the path from leaf to root.
396
- for d in range(self.depth-1, 0, -1):
397
- if self.hierarchy_structure[d][0] != OR_GROUP:
398
- self.propagate_and_group_false_truth_values.prepared_call(
399
- self.grid,
400
- self.block,
401
- self.hierarchy_votes[d-1],
402
- self.hierarchy_votes[d],
403
- self.hierarchy_size[d + 1],
404
- self.hierarchy_structure[d][1]
405
- )
406
- cuda.Context.synchronize()
407
- else:
408
- self.propagate_or_group_false_truth_values.prepared_call(
409
- self.grid,
410
- self.block,
411
- self.cuda_rng.state,
412
- self.hierarchy_votes[d-1],
413
- self.hierarchy_votes[d],
414
- self.hierarchy_size[d + 1],
415
- self.hierarchy_structure[d][1]
416
- )
417
- cuda.Context.synchronize()
418
-
419
- # Updates the clause components (leaves) based on the propagated truth values
420
- self.update_hierarchy.prepared_call(
382
+ for e in range(number_of_examples):
383
+ self.evaluate_hierarchy(encoded_X_hierarchy_training_gpu, e)
384
+
385
+ # Propagates the root value and any intermittent node values back to the leaves.
386
+ # The purpose is to determine which leaves only has True nodes on the path from leaf to root.
387
+ for d in range(self.depth-1, 0, -1):
388
+ if self.hierarchy_structure[d][0] != OR_GROUP:
389
+ self.propagate_and_group_false_truth_values.prepared_call(
390
+ self.grid,
391
+ self.block,
392
+ self.hierarchy_votes[d-1],
393
+ self.hierarchy_votes[d],
394
+ self.hierarchy_size[d + 1],
395
+ self.hierarchy_structure[d][1]
396
+ )
397
+ else:
398
+ self.propagate_or_group_false_truth_values.prepared_call(
399
+ self.grid,
400
+ self.block,
401
+ self.cuda_rng.state,
402
+ self.hierarchy_votes[d-1],
403
+ self.hierarchy_votes[d],
404
+ self.hierarchy_size[d + 1],
405
+ self.hierarchy_structure[d][1]
406
+ )
407
+
408
+ # Updates the clause components (leaves) based on the propagated truth values
409
+ self.update_hierarchy.prepared_call(
410
+ self.grid,
411
+ self.block,
412
+ self.cuda_rng.state,
413
+ np.int32(self.number_of_outputs),
414
+ self.ta_state_hierarchy_gpu,
415
+ self.clause_weights_gpu,
416
+ self.hierarchy_votes[0],
417
+ self.depth,
418
+ self.hierarchy_structure_factors_gpu,
419
+ self.hierarchy_structure_type_gpu,
420
+ self.class_sum_gpu,
421
+ encoded_X_hierarchy_training_gpu,
422
+ Y_gpu,
423
+ np.int32(e)
424
+ )
425
+
426
+ # Updates the clause weights
427
+ if (self.tm_type in [WEIGHTED_TM, COALESCED_TM]):
428
+ self.update_weights.prepared_call(
421
429
  self.grid,
422
430
  self.block,
423
431
  self.cuda_rng.state,
432
+ np.int32(self.tm_type),
424
433
  np.int32(self.number_of_outputs),
425
- self.ta_state_hierarchy_gpu,
426
434
  self.clause_weights_gpu,
427
- self.hierarchy_votes[0],
428
- self.depth,
429
- self.hierarchy_structure_factors_gpu,
430
- self.hierarchy_structure_type_gpu,
435
+ self.hierarchy_votes[self.depth-1],
431
436
  self.class_sum_gpu,
432
- encoded_X_hierarchy_training_gpu,
433
437
  Y_gpu,
434
438
  np.int32(e)
435
439
  )
436
- cuda.Context.synchronize()
437
-
438
- # Updates the clause weights
439
- if (self.tm_type in [WEIGHTED_TM, COALESCED_TM]):
440
- self.update_weights.prepared_call(
441
- self.grid,
442
- self.block,
443
- self.cuda_rng.state,
444
- np.int32(self.tm_type),
445
- np.int32(self.number_of_outputs),
446
- self.clause_weights_gpu,
447
- self.hierarchy_votes[self.depth-1],
448
- self.class_sum_gpu,
449
- Y_gpu,
450
- np.int32(e)
451
- )
452
- cuda.Context.synchronize()
453
440
  return
454
441
 
455
442
  def _score(self, X):
@@ -543,8 +530,8 @@ class CommonTsetlinMachine():
543
530
  encoded_X_hierarchy_test_gpu = gpuarray.empty((number_of_examples, self.number_of_literal_chunks), dtype=np.uint32)
544
531
  self.encode_X(X, encoded_X_hierarchy_test_gpu.gpudata)
545
532
 
546
- class_sum = np.ascontiguousarray(np.zeros((self.number_of_outputs, number_of_examples))).astype(np.int32)
547
- class_sum_example = np.ascontiguousarray(np.zeros(self.number_of_outputs)).astype(np.int32)
533
+ class_sum = np.zeros((self.number_of_outputs, number_of_examples), dtype=np.float32)
534
+ class_sum_example = np.zeros(self.number_of_outputs, dtype=np.float32)
548
535
  hierarchy_votes = []
549
536
  for e in range(number_of_examples):
550
537
  self.evaluate_hierarchy(encoded_X_hierarchy_test_gpu.gpudata, e)
@@ -554,7 +541,7 @@ class CommonTsetlinMachine():
554
541
 
555
542
  hierarchy_votes_example = []
556
543
  for d in range(self.depth):
557
- temp_arr = np.empty(self.number_of_clauses*int(self.hierarchy_size[d+1]), dtype=np.int32)
544
+ temp_arr = np.zeros(self.number_of_clauses*int(self.hierarchy_size[d+1]), dtype=np.float32)
558
545
  cuda.memcpy_dtoh(temp_arr, self.hierarchy_votes[d])
559
546
  hierarchy_votes_example.append(temp_arr.reshape((self.number_of_clauses, int(self.hierarchy_size[d+1]))))
560
547
 
@@ -581,7 +568,7 @@ class CommonTsetlinMachine():
581
568
  depth_d_node_index = component_remainder % self.hierarchy_structure[d][1]
582
569
  component_remainder = component_remainder // self.hierarchy_structure[d][1]
583
570
 
584
- if self.hierarchy_structure[d][0] != OR_ALTERNATIVES:
571
+ if (self.hierarchy_structure[d][0] != OR_ALTERNATIVES) and (self.hierarchy_structure[d][0] != AND_ALTERNATIVES):
585
572
  feature_base += size * depth_d_node_index
586
573
  size *= self.hierarchy_structure[d][1];
587
574
 
@@ -591,7 +578,10 @@ class CommonTsetlinMachine():
591
578
  right.append(")")
592
579
  left.insert(0, "(")
593
580
  elif previous_index[d-1] != depth_d_node_index:
594
- inside.append(self.hierarchy_structure[d][0])
581
+ if self.hierarchy_structure[d][0] in [AND_GROUP, AND_ALTERNATIVES]:
582
+ inside.append(" ∧ ")
583
+ elif self.hierarchy_structure[d][0] in [OR_GROUP, OR_ALTERNATIVES]:
584
+ inside.append(" ∨ ")
595
585
 
596
586
  previous_index[d-1] = depth_d_node_index
597
587
 
@@ -607,7 +597,7 @@ class CommonTsetlinMachine():
607
597
  l = []
608
598
  for k in range(self.number_of_literals_per_leaf):
609
599
  if self.ta_action(i, j, k):
610
- if k < self.number_of_literals_per_leaf // 2:
600
+ if (not self.append_negated) or k < self.number_of_literals_per_leaf // 2:
611
601
  if print_ta_state:
612
602
  l.append("x%d(%d)" % (feature_base + k, self.ta_state(i, j, k)))
613
603
  else:
@@ -672,7 +662,7 @@ class MultiOutputTsetlinMachine(CommonTsetlinMachine):
672
662
  self.negative_clauses = 1
673
663
  super().__init__(number_of_clauses, T, s, q=q, log_scale=log_scale, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
674
664
 
675
- def fit(self, X, Y, epochs=100, incremental=False):
665
+ def fit(self, X, Y):
676
666
  X = X.reshape(X.shape[0], X.shape[1], 1)
677
667
 
678
668
  self.number_of_outputs = Y.shape[1]
@@ -682,7 +672,7 @@ class MultiOutputTsetlinMachine(CommonTsetlinMachine):
682
672
  self.min_y = None
683
673
 
684
674
  encoded_Y = np.where(Y == 1, self.T, -self.T).astype(np.int32)
685
- self._fit(X, encoded_Y, epochs = epochs, incremental = incremental)
675
+ self._fit(X, encoded_Y)
686
676
 
687
677
  return
688
678
 
@@ -701,7 +691,7 @@ class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
701
691
 
702
692
  super().__init__(number_of_clauses, T, s, q=q, log_scale=log_scale, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
703
693
 
704
- def fit(self, X, Y, epochs=100, incremental=False):
694
+ def fit(self, X, Y):
705
695
  X = X.reshape(X.shape[0], X.shape[1], 1)
706
696
 
707
697
  self.number_of_outputs = int(np.max(Y) + 1)
@@ -714,7 +704,7 @@ class MultiClassCoalescedTsetlinMachine(CommonTsetlinMachine):
714
704
  for i in range(self.number_of_outputs):
715
705
  encoded_Y[:,i] = np.where(Y == i, self.T, -self.T)
716
706
 
717
- self._fit(X, encoded_Y, epochs = epochs, incremental = incremental)
707
+ self._fit(X, encoded_Y)
718
708
 
719
709
  return
720
710
 
@@ -743,7 +733,7 @@ class MultiClassTsetlinMachine:
743
733
 
744
734
  self.configured = False
745
735
 
746
- def fit(self, X, Y, epochs=100, incremental=False):
736
+ def fit(self, X, Y):
747
737
  self.number_of_outputs = int(np.max(Y) + 1)
748
738
 
749
739
  if not self.configured:
@@ -755,19 +745,18 @@ class MultiClassTsetlinMachine:
755
745
 
756
746
  encoded_Y = np.empty(Y.shape[0], dtype = np.int32)
757
747
 
758
- for epoch in range(epochs):
759
- for i in range(self.number_of_outputs):
760
- target_X = X[Y==i]
748
+ for i in range(self.number_of_outputs):
749
+ target_X = X[Y==i]
761
750
 
762
- not_target_X = X[Y!=i]
763
- not_target_index = np.random.rand(not_target_X.shape[0]) <= 1.0/(self.number_of_outputs - 1)
751
+ not_target_X = X[Y!=i]
752
+ not_target_index = np.random.rand(not_target_X.shape[0]) <= 1.0/(self.number_of_outputs - 1)
764
753
 
765
- balanced_X = np.vstack((target_X, not_target_X[not_target_index,:]))
766
- balanced_Y = np.hstack((np.ones(target_X.shape[0]), np.zeros(not_target_X.shape[0])))
767
- index = np.arange(balanced_X.shape[0])
768
- np.random.shuffle(index)
754
+ balanced_X = np.vstack((target_X, not_target_X[not_target_index,:]))
755
+ balanced_Y = np.hstack((np.ones(target_X.shape[0]), np.zeros(not_target_X.shape[0])))
756
+ index = np.arange(balanced_X.shape[0])
757
+ np.random.shuffle(index)
769
758
 
770
- self.tms[i].fit(balanced_X[index], balanced_Y[index], epochs=1, incremental=incremental)
759
+ self.tms[i].fit(balanced_X[index], balanced_Y[index])
771
760
  return
772
761
 
773
762
  def score(self, X):
@@ -799,6 +788,11 @@ class MultiClassTsetlinMachine:
799
788
  },
800
789
  }
801
790
 
791
+ def print_hierarchy(self, print_ta_state=False):
792
+ for i in range(self.number_of_outputs):
793
+ print("CLASS %d\n", i)
794
+ self.tms[i].print_hierarchy(print_ta_state = print_ta_state)
795
+
802
796
  def load(self, state_dict: dict):
803
797
  self.number_of_outputs = state_dict['number_of_outputs']
804
798
 
@@ -822,7 +816,7 @@ class TsetlinMachine(CommonTsetlinMachine):
822
816
 
823
817
  super().__init__(number_of_clauses, T, s, q=q, log_scale=log_scale, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
824
818
 
825
- def fit(self, X, Y, epochs=100, incremental=False):
819
+ def fit(self, X, Y):
826
820
  X = X.reshape(X.shape[0], X.shape[1], 1)
827
821
 
828
822
  self.number_of_outputs = 1
@@ -832,7 +826,7 @@ class TsetlinMachine(CommonTsetlinMachine):
832
826
 
833
827
  encoded_Y = np.where(Y == 1, self.T, -self.T).astype(np.int32)
834
828
 
835
- self._fit(X, encoded_Y, epochs = epochs, incremental = incremental)
829
+ self._fit(X, encoded_Y)
836
830
 
837
831
  return
838
832
 
@@ -850,7 +844,7 @@ class RegressionTsetlinMachine(CommonTsetlinMachine):
850
844
 
851
845
  super().__init__(number_of_clauses, T, s, log_scale=log_scale, hierarchy_structure=hierarchy_structure, boost_true_positive_feedback=boost_true_positive_feedback, number_of_state_bits=number_of_state_bits, append_negated=append_negated, grid=grid, block=block, seed=seed)
852
846
 
853
- def fit(self, X, Y, epochs=100, incremental=False):
847
+ def fit(self, X, Y):
854
848
  X = X.reshape(X.shape[0], X.shape[1], 1)
855
849
 
856
850
  self.number_of_outputs = 1
@@ -861,7 +855,7 @@ class RegressionTsetlinMachine(CommonTsetlinMachine):
861
855
 
862
856
  encoded_Y = ((Y - self.min_y)/(self.max_y - self.min_y)*self.T).astype(np.int32)
863
857
 
864
- self._fit(X, encoded_Y, epochs = epochs, incremental = incremental)
858
+ self._fit(X, encoded_Y)
865
859
 
866
860
  return
867
861
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyHierarchicalTsetlinMachineCUDA
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Hierarchical Tsetlin Machine Architecture.
5
5
  Home-page: https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/
6
6
  Author: Ole-Christoffer Granmo
@@ -11,7 +11,7 @@ or
11
11
  git clone git@github.com:cair/PyHierarchicalTsetlinMachineCUDA.git
12
12
  cd PyHierarchicalTsetlinMachineCUDA
13
13
  python ./setup.py sdist
14
- pip install dist/PyHierarchicalTsetlinMachineCUDA-0.2.6.tar.gz
14
+ pip install dist/PyHierarchicalTsetlinMachineCUDA-0.2.8.tar.gz
15
15
  ```
16
16
 
17
17
  ## Examples
@@ -2,7 +2,7 @@ from setuptools import *
2
2
 
3
3
  setup(
4
4
  name='PyHierarchicalTsetlinMachineCUDA',
5
- version='0.2.8',
5
+ version='0.2.9',
6
6
  author='Ole-Christoffer Granmo',
7
7
  author_email='ole.granmo@uia.no',
8
8
  url='https://github.com/cair/PyHierarchicalTsetlinMachineCUDA/',