diff --git a/Applications/GesturePod/training/README.md b/Applications/GesturePod/training/README.md index fe80bf6f..844b3e6f 100644 --- a/Applications/GesturePod/training/README.md +++ b/Applications/GesturePod/training/README.md @@ -83,6 +83,13 @@ the GesturePod. Alternately, update ```EdgeML/Applications/GesturePod/onComputer/src/data.h``` to simulate inference of the new model on your computer. +To generate a `data.h`, you could follow the below: +Save the W, B, Z matrices as Tab Separated Values (tsv) after training a model, in the path of `genDataHeader.py`. +Note the value of `gamma`. +``` +python genDataHeader.py [gamma] +``` +This will generate the `data.h` ## Dependencies To communicate with the MPU6050, we use [jrowberg's](https://github.com/jrowberg/i2cdevlib) ```i2cdevlib``` library. Last tested with commit [900b8f9](https://github.com/jrowberg/i2cdevlib/tree/900b8f959e9fa5c3126e0301f8a61d45a4ea99cc). diff --git a/Applications/GesturePod/training/dataFileTemplate.py b/Applications/GesturePod/training/dataFileTemplate.py new file mode 100644 index 00000000..319df642 --- /dev/null +++ b/Applications/GesturePod/training/dataFileTemplate.py @@ -0,0 +1,92 @@ +''' +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the MIT license. + +dataFileTemplate.py has the template for data.h +DO NOT MODIFY THIS + +''' +def populateDataFileTemplate(valueDict): + gamma = valueDict['gamma'] + featDim = valueDict['featDim'] + ldDim = valueDict['ldDim'] + ldProjectionMatrix = valueDict['ldProjectionMatrix'] + numPrototypes = valueDict['numPrototypes'] + prototypeMatrix = valueDict['prototypeMatrix'] + numLabels = valueDict['numLabels'] + prototypeLabelMatrix = valueDict['prototypeLabelMatrix'] + + template = '''/* + * This is an autogenerated file. Modifications + * might not be persistent. + */ +namespace protoNNParam { + +#ifndef __TEST_PROTONN__ + /** Gamma for gaussian kernel */ + const PROGMEM float gamma = %s; + /** Low Dimensional Projection Matrix */ + const PROGMEM unsigned int featDim = %s; + const PROGMEM unsigned int ldDim = %s; + + /** + * Projectino Matrix (W) + * d_cap x d flattened (dimension of 2D array) + * ldDim x featDim + */ + const PROGMEM float ldProjectionMatrix[] = {%s}; + ''' % (gamma, featDim, ldDim, ldProjectionMatrix) + + template += ''' + /** + * Prototypes (B) + * m x d_cap flattened (dimension of 2D array) + * numPrototypes x d_cap + */ + const PROGMEM float prototypeMatrix[] = {%s}; + /** Number of prototypes (m) */ + const PROGMEM unsigned int numPrototypes = %s; + ''' % (prototypeMatrix, numPrototypes) + + template += ''' + /** + * Prototype Lables (Z) + * m x L (dimension of 2D array) + * numLabels x numPrototypes + */ + const PROGMEM float prototypeLabelMatrix[] = {%s}; + /** Number of output labels, (L). */ + const PROGMEM unsigned int numLabels = %s; // 0,1,2,3,4,5 + ''' % (prototypeLabelMatrix, numLabels) + + template += ''' +#else + const PROGMEM float = 1.0; + const PROGMEM unsigned int featDim = 10; + const PROGMEM unsigned int ldDim = 5; + // Row Major (X.x) + const PROGMEM float ldProjectionMatrix[] = { + 0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0, + 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0, + 2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0, + 3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0, + 4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0, + }; + // Column Major + const PROGMEM unsigned int numPrototypes = 3; + const PROGMEM float prototypeMatrix[] = { + -1.0,-0.5,0.0,0.5,1.0, + -2.0,-1.0,0.0,1.0,2.0, + -7.51,-7.51,-7.51,-7.51,-7.51, + }; + // column major + const PROGMEM unsigned int numLabels = 4; + const PROGMEM float prototypeLabelMatrix[] = { + 0.96,0.01,0.01,0.02, + 0.02,0.94,0.02,0.02, + 0.10,0.15,0.55,0.20, + }; +#endif +}; + ''' + return template diff --git a/Applications/GesturePod/training/genDataHeader.py b/Applications/GesturePod/training/genDataHeader.py new file mode 100644 index 00000000..8b5b7df7 --- /dev/null +++ b/Applications/GesturePod/training/genDataHeader.py @@ -0,0 +1,102 @@ +''' +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the MIT license. + +genDataHeader.py generates data.h +''' + +import numpy as np +import pandas as pd +from dataFileTemplate import populateDataFileTemplate +import sys + + +def loadTLCMatrices(dfolder): + ''' + Loads Matrices B, W and Z from TLC format + ''' + # W is stored as d_cap x d + df = pd.read_csv(dfolder + 'W', sep='\t', header=None) + W = np.matrix(df) + d_cap = W.shape[0] + + # B is stored as d_cap x m + df = pd.read_csv(dfolder + 'B', sep='\t', header=None) + B = np.matrix(df) + m = B.shape[1] + assert(d_cap == B.shape[0]) + + # Z is stored as L x m + df = pd.read_csv(dfolder + 'Z', sep='\t', header=None) + Z = np.matrix(df) + assert(Z.shape[1] == m) + + return W, B, Z + + +def createDataFile(W, B, Z, gamma, outfile='data.h'): + ''' + Exports the provided matrices loaded, into a temp file + so that they can be directly copied onto the MKR1000 + board's data.h file. + Required input matrix dimensions: + W: d_cap x d + B: d_cap x m + Z: L x m + + Created output dimensions: + W: d_cap x d + B: m x d_cap (i.e column major) + Z: m x L (i.e. column major) + ''' + valueDict = {} + valueDict['gamma'] = gamma + d_cap = W.shape[0] + d = W.shape[1] + valueDict['featDim'] = '%d' % (d) + valueDict['ldDim'] = '%d' % (d_cap) + WStr = '\n\t\t' + for i in range(0, d_cap): + for j in range(0, d): + WStr += str(W[i, j]) + ',' + WStr += '\n\t\t' + valueDict['ldProjectionMatrix'] = WStr[:-1] + + assert(B.shape[0] == d_cap) + m = B.shape[1] + valueDict['numPrototypes'] = '%d' % (m) + BStr = '\n\t\t' + for i in range(0, m): + for j in range(0, d_cap): + # Column major (j, i) + BStr += '%f' % (B[j, i]) + ',' + BStr += '\n\t\t' + valueDict['prototypeMatrix'] = BStr[:-1] + assert(Z.shape[1] == m) + L = Z.shape[0] + valueDict['numLabels'] = L + ZStr = '\n\t\t' + for i in range(0, m): + for j in range(0, L): + # Columns major + ZStr += '%f' % (Z[j, i]) + ',' + ZStr += '\n\t\t' + valueDict['prototypeLabelMatrix'] = ZStr[:-2] + template = populateDataFileTemplate(valueDict) + fin = open(outfile, 'w') + fin.write(template) + fin.close() + + + +def automaticExport(): + # Copy W, B, Z from Debug + gamma = sys.argv[1] + dfolder = './' + W, B, Z = loadTLCMatrices(dfolder) + # Create a new file with gamma in it + createDataFile(W, B, Z, gamma, 'data.h') + + +if __name__ == '__main__': + automaticExport()