def SgdLR(data, label, theta, lut): label_local = hcl.unpack(label, name="label_local") theta_local = hcl.unpack(theta, name="theta_local") data_local = hcl.unpack(data, name="data_local") FTYPE = theta_local.dtype def Sigmoid(exponent): ret = hcl.scalar(0.0, "sigmoid", FTYPE) with hcl.if_(exponent > hcl.cast(FTYPE, 4.0)): ret[0] = 1.0 with hcl.elif_(exponent < hcl.cast(FTYPE, -4.0)): ret[0] = 0.0 with hcl.else_(): with hcl.if_(exponent < hcl.cast(FTYPE, 0.0)): num = hcl.scalar(0, dtype=hcl.UFixed(18, 8)) num[0][18:0] = exponent[29:11] num[0] = ~(num[0] << 8) + 1 index = 2047.0 - num[0] ret[0] = lut[hcl.cast(hcl.Int(32), index)] with hcl.else_(): index = exponent[21:11] ret[0] = lut[hcl.cast(hcl.Int(32), index)] return ret[0] with hcl.stage("M"): with hcl.for_(0, NUM_TRAINING) as train_id: training_instance = hcl.compute( (NUM_FEATURES, ), lambda x: data_local[train_id * NUM_FEATURES + x], "training_instance", data_local.dtype) # Main Computation k = hcl.reduce_axis(0, NUM_FEATURES, "k") dot = hcl.compute( (1, ), lambda x: hcl.sum(theta_local[k] * training_instance[k], axis=k, dtype=FTYPE), "dot", dtype=FTYPE) gradient = hcl.compute((NUM_FEATURES, ), lambda x: (Sigmoid(dot[0]) - label_local[ train_id]) * training_instance[x], "gradient", dtype=FTYPE) update = hcl.update( theta_local, lambda x: theta_local[x] - 2565.0 * gradient[x], name="update") theta_pack = hcl.pack(theta_local, name="theta_pack", dtype=theta.dtype) stream_out = hcl.update(theta, lambda x: theta_pack[x], name="stream_out") return stream_out
def unpack(A): return hcl.unpack(A, factor=4, name="B")
def unpack(A, B): C = hcl.unpack(A, name="C", dtype=B.dtype) hcl.update(B, lambda x: C[x])
def pack_unpack(A): C = hcl.pack(A, factor=4) return hcl.unpack(C, factor=4)
def kernel(pack_train, trainLabels, pack_test, testLabels, rdv3, epoch): def learn(k, hdTrainData, prototype, prototypeCounter): #Find samples that have the label k match = hcl.compute( hdTrainData.shape, lambda x, y: hcl.select(trainLabels[x] == k, hdTrainData[x][y], 0), "match") #Record the number of these samples with hcl.for_(0, hdTrainData.shape[0]) as a: with hcl.if_(trainLabels[a] == k): max[k] += 1 #Do hdc sum on these samples' hdv r = hcl.reduce_axis(0, hdTrainData.shape[0], 'r') result = hcl.compute((hdTrainData.shape[1], ), lambda y: hcl.sum(match[r][y], axis=r), "result") #Do the binary voting sum1 = hcl.compute((hdTrainData.shape[1], ), lambda x: 0, "sum1") with hcl.if_(max[k] % 2 == 0): hcl.update( sum1, lambda x: hcl.select( result[x] + rdv3[k][x] - max[k] / 2 > 0, 1, 0)) with hcl.else_(): hcl.update(sum1, lambda x: hcl.select(result[x] - max[k] / 2 > 0, 1, 0)) #Push the binary sum to prototype and the original sum to prototypeCounter with hcl.for_(0, hdTrainData.shape[1]) as t: prototype[k][t] = sum1[t] prototypeCounter[k][t] = result[t] def test_hdc_accu(proto, hyper_dataset, labels, type): ###data preparation distance1 = hcl.compute((hyper_dataset.shape[1], ), lambda x: 0, 'distance1') hamming_dist1 = hcl.compute((numClasses, ), lambda x: 0, "hamming_dist1") m1 = hcl.reduce_axis(0, hyper_dataset.shape[1], "m1") correct1 = hcl.scalar(0, 'correct1') ### with hcl.for_(0, hyper_dataset.shape[0]) as i: with hcl.for_(0, numClasses) as n: #Do hdc multiplication(XOR) on sample[i]'s hdv and prototype[n]'s hdv (elementwise on the high-bit data) hcl.update(distance1, lambda x: hyper_dataset[i][x] ^ proto[n][x]) #Calculate the hamming distance of the two vectors by adding 1s hamming_dist1[n] = hcl.sum(distance1[m1], axis=m1) #Find the one having the least hamming distance and choose it's label as the predicted label pred1 = hcl.scalar(0, 'pred1') with hcl.for_(0, hamming_dist1.shape[0]) as j: with hcl.if_(hamming_dist1[j] < hamming_dist1[pred1]): pred1.v = j with hcl.if_(pred1.v == labels[i]): correct1.v += 1 #Print the accuracy all1 = hcl.scalar(hyper_dataset.shape[0], "all1", dtype=hcl.Float(32)) accuracy1 = hcl.compute((1, ), lambda x: correct1.v / all1.v * 100, "accuracy1", dtype=hcl.Float(32)) with hcl.if_(type == 1): hcl.print((correct1, hyper_dataset.shape[0], accuracy1[0]), "Training accu: %d/%d (%.2f%%)\n") with hcl.else_(): hcl.print((correct1, hyper_dataset.shape[0], accuracy1[0]), "Testing accu: %d/%d (%.2f%%)\n") def update(l, prototype, prototypeCounter, max): hcl.print((l + 1), "%d:Use hard examples to update the prototype counters.\n") ###data preparation distance = hcl.compute((hdTrainData.shape[1], ), lambda x: 0, 'distance') hamming_dist = hcl.compute((numClasses, ), lambda x: 0, "hamming_dist") m = hcl.reduce_axis(0, hdTrainData.shape[1], "m") ### with hcl.for_(0, hdTrainData.shape[0]) as i: with hcl.for_(0, numClasses) as n: #Do hdc multiplication(XOR) on sample[i]'s hdv and prototype[n]'s hdv (elementwise on the high-bit data) hcl.update(distance, lambda x: hdTrainData[i][x] ^ prototype[n][x]) #Calculate the hamming distance of the two vectors by adding 1s hamming_dist[n] = hcl.sum(distance[m], axis=m) #Find the one having the least hamming distance and choose it's label as the predicted label pred = hcl.scalar(0, 'pred') with hcl.for_(0, hamming_dist.shape[0]) as j: with hcl.if_(hamming_dist[j] < hamming_dist[pred]): pred.v = j #Adjust the proto vectors by adding the sample vector on its label proto hdv and substrct it on its predicted proto hdv with hcl.if_(pred.v != trainLabels[i]): max[trainLabels[i]] += 1 max[pred] -= 1 with hcl.for_(0, hdTrainData.shape[1]) as m: prototypeCounter[trainLabels[i]][m] += hdTrainData[i][m] prototypeCounter[pred][m] -= hdTrainData[i][m] with hcl.if_(max[trainLabels[i]] % 2 == 0): with hcl.if_(prototypeCounter[trainLabels[i]][m] - max[trainLabels[i]] / 2 == 0): prototype[trainLabels[i]][m] &= 1 with hcl.else_(): prototype[trainLabels[i]][m] = hcl.select( prototypeCounter[trainLabels[i]][m] - max[trainLabels[i]] / 2 > 0, 1, 0) with hcl.if_(max[pred] % 2 == 0): with hcl.if_(prototypeCounter[pred][m] - max[pred] / 2 == 0): prototype[pred][m] &= 1 with hcl.else_(): prototype[pred][m] = hcl.select( prototypeCounter[pred][m] - max[pred] / 2 > 0, 1, 0) #print the accuracy hcl.mutate( (1, ), lambda x: test_hdc_accu(prototype, hdTrainData, trainLabels, 1), 'training_update') hcl.mutate( (1, ), lambda x: test_hdc_accu(prototype, hdTestData, testLabels, 2), 'testing_update') ###unpack hdTrainData = hcl.unpack(pack_train, axis=1, dtype=hcl.UInt(1), name="hdTrainData") hdTestData = hcl.unpack(pack_test, axis=1, dtype=hcl.UInt(1), name="hdTestData") ###learn hcl.print((), "Learning the prototype HDVs.\n") prototype = hcl.compute( (numClasses, hdTrainData.shape[1]), lambda x, y: 0, "prototype", ) prototypeCounter = hcl.compute( (numClasses, hdTrainData.shape[1]), lambda x, y: 0, "prototypeCounter") #Every dimension is the sum of the targeted data #max is the number records the added vectors, later for binary voting max = hcl.compute((numClasses, ), lambda x: 0) hcl.mutate((numClasses, ), lambda k: learn(k, hdTrainData, prototype, prototypeCounter), "learn") #Test the accuracy after learning hcl.mutate((1, ), lambda x: test_hdc_accu(prototype, hdTrainData, trainLabels, 1), "test_train_accu") hcl.mutate((1, ), lambda x: test_hdc_accu(prototype, hdTestData, testLabels, 2), "test_test_accu") ###update hcl.mutate((epoch[0], ), lambda x: update(x, prototype, prototypeCounter, max), "update")