ref: cc714cc5b004ca6304053322bead45a0d306876e
parent: 1074e5f03b519f5c0d12a9c83413b28cabcd5f06
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Tue May 9 23:05:41 EDT 2023
binary weights work in progress
--- 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;
--- /dev/null
+++ b/dnn/parse_lpcnet_weights.c
@@ -1,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;
+}
--- a/dnn/training_tf2/dump_lpcnet.py
+++ b/dnn/training_tf2/dump_lpcnet.py
@@ -39,6 +39,7 @@
import re
import argparse
+array_list = []
# no cuda devices needed
os.environ['CUDA_VISIBLE_DEVICES'] = ""
@@ -52,11 +53,19 @@
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 @@
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):
@@ -341,6 +351,15 @@
layer_list.append(layer.name)
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))
--- /dev/null
+++ b/dnn/write_lpcnet_weights.c
@@ -1,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;
+}
--
⑨