From 9f95ff5b6ba01db09552b84a0ab79607060a2666 Mon Sep 17 00:00:00 2001 From: Ali Labbene Date: Wed, 11 Dec 2019 08:59:21 +0100 Subject: Official ARM version: v5.4.0 Add CMSIS V5.4.0, please refer to index.html available under \docs folder. Note: content of \CMSIS\Core\Include has been copied under \Include to keep the same structure used in existing projects, and thus avoid projects mass update Note: the following components have been removed from ARM original delivery (as not used in ST packages) - CMSIS_EW2018.pdf - .gitattributes - .gitignore - \Device - \CMSIS - \CoreValidation - \DAP - \Documentation - \DoxyGen - \Driver - \Pack - \RTOS\CMSIS_RTOS_Tutorial.pdf - \RTOS\RTX - \RTOS\Template - \RTOS2\RTX - \Utilities - All ARM/GCC projects files are deleted from \DSP, \RTOS and \RTOS2 Change-Id: Ia026c3f0f0d016627a4fb5a9032852c33d24b4d3 --- .../fully_connected_opt_weight_generation.py | 146 +++++++++++++++++++++ NN/Scripts/NNFunctions/table_gen.py | 116 ++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 NN/Scripts/NNFunctions/fully_connected_opt_weight_generation.py create mode 100644 NN/Scripts/NNFunctions/table_gen.py (limited to 'NN/Scripts') diff --git a/NN/Scripts/NNFunctions/fully_connected_opt_weight_generation.py b/NN/Scripts/NNFunctions/fully_connected_opt_weight_generation.py new file mode 100644 index 0000000..0319e83 --- /dev/null +++ b/NN/Scripts/NNFunctions/fully_connected_opt_weight_generation.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +import numpy as np + +def convert_to_x4_q7_weights(weights): + [r, h, w, c] = weights.shape + weights = np.reshape(weights, (r, h*w*c)) + num_of_rows = r + num_of_cols = h*w*c + new_weights = np.copy(weights) + new_weights = np.reshape(new_weights, (r*h*w*c)) + counter = 0 + for i in range(int(num_of_rows)/4): + # we only need to do the re-ordering for every 4 rows + row_base = 4*i + for j in range (int(num_of_cols)/4): + # for each 4 entries + column_base = 4*j + new_weights[counter] = weights[row_base ][column_base ] + new_weights[counter+1] = weights[row_base+1][column_base ] + new_weights[counter+2] = weights[row_base ][column_base+2] + new_weights[counter+3] = weights[row_base+1][column_base+2] + new_weights[counter+4] = weights[row_base+2][column_base ] + new_weights[counter+5] = weights[row_base+3][column_base ] + new_weights[counter+6] = weights[row_base+2][column_base+2] + new_weights[counter+7] = weights[row_base+3][column_base+2] + + new_weights[counter+8] = weights[row_base ][column_base+1] + new_weights[counter+9] = weights[row_base+1][column_base+1] + new_weights[counter+10] = weights[row_base ][column_base+3] + new_weights[counter+11] = weights[row_base+1][column_base+3] + new_weights[counter+12] = weights[row_base+2][column_base+1] + new_weights[counter+13] = weights[row_base+3][column_base+1] + new_weights[counter+14] = weights[row_base+2][column_base+3] + new_weights[counter+15] = weights[row_base+3][column_base+3] + counter = counter + 16 + # the remaining ones are in order + for j in range((int)(num_of_cols-num_of_cols%4), int(num_of_cols)): + new_weights[counter] = weights[row_base][j] + new_weights[counter+1] = weights[row_base+1][j] + new_weights[counter+2] = weights[row_base+2][j] + new_weights[counter+3] = weights[row_base+3][j] + counter = counter + 4 + return new_weights + +def convert_to_x4_q15_weights(weights): + [r, h, w, c] = weights.shape + weights = np.reshape(weights, (r, h*w*c)) + num_of_rows = r + num_of_cols = h*w*c + new_weights = np.copy(weights) + new_weights = np.reshape(new_weights, (r*h*w*c)) + counter = 0 + for i in range(int(num_of_rows)/4): + # we only need to do the re-ordering for every 4 rows + row_base = 4*i + for j in range (int(num_of_cols)/2): + # for each 2 entries + column_base = 2*j + new_weights[counter] = weights[row_base ][column_base ] + new_weights[counter+1] = weights[row_base ][column_base+1] + new_weights[counter+2] = weights[row_base+1][column_base ] + new_weights[counter+3] = weights[row_base+1][column_base+1] + new_weights[counter+4] = weights[row_base+2][column_base ] + new_weights[counter+5] = weights[row_base+2][column_base+1] + new_weights[counter+6] = weights[row_base+3][column_base ] + new_weights[counter+7] = weights[row_base+3][column_base+1] + + counter = counter + 8 + # the remaining ones are in order + for j in range((int)(num_of_cols-num_of_cols%2), int(num_of_cols)): + new_weights[counter] = weights[row_base][j] + new_weights[counter+1] = weights[row_base+1][j] + new_weights[counter+2] = weights[row_base+2][j] + new_weights[counter+3] = weights[row_base+3][j] + counter = counter + 4 + return new_weights + +def convert_q7_q15_weights(weights): + [r, h, w, c] = weights.shape + weights = np.reshape(weights, (r, h*w*c)) + num_of_rows = r + num_of_cols = h*w*c + new_weights = np.copy(weights) + new_weights = np.reshape(new_weights, (r*h*w*c)) + counter = 0 + for i in range(int(num_of_rows)/4): + # we only need to do the re-ordering for every 4 rows + row_base = 4*i + for j in range (int(num_of_cols)/2): + # for each 2 entries + column_base = 2*j + new_weights[counter] = weights[row_base ][column_base ] + new_weights[counter+1] = weights[row_base+1][column_base ] + new_weights[counter+2] = weights[row_base ][column_base+1] + new_weights[counter+3] = weights[row_base+1][column_base+1] + new_weights[counter+4] = weights[row_base+2][column_base ] + new_weights[counter+5] = weights[row_base+3][column_base ] + new_weights[counter+6] = weights[row_base+2][column_base+1] + new_weights[counter+7] = weights[row_base+3][column_base+1] + + counter = counter + 8 + # the remaining ones are in order + for j in range((int)(num_of_cols-num_of_cols%2), int(num_of_cols)): + new_weights[counter] = weights[row_base][j] + new_weights[counter+1] = weights[row_base+1][j] + new_weights[counter+2] = weights[row_base+2][j] + new_weights[counter+3] = weights[row_base+3][j] + counter = counter + 4 + return new_weights + +# input dimensions +vec_dim = 127 +row_dim = 127 + +weight = np.zeros((row_dim,vec_dim), dtype=int) + +# generate random inputs +for i in range(row_dim): + for j in range(vec_dim): + weight[i][j] = np.random.randint(256)-128 + +weight = np.reshape(weight, (row_dim, vec_dim, 1, 1)) + +outfile = open("../Ref_Implementations/fully_connected_testing_weights.h", "w") +outfile.write("#define IP2_WEIGHT {") +weight.tofile(outfile,sep=",",format="%d") +outfile.write("}\n\n") + +new_weight = convert_to_x4_q7_weights(weight) +outfile.write("#define IP4_WEIGHT {") +new_weight.tofile(outfile,sep=",",format="%d") +outfile.write("}\n\n") + +new_weight = convert_q7_q15_weights(weight) +outfile.write("#define IP4_q7_q15_WEIGHT {") +new_weight.tofile(outfile,sep=",",format="%d") +outfile.write("}\n\n") + +new_weight = convert_to_x4_q15_weights(weight) +outfile.write("#define IP4_WEIGHT_Q15 {") +new_weight.tofile(outfile,sep=",",format="%d") +outfile.write("}\n\n") + + +outfile.close() diff --git a/NN/Scripts/NNFunctions/table_gen.py b/NN/Scripts/NNFunctions/table_gen.py new file mode 100644 index 0000000..5db6d3e --- /dev/null +++ b/NN/Scripts/NNFunctions/table_gen.py @@ -0,0 +1,116 @@ +#!/usr/bin/python + +import math + +class Table(object): + + def __init__(self, table_entry=256, table_range=8): + self.table_entry = table_entry + self.table_range = table_range + pass + + def sigmoid(self, x): + return 1 / (1 + math.exp(-1*x)) + + def tanh(self, x): + return (math.exp(2*x)-1) / (math.exp(2*x)+1) + + def fp2q7(self, x): + x_int = math.floor(x*(2**7)+0.5) + if x_int >= 128 : + x_int = 127 + if x_int < -128 : + x_int = -128 + if x_int >= 0 : + return x_int + else : + return 0x100 + x_int + + def fp2q15(self, x): + x_int = math.floor(x*(2**15)+0.5) + if x_int >= 2**15 : + x_int = 2**15-1 + if x_int < -1*2**15 : + x_int = -1*2**15 + if x_int >= 0 : + return x_int + else : + return 0x10000 + x_int + + def table_gen(self): + outfile = open("NNCommonTable.c", "wb") + + outfile.write("/*\n * Common tables for NN\n *\n *\n *\n *\n */\n\n#include \"arm_math.h\"\n#include \"NNCommonTable.h\"\n\n/*\n * Table for sigmoid\n */\n") + + for function_type in ["sigmoid", "tanh"]: + for data_type in [7, 15]: + out_type = "q"+str(data_type)+"_t" + act_func = getattr(self, function_type) + quan_func = getattr(self, 'fp2q'+str(data_type)) + + # unified table + outfile.write('const %s %sTable_q%d[%d] = {\n' % (out_type, function_type, data_type, self.table_entry) ) + for i in range(self.table_entry): + # convert into actual value + if i < self.table_entry/2: + value_q7 = self.table_range * (i) + else: + value_q7 = self.table_range * (i - self.table_entry) + + if data_type == 7: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%02x, ' % (quan_func(act_func(float(value_q7)/self.table_entry)))) + else: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%04x, ' % (quan_func(act_func(float(value_q7)/self.table_entry)))) + if i % 8 == 7: + outfile.write("\n") + outfile.write("};\n\n") + + for data_type in [15]: + out_type = "q"+str(data_type)+"_t" + act_func = getattr(self, function_type) + quan_func = getattr(self, 'fp2q'+str(data_type)) + + # H-L tables + outfile.write('const %s %sLTable_q%d[%d] = {\n' % (out_type, function_type, data_type, self.table_entry/2)) + for i in range(self.table_entry/2): + # convert into actual value, max value is 16*self.table_entry/4 / 4 + # which is equivalent to self.table_entry / self.table_entry/2 = 2, i.e., 1/4 of 8 + if i < self.table_entry/4: + value_q7 = self.table_range * i / 4 + else: + value_q7 = self.table_range * (i - self.table_entry/2) / 4 + if data_type == 7: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%02x, ' % (quan_func(act_func(float(value_q7)/(self.table_entry/2))))) + else: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%04x, ' % (quan_func(act_func(float(value_q7)/(self.table_entry/2))))) + if i % 8 == 7: + outfile.write("\n") + outfile.write("};\n\n") + + outfile.write('const %s %sHTable_q%d[%d] = {\n' % (out_type, function_type, data_type, 3*self.table_entry/4)) + for i in range(3 * self.table_entry/4): + # convert into actual value, tageting range (2, 8) + if i < 3*self.table_entry/8 : + value_q7 = self.table_range * ( i + self.table_entry/8 ) + else: + value_q7 = self.table_range * ( i + self.table_entry/8 - self.table_entry) + if data_type == 7: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%02x, ' % (quan_func(act_func(float(value_q7)/self.table_entry)))) + else: + #outfile.write('%f, ' % (act_func(float(value_q7)/256))) + outfile.write('0x%04x, ' % (quan_func(act_func(float(value_q7)/self.table_entry)))) + if i % 8 == 7: + outfile.write("\n") + outfile.write("};\n\n") + + outfile.close() + + +mytable = Table(table_entry=256, table_range=16) + +mytable.table_gen() -- cgit