diff --git a/dnn/nnet.h b/dnn/nnet.h index 7e2549b271e858c18278c59ea9be4990d6ceb88c..58afeeb28d7b08c838f99f8f102d2ddca201f1ba 100644 --- a/dnn/nnet.h +++ b/dnn/nnet.h @@ -38,6 +38,29 @@ #define ACTIVATION_SOFTMAX 4 #define ACTIVATION_SWISH 5 +#define WEIGHT_BLOB_VERSION 0 +#define WEIGHT_BLOCK_SIZE 64 +typedef struct { + const char *name; + int type; + int size; + const void *data; +} WeightArray; + +#define WEIGHT_TYPE_float 0 +#define WEIGHT_TYPE_int 1 +#define WEIGHT_TYPE_qweight 2 + +typedef struct { + char head[4]; + int version; + int type; + int size; + int block_size; + char name[44]; +} WeightHead; + + typedef struct { const float *bias; const float *input_weights; diff --git a/dnn/parse_lpcnet_weights.c b/dnn/parse_lpcnet_weights.c new file mode 100644 index 0000000000000000000000000000000000000000..0be08046073d1af229584e41c3ab548e3f808e25 --- /dev/null +++ b/dnn/parse_lpcnet_weights.c @@ -0,0 +1,104 @@ +/* Copyright (c) 2023 Amazon */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "nnet.h" + +extern const WeightArray lpcnet_arrays[]; + +int parse_record(const unsigned char **data, int *len, WeightArray *array) { + if (*len < WEIGHT_BLOCK_SIZE) return -1; + WeightHead *h = (WeightHead *)*data; + if (h->block_size < h->size) return -1; + if (*len < h->block_size+WEIGHT_BLOCK_SIZE) return -1; + if (h->name[sizeof(h->name)-1] != 0) return -1; + if (h->size < 0) return -1; + array->name = h->name; + array->type = h->type; + array->size = h->size; + array->data = (*data)+WEIGHT_BLOCK_SIZE; + + *data += h->block_size+WEIGHT_BLOCK_SIZE; + *len -= h->block_size+WEIGHT_BLOCK_SIZE; + return array->size; +} + +int parse_weights(WeightArray **list, const unsigned char *data, int len) +{ + int nb_arrays=0; + int capacity=20; + *list = malloc(capacity*sizeof(WeightArray)); + while (len > 0) { + int ret; + WeightArray array = {NULL, 0, 0, 0}; + ret = parse_record(&data, &len, &array); + if (ret > 0) { + if (nb_arrays+1 >= capacity) { + /* Make sure there's room for the ending NULL element too. */ + capacity = capacity*3/2; + *list = realloc(*list, capacity*sizeof(WeightArray)); + } + (*list)[nb_arrays++] = array; + } + } + (*list)[nb_arrays].name=NULL; + return nb_arrays; +} + +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> +#include <sys/stat.h> +#include <stdio.h> + +int main() +{ + int fd; + unsigned char *data; + int len; + int nb_arrays; + int i; + WeightArray *list; + struct stat st; + const char *filename = "weights_blob.bin"; + stat(filename, &st); + len = st.st_size; + fd = open(filename, O_RDONLY); + data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + printf("size is %d\n", len); + nb_arrays = parse_weights(&list, data, len); + for (i=0;i<nb_arrays;i++) { + printf("found %s: size %d\n", list[i].name, list[i].size); + } + printf("%p\n", list[i].name); + free(list); + munmap(data, len); + close(fd); + return 0; +} diff --git a/dnn/training_tf2/dump_lpcnet.py b/dnn/training_tf2/dump_lpcnet.py index e2877177561028468d324ca5a65388f9ff9b878b..ece5d2cfc91f036ddb177c09eeee63f59ba8accc 100755 --- a/dnn/training_tf2/dump_lpcnet.py +++ b/dnn/training_tf2/dump_lpcnet.py @@ -39,6 +39,7 @@ import h5py import re import argparse +array_list = [] # no cuda devices needed os.environ['CUDA_VISIBLE_DEVICES'] = "" @@ -52,11 +53,19 @@ max_conv_inputs = 1 max_mdense_tmp = 1 def printVector(f, vector, name, dtype='float', dotp=False): + global array_list if dotp: vector = vector.reshape((vector.shape[0]//4, 4, vector.shape[1]//8, 8)) vector = vector.transpose((2, 0, 3, 1)) v = np.reshape(vector, (-1)); #print('static const float ', name, '[', len(v), '] = \n', file=f) + if name not in array_list: + array_list.append(name) + f.write('#ifdef USE_WEIGHTS_FILE\n') + f.write('static const {} *{} = NULL;\n'.format(dtype, name, len(v))) + f.write('#else\n') + f.write('#define WEIGHTS_{}_DEFINED\n'.format(name)) + f.write('#define WEIGHTS_{}_TYPE WEIGHT_TYPE_{}\n'.format(name, dtype)) f.write('static const {} {}[{}] = {{\n '.format(dtype, name, len(v))) for i in range(0, len(v)): f.write('{}'.format(v[i])) @@ -69,7 +78,8 @@ def printVector(f, vector, name, dtype='float', dotp=False): else: f.write(" ") #print(v, file=f) - f.write('\n};\n\n') + f.write('\n};\n') + f.write('#endif\n\n') return; def printSparseVector(f, A, name, have_diag=True): @@ -342,6 +352,15 @@ if __name__ == "__main__": dump_sparse_gru(model.get_layer('gru_a'), f, hf) + f.write('#ifdef DUMP_BINARY_WEIGHTS\n') + f.write('const WeightArray lpcnet_arrays[] = {\n') + for name in array_list: + f.write('#ifdef WEIGHTS_{}_DEFINED\n'.format(name)) + f.write(' {{"{}", WEIGHTS_{}_TYPE, sizeof({}), {}}},\n'.format(name, name, name, name)) + f.write('#endif\n') + f.write(' {NULL, 0, 0}\n};\n') + f.write('#endif\n') + hf.write('#define MAX_RNN_NEURONS {}\n\n'.format(max_rnn_neurons)) hf.write('#define MAX_CONV_INPUTS {}\n\n'.format(max_conv_inputs)) hf.write('#define MAX_MDENSE_TMP {}\n\n'.format(max_mdense_tmp)) diff --git a/dnn/write_lpcnet_weights.c b/dnn/write_lpcnet_weights.c new file mode 100644 index 0000000000000000000000000000000000000000..74a019689d133fae5329067da012bc51e39ebbfe --- /dev/null +++ b/dnn/write_lpcnet_weights.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2023 Amazon */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include "nnet.h" + +extern const WeightArray lpcnet_arrays[]; + +void write_weights(const WeightArray *list, FILE *fout) +{ + int i=0; + unsigned char zeros[WEIGHT_BLOCK_SIZE] = {0}; + while (list[i].name != NULL) { + WeightHead h; + strcpy(h.head, "DNNw"); + h.version = WEIGHT_BLOB_VERSION; + h.type = list[i].type; + h.size = list[i].size; + h.block_size = (h.size+WEIGHT_BLOCK_SIZE-1)/WEIGHT_BLOCK_SIZE*WEIGHT_BLOCK_SIZE; + RNN_CLEAR(h.name, sizeof(h.name)); + strncpy(h.name, list[i].name, sizeof(h.name)); + h.name[sizeof(h.name)-1] = 0; + celt_assert(sizeof(h) == WEIGHT_BLOCK_SIZE); + fwrite(&h, 1, WEIGHT_BLOCK_SIZE, fout); + fwrite(list[i].data, 1, h.size, fout); + fwrite(zeros, 1, h.block_size-h.size, fout); + i++; + } +} + +int main() +{ + FILE *fout = fopen("weights_blob.bin", "w"); + write_weights(lpcnet_arrays, fout); + fclose(fout); + return 0; +}