ref: f0ce43389ad630f0594be81ce1716b2b72e8c883
parent: d428b0d32af185cf50afaaddf31d54f3e8d01842
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Wed Jun 30 14:54:27 EDT 2021
Update test_lpcnet.py, remove old TF1 code
--- a/dnn/causalconv.py
+++ /dev/null
@@ -1,52 +1,0 @@
-from keras import backend as K
-from keras.engine.topology import Layer
-from keras.layers import activations, initializers, regularizers, constraints, InputSpec, Conv1D
-import numpy as np
-
-class CausalConv(Conv1D):
-
- def __init__(self, filters,
- kernel_size,
- dilation_rate=1,
- activation=None,
- use_bias=True,
- kernel_initializer='glorot_uniform',
- bias_initializer='zeros',
- kernel_regularizer=None,
- bias_regularizer=None,
- activity_regularizer=None,
- kernel_constraint=None,
- bias_constraint=None,
- return_memory=False,
- **kwargs):
-
- super(CausalConv, self).__init__(
- filters=filters,
- kernel_size=kernel_size,
- strides=1,
- padding='valid',
- data_format='channels_last',
- dilation_rate=dilation_rate,
- activation=activation,
- use_bias=use_bias,
- kernel_initializer=kernel_initializer,
- bias_initializer=bias_initializer,
- kernel_regularizer=kernel_regularizer,
- bias_regularizer=bias_regularizer,
- activity_regularizer=activity_regularizer,
- kernel_constraint=kernel_constraint,
- bias_constraint=bias_constraint,
- **kwargs)
- self.mem_size = dilation_rate*(kernel_size-1)
- self.return_memory = return_memory
-
- def call(self, inputs, memory=None):
- if memory is None:
- mem = K.zeros((K.shape(inputs)[0], self.mem_size, K.shape(inputs)[-1]))
- else:
- mem = K.variable(K.cast_to_floatx(memory))
- inputs = K.concatenate([mem, inputs], axis=1)
- ret = super(CausalConv, self).call(inputs)
- if self.return_memory:
- ret = ret, inputs[:, :self.mem_size, :]
- return ret
--- a/dnn/dump_lpcnet.py
+++ /dev/null
@@ -1,270 +1,0 @@
-#!/usr/bin/python3
-'''Copyright (c) 2017-2018 Mozilla
-
- 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.
-'''
-
-import lpcnet
-import sys
-import numpy as np
-from keras.optimizers import Adam
-from keras.callbacks import ModelCheckpoint
-from keras.layers import Layer, GRU, CuDNNGRU, Dense, Conv1D, Embedding
-from ulaw import ulaw2lin, lin2ulaw
-from mdense import MDense
-import keras.backend as K
-import h5py
-import re
-
-max_rnn_neurons = 1
-max_conv_inputs = 1
-max_mdense_tmp = 1
-
-def printVector(f, vector, name, dtype='float'):
- v = np.reshape(vector, (-1));
- #print('static const float ', name, '[', len(v), '] = \n', file=f)
- f.write('static const {} {}[{}] = {{\n '.format(dtype, name, len(v)))
- for i in range(0, len(v)):
- f.write('{}'.format(v[i]))
- if (i!=len(v)-1):
- f.write(',')
- else:
- break;
- if (i%8==7):
- f.write("\n ")
- else:
- f.write(" ")
- #print(v, file=f)
- f.write('\n};\n\n')
- return;
-
-def printSparseVector(f, A, name):
- N = A.shape[0]
- W = np.zeros((0,))
- diag = np.concatenate([np.diag(A[:,:N]), np.diag(A[:,N:2*N]), np.diag(A[:,2*N:])])
- A[:,:N] = A[:,:N] - np.diag(np.diag(A[:,:N]))
- A[:,N:2*N] = A[:,N:2*N] - np.diag(np.diag(A[:,N:2*N]))
- A[:,2*N:] = A[:,2*N:] - np.diag(np.diag(A[:,2*N:]))
- printVector(f, diag, name + '_diag')
- idx = np.zeros((0,), dtype='int')
- for i in range(3*N//16):
- pos = idx.shape[0]
- idx = np.append(idx, -1)
- nb_nonzero = 0
- for j in range(N):
- if np.sum(np.abs(A[j, i*16:(i+1)*16])) > 1e-10:
- nb_nonzero = nb_nonzero + 1
- idx = np.append(idx, j)
- W = np.concatenate([W, A[j, i*16:(i+1)*16]])
- idx[pos] = nb_nonzero
- printVector(f, W, name)
- #idx = np.tile(np.concatenate([np.array([N]), np.arange(N)]), 3*N//16)
- printVector(f, idx, name + '_idx', dtype='int')
- return;
-
-def dump_layer_ignore(self, f, hf):
- print("ignoring layer " + self.name + " of type " + self.__class__.__name__)
- return False
-Layer.dump_layer = dump_layer_ignore
-
-def dump_sparse_gru(self, f, hf):
- global max_rnn_neurons
- name = 'sparse_' + self.name
- print("printing layer " + name + " of type sparse " + self.__class__.__name__)
- weights = self.get_weights()
- printSparseVector(f, weights[1], name + '_recurrent_weights')
- printVector(f, weights[-1], name + '_bias')
- if hasattr(self, 'activation'):
- activation = self.activation.__name__.upper()
- else:
- activation = 'TANH'
- if hasattr(self, 'reset_after') and not self.reset_after:
- reset_after = 0
- else:
- reset_after = 1
- neurons = weights[0].shape[1]//3
- max_rnn_neurons = max(max_rnn_neurons, neurons)
- f.write('const SparseGRULayer {} = {{\n {}_bias,\n {}_recurrent_weights_diag,\n {}_recurrent_weights,\n {}_recurrent_weights_idx,\n {}, ACTIVATION_{}, {}\n}};\n\n'
- .format(name, name, name, name, name, weights[0].shape[1]//3, activation, reset_after))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights[0].shape[1]//3))
- hf.write('#define {}_STATE_SIZE {}\n'.format(name.upper(), weights[0].shape[1]//3))
- hf.write('extern const SparseGRULayer {};\n\n'.format(name));
- return True
-
-def dump_gru_layer(self, f, hf):
- global max_rnn_neurons
- name = self.name
- print("printing layer " + name + " of type " + self.__class__.__name__)
- weights = self.get_weights()
- printVector(f, weights[0], name + '_weights')
- printVector(f, weights[1], name + '_recurrent_weights')
- printVector(f, weights[-1], name + '_bias')
- if hasattr(self, 'activation'):
- activation = self.activation.__name__.upper()
- else:
- activation = 'TANH'
- if hasattr(self, 'reset_after') and not self.reset_after:
- reset_after = 0
- else:
- reset_after = 1
- neurons = weights[0].shape[1]//3
- max_rnn_neurons = max(max_rnn_neurons, neurons)
- f.write('const GRULayer {} = {{\n {}_bias,\n {}_weights,\n {}_recurrent_weights,\n {}, {}, ACTIVATION_{}, {}\n}};\n\n'
- .format(name, name, name, name, weights[0].shape[0], weights[0].shape[1]//3, activation, reset_after))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights[0].shape[1]//3))
- hf.write('#define {}_STATE_SIZE {}\n'.format(name.upper(), weights[0].shape[1]//3))
- hf.write('extern const GRULayer {};\n\n'.format(name));
- return True
-CuDNNGRU.dump_layer = dump_gru_layer
-GRU.dump_layer = dump_gru_layer
-
-def dump_dense_layer_impl(name, weights, bias, activation, f, hf):
- printVector(f, weights, name + '_weights')
- printVector(f, bias, name + '_bias')
- f.write('const DenseLayer {} = {{\n {}_bias,\n {}_weights,\n {}, {}, ACTIVATION_{}\n}};\n\n'
- .format(name, name, name, weights.shape[0], weights.shape[1], activation))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights.shape[1]))
- hf.write('extern const DenseLayer {};\n\n'.format(name));
-
-def dump_dense_layer(self, f, hf):
- name = self.name
- print("printing layer " + name + " of type " + self.__class__.__name__)
- weights = self.get_weights()
- activation = self.activation.__name__.upper()
- dump_dense_layer_impl(name, weights[0], weights[1], activation, f, hf)
- return False
-
-Dense.dump_layer = dump_dense_layer
-
-def dump_mdense_layer(self, f, hf):
- global max_mdense_tmp
- name = self.name
- print("printing layer " + name + " of type " + self.__class__.__name__)
- weights = self.get_weights()
- printVector(f, np.transpose(weights[0], (1, 2, 0)), name + '_weights')
- printVector(f, np.transpose(weights[1], (1, 0)), name + '_bias')
- printVector(f, np.transpose(weights[2], (1, 0)), name + '_factor')
- activation = self.activation.__name__.upper()
- max_mdense_tmp = max(max_mdense_tmp, weights[0].shape[0]*weights[0].shape[2])
- f.write('const MDenseLayer {} = {{\n {}_bias,\n {}_weights,\n {}_factor,\n {}, {}, {}, ACTIVATION_{}\n}};\n\n'
- .format(name, name, name, name, weights[0].shape[1], weights[0].shape[0], weights[0].shape[2], activation))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights[0].shape[0]))
- hf.write('extern const MDenseLayer {};\n\n'.format(name));
- return False
-MDense.dump_layer = dump_mdense_layer
-
-def dump_conv1d_layer(self, f, hf):
- global max_conv_inputs
- name = self.name
- print("printing layer " + name + " of type " + self.__class__.__name__)
- weights = self.get_weights()
- printVector(f, weights[0], name + '_weights')
- printVector(f, weights[-1], name + '_bias')
- activation = self.activation.__name__.upper()
- max_conv_inputs = max(max_conv_inputs, weights[0].shape[1]*weights[0].shape[0])
- f.write('const Conv1DLayer {} = {{\n {}_bias,\n {}_weights,\n {}, {}, {}, ACTIVATION_{}\n}};\n\n'
- .format(name, name, name, weights[0].shape[1], weights[0].shape[0], weights[0].shape[2], activation))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights[0].shape[2]))
- hf.write('#define {}_STATE_SIZE ({}*{})\n'.format(name.upper(), weights[0].shape[1], (weights[0].shape[0]-1)))
- hf.write('#define {}_DELAY {}\n'.format(name.upper(), (weights[0].shape[0]-1)//2))
- hf.write('extern const Conv1DLayer {};\n\n'.format(name));
- return True
-Conv1D.dump_layer = dump_conv1d_layer
-
-
-def dump_embedding_layer_impl(name, weights, f, hf):
- printVector(f, weights, name + '_weights')
- f.write('const EmbeddingLayer {} = {{\n {}_weights,\n {}, {}\n}};\n\n'
- .format(name, name, weights.shape[0], weights.shape[1]))
- hf.write('#define {}_OUT_SIZE {}\n'.format(name.upper(), weights.shape[1]))
- hf.write('extern const EmbeddingLayer {};\n\n'.format(name));
-
-def dump_embedding_layer(self, f, hf):
- name = self.name
- print("printing layer " + name + " of type " + self.__class__.__name__)
- weights = self.get_weights()[0]
- dump_embedding_layer_impl(name, weights, f, hf)
- return False
-Embedding.dump_layer = dump_embedding_layer
-
-
-model, _, _ = lpcnet.new_lpcnet_model(rnn_units1=384, use_gpu=False)
-model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
-#model.summary()
-
-model.load_weights(sys.argv[1])
-
-if len(sys.argv) > 2:
- cfile = sys.argv[2];
- hfile = sys.argv[3];
-else:
- cfile = 'nnet_data.c'
- hfile = 'nnet_data.h'
-
-
-f = open(cfile, 'w')
-hf = open(hfile, 'w')
-
-
-f.write('/*This file is automatically generated from a Keras model*/\n\n')
-f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "nnet.h"\n#include "{}"\n\n'.format(hfile))
-
-hf.write('/*This file is automatically generated from a Keras model*/\n\n')
-hf.write('#ifndef RNN_DATA_H\n#define RNN_DATA_H\n\n#include "nnet.h"\n\n')
-
-embed_size = lpcnet.embed_size
-
-E = model.get_layer('embed_sig').get_weights()[0]
-W = model.get_layer('gru_a').get_weights()[0][:embed_size,:]
-dump_embedding_layer_impl('gru_a_embed_sig', np.dot(E, W), f, hf)
-W = model.get_layer('gru_a').get_weights()[0][embed_size:2*embed_size,:]
-dump_embedding_layer_impl('gru_a_embed_pred', np.dot(E, W), f, hf)
-W = model.get_layer('gru_a').get_weights()[0][2*embed_size:3*embed_size,:]
-dump_embedding_layer_impl('gru_a_embed_exc', np.dot(E, W), f, hf)
-W = model.get_layer('gru_a').get_weights()[0][3*embed_size:,:]
-#FIXME: dump only half the biases
-b = model.get_layer('gru_a').get_weights()[2]
-dump_dense_layer_impl('gru_a_dense_feature', W, b, 'LINEAR', f, hf)
-
-layer_list = []
-for i, layer in enumerate(model.layers):
- if layer.dump_layer(f, hf):
- layer_list.append(layer.name)
-
-dump_sparse_gru(model.get_layer('gru_a'), f, hf)
-
-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))
-
-
-hf.write('typedef struct {\n')
-for i, name in enumerate(layer_list):
- hf.write(' float {}_state[{}_STATE_SIZE];\n'.format(name, name.upper()))
-hf.write('} NNetState;\n')
-
-hf.write('\n\n#endif\n')
-
-f.close()
-hf.close()
--- a/dnn/gatedconv.py
+++ /dev/null
@@ -1,65 +1,0 @@
-from keras import backend as K
-from keras.engine.topology import Layer
-from keras.layers import activations, initializers, regularizers, constraints, InputSpec, Conv1D, Dense
-import numpy as np
-
-class GatedConv(Conv1D):
-
- def __init__(self, filters,
- kernel_size,
- dilation_rate=1,
- activation='tanh',
- use_bias=True,
- kernel_initializer='glorot_uniform',
- bias_initializer='zeros',
- kernel_regularizer=None,
- bias_regularizer=None,
- activity_regularizer=None,
- kernel_constraint=None,
- bias_constraint=None,
- return_memory=False,
- **kwargs):
-
- super(GatedConv, self).__init__(
- filters=2*filters,
- kernel_size=kernel_size,
- strides=1,
- padding='valid',
- data_format='channels_last',
- dilation_rate=dilation_rate,
- activation='linear',
- use_bias=use_bias,
- kernel_initializer=kernel_initializer,
- bias_initializer=bias_initializer,
- kernel_regularizer=kernel_regularizer,
- bias_regularizer=bias_regularizer,
- activity_regularizer=activity_regularizer,
- kernel_constraint=kernel_constraint,
- bias_constraint=bias_constraint,
- **kwargs)
- self.mem_size = dilation_rate*(kernel_size-1)
- self.return_memory = return_memory
- self.out_dims = filters
- self.nongate_activation = activations.get(activation)
-
- def call(self, inputs, cond=None, memory=None):
- if memory is None:
- mem = K.zeros((K.shape(inputs)[0], self.mem_size, K.shape(inputs)[-1]))
- else:
- mem = K.variable(K.cast_to_floatx(memory))
- inputs = K.concatenate([mem, inputs], axis=1)
- ret = super(GatedConv, self).call(inputs)
- if cond is not None:
- d = Dense(2*self.out_dims, use_bias=False, activation='linear')
- ret = ret + d(cond)
- ret = self.nongate_activation(ret[:, :, :self.out_dims]) * activations.sigmoid(ret[:, :, self.out_dims:])
- if self.return_memory:
- ret = ret, inputs[:, :self.mem_size, :]
- return ret
-
- def compute_output_shape(self, input_shape):
- assert input_shape and len(input_shape) >= 2
- assert input_shape[-1]
- output_shape = list(input_shape)
- output_shape[-1] = self.out_dims
- return tuple(output_shape)
--- a/dnn/lpcnet.py
+++ /dev/null
@@ -1,176 +1,0 @@
-#!/usr/bin/python3
-'''Copyright (c) 2018 Mozilla
-
- 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.
-'''
-
-import math
-from keras.models import Model
-from keras.layers import Input, GRU, CuDNNGRU, Dense, Embedding, Reshape, Concatenate, Lambda, Conv1D, Multiply, Add, Bidirectional, MaxPooling1D, Activation
-from keras import backend as K
-from keras.initializers import Initializer
-from keras.callbacks import Callback
-from mdense import MDense
-import numpy as np
-import h5py
-import sys
-
-frame_size = 160
-pcm_bits = 8
-embed_size = 128
-pcm_levels = 2**pcm_bits
-
-class Sparsify(Callback):
- def __init__(self, t_start, t_end, interval, density):
- super(Sparsify, self).__init__()
- self.batch = 0
- self.t_start = t_start
- self.t_end = t_end
- self.interval = interval
- self.final_density = density
-
- def on_batch_end(self, batch, logs=None):
- #print("batch number", self.batch)
- self.batch += 1
- if self.batch < self.t_start or ((self.batch-self.t_start) % self.interval != 0 and self.batch < self.t_end):
- #print("don't constrain");
- pass
- else:
- #print("constrain");
- layer = self.model.get_layer('gru_a')
- w = layer.get_weights()
- p = w[1]
- nb = p.shape[1]//p.shape[0]
- N = p.shape[0]
- #print("nb = ", nb, ", N = ", N);
- #print(p.shape)
- #print ("density = ", density)
- for k in range(nb):
- density = self.final_density[k]
- if self.batch < self.t_end:
- r = 1 - (self.batch-self.t_start)/(self.t_end - self.t_start)
- density = 1 - (1-self.final_density[k])*(1 - r*r*r)
- A = p[:, k*N:(k+1)*N]
- A = A - np.diag(np.diag(A))
- A = np.transpose(A, (1, 0))
- L=np.reshape(A, (N, N//16, 16))
- S=np.sum(L*L, axis=-1)
- SS=np.sort(np.reshape(S, (-1,)))
- thresh = SS[round(N*N//16*(1-density))]
- mask = (S>=thresh).astype('float32');
- mask = np.repeat(mask, 16, axis=1)
- mask = np.minimum(1, mask + np.diag(np.ones((N,))))
- mask = np.transpose(mask, (1, 0))
- p[:, k*N:(k+1)*N] = p[:, k*N:(k+1)*N]*mask
- #print(thresh, np.mean(mask))
- w[1] = p
- layer.set_weights(w)
-
-
-class PCMInit(Initializer):
- def __init__(self, gain=.1, seed=None):
- self.gain = gain
- self.seed = seed
-
- def __call__(self, shape, dtype=None):
- num_rows = 1
- for dim in shape[:-1]:
- num_rows *= dim
- num_cols = shape[-1]
- flat_shape = (num_rows, num_cols)
- if self.seed is not None:
- np.random.seed(self.seed)
- a = np.random.uniform(-1.7321, 1.7321, flat_shape)
- #a[:,0] = math.sqrt(12)*np.arange(-.5*num_rows+.5,.5*num_rows-.4)/num_rows
- #a[:,1] = .5*a[:,0]*a[:,0]*a[:,0]
- a = a + np.reshape(math.sqrt(12)*np.arange(-.5*num_rows+.5,.5*num_rows-.4)/num_rows, (num_rows, 1))
- return self.gain * a
-
- def get_config(self):
- return {
- 'gain': self.gain,
- 'seed': self.seed
- }
-
-def new_lpcnet_model(rnn_units1=384, rnn_units2=16, nb_used_features = 38, training=False, use_gpu=True, adaptation=False):
- pcm = Input(shape=(None, 3))
- feat = Input(shape=(None, nb_used_features))
- pitch = Input(shape=(None, 1))
- dec_feat = Input(shape=(None, 128))
- dec_state1 = Input(shape=(rnn_units1,))
- dec_state2 = Input(shape=(rnn_units2,))
-
- padding = 'valid' if training else 'same'
- fconv1 = Conv1D(128, 3, padding=padding, activation='tanh', name='feature_conv1')
- fconv2 = Conv1D(128, 3, padding=padding, activation='tanh', name='feature_conv2')
-
- embed = Embedding(256, embed_size, embeddings_initializer=PCMInit(), name='embed_sig')
- cpcm = Reshape((-1, embed_size*3))(embed(pcm))
-
- pembed = Embedding(256, 64, name='embed_pitch')
- cat_feat = Concatenate()([feat, Reshape((-1, 64))(pembed(pitch))])
-
- cfeat = fconv2(fconv1(cat_feat))
-
- fdense1 = Dense(128, activation='tanh', name='feature_dense1')
- fdense2 = Dense(128, activation='tanh', name='feature_dense2')
-
- cfeat = fdense2(fdense1(cfeat))
-
- rep = Lambda(lambda x: K.repeat_elements(x, frame_size, 1))
-
- if use_gpu:
- rnn = CuDNNGRU(rnn_units1, return_sequences=True, return_state=True, name='gru_a')
- rnn2 = CuDNNGRU(rnn_units2, return_sequences=True, return_state=True, name='gru_b')
- else:
- rnn = GRU(rnn_units1, return_sequences=True, return_state=True, recurrent_activation="sigmoid", reset_after='true', name='gru_a')
- rnn2 = GRU(rnn_units2, return_sequences=True, return_state=True, recurrent_activation="sigmoid", reset_after='true', name='gru_b')
-
- rnn_in = Concatenate()([cpcm, rep(cfeat)])
- md = MDense(pcm_levels, activation='softmax', name='dual_fc')
- gru_out1, _ = rnn(rnn_in)
- gru_out2, _ = rnn2(Concatenate()([gru_out1, rep(cfeat)]))
- ulaw_prob = md(gru_out2)
-
- if adaptation:
- rnn.trainable=False
- rnn2.trainable=False
- md.trainable=False
- embed.Trainable=False
-
- model = Model([pcm, feat, pitch], ulaw_prob)
- model.rnn_units1 = rnn_units1
- model.rnn_units2 = rnn_units2
- model.nb_used_features = nb_used_features
- model.frame_size = frame_size
-
- encoder = Model([feat, pitch], cfeat)
-
- dec_rnn_in = Concatenate()([cpcm, dec_feat])
- dec_gru_out1, state1 = rnn(dec_rnn_in, initial_state=dec_state1)
- dec_gru_out2, state2 = rnn2(Concatenate()([dec_gru_out1, dec_feat]), initial_state=dec_state2)
- dec_ulaw_prob = md(dec_gru_out2)
-
- decoder = Model([pcm, dec_feat, dec_state1, dec_state2], [dec_ulaw_prob, state1, state2])
- return model, encoder, decoder
--- a/dnn/mdense.py
+++ /dev/null
@@ -1,94 +1,0 @@
-from keras import backend as K
-from keras.engine.topology import Layer
-from keras.layers import activations, initializers, regularizers, constraints, InputSpec
-import numpy as np
-import math
-
-class MDense(Layer):
-
- def __init__(self, outputs,
- channels=2,
- activation=None,
- use_bias=True,
- kernel_initializer='glorot_uniform',
- bias_initializer='zeros',
- kernel_regularizer=None,
- bias_regularizer=None,
- activity_regularizer=None,
- kernel_constraint=None,
- bias_constraint=None,
- **kwargs):
- if 'input_shape' not in kwargs and 'input_dim' in kwargs:
- kwargs['input_shape'] = (kwargs.pop('input_dim'),)
- super(MDense, self).__init__(**kwargs)
- self.units = outputs
- self.channels = channels
- self.activation = activations.get(activation)
- self.use_bias = use_bias
- self.kernel_initializer = initializers.get(kernel_initializer)
- self.bias_initializer = initializers.get(bias_initializer)
- self.kernel_regularizer = regularizers.get(kernel_regularizer)
- self.bias_regularizer = regularizers.get(bias_regularizer)
- self.activity_regularizer = regularizers.get(activity_regularizer)
- self.kernel_constraint = constraints.get(kernel_constraint)
- self.bias_constraint = constraints.get(bias_constraint)
- self.input_spec = InputSpec(min_ndim=2)
- self.supports_masking = True
-
- def build(self, input_shape):
- assert len(input_shape) >= 2
- input_dim = input_shape[-1]
-
- self.kernel = self.add_weight(shape=(self.units, input_dim, self.channels),
- initializer=self.kernel_initializer,
- name='kernel',
- regularizer=self.kernel_regularizer,
- constraint=self.kernel_constraint)
- if self.use_bias:
- self.bias = self.add_weight(shape=(self.units, self.channels),
- initializer=self.bias_initializer,
- name='bias',
- regularizer=self.bias_regularizer,
- constraint=self.bias_constraint)
- else:
- self.bias = None
- self.factor = self.add_weight(shape=(self.units, self.channels),
- initializer='ones',
- name='factor',
- regularizer=self.bias_regularizer,
- constraint=self.bias_constraint)
- self.input_spec = InputSpec(min_ndim=2, axes={-1: input_dim})
- self.built = True
-
- def call(self, inputs):
- output = K.dot(inputs, self.kernel)
- if self.use_bias:
- output = output + self.bias
- output = K.tanh(output) * self.factor
- output = K.sum(output, axis=-1)
- if self.activation is not None:
- output = self.activation(output)
- return output
-
- def compute_output_shape(self, input_shape):
- assert input_shape and len(input_shape) >= 2
- assert input_shape[-1]
- output_shape = list(input_shape)
- output_shape[-1] = self.units
- return tuple(output_shape)
-
- def get_config(self):
- config = {
- 'units': self.units,
- 'activation': activations.serialize(self.activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
- 'activity_regularizer': regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint)
- }
- base_config = super(MDense, self).get_config()
- return dict(list(base_config.items()) + list(config.items()))
--- a/dnn/test_lpcnet.py
+++ /dev/null
@@ -1,106 +1,0 @@
-#!/usr/bin/python3
-'''Copyright (c) 2018 Mozilla
-
- 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.
-'''
-
-import lpcnet
-import sys
-import numpy as np
-from keras.optimizers import Adam
-from keras.callbacks import ModelCheckpoint
-from ulaw import ulaw2lin, lin2ulaw
-import keras.backend as K
-import h5py
-
-import tensorflow as tf
-from keras.backend.tensorflow_backend import set_session
-config = tf.ConfigProto()
-config.gpu_options.per_process_gpu_memory_fraction = 0.2
-set_session(tf.Session(config=config))
-
-model, enc, dec = lpcnet.new_lpcnet_model(use_gpu=False)
-
-model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
-#model.summary()
-
-feature_file = sys.argv[1]
-out_file = sys.argv[2]
-frame_size = model.frame_size
-nb_features = 55
-nb_used_features = model.nb_used_features
-
-features = np.fromfile(feature_file, dtype='float32')
-features = np.resize(features, (-1, nb_features))
-nb_frames = 1
-feature_chunk_size = features.shape[0]
-pcm_chunk_size = frame_size*feature_chunk_size
-
-features = np.reshape(features, (nb_frames, feature_chunk_size, nb_features))
-features[:,:,18:36] = 0
-periods = (.1 + 50*features[:,:,36:37]+100).astype('int16')
-
-
-
-model.load_weights('lpcnet20h_384_10_G16_80.h5')
-
-order = 16
-
-pcm = np.zeros((nb_frames*pcm_chunk_size, ))
-fexc = np.zeros((1, 1, 3), dtype='int16')+128
-state1 = np.zeros((1, model.rnn_units1), dtype='float32')
-state2 = np.zeros((1, model.rnn_units2), dtype='float32')
-
-mem = 0
-coef = 0.85
-
-fout = open(out_file, 'wb')
-
-skip = order + 1
-for c in range(0, nb_frames):
- cfeat = enc.predict([features[c:c+1, :, :nb_used_features], periods[c:c+1, :, :]])
- for fr in range(0, feature_chunk_size):
- f = c*feature_chunk_size + fr
- a = features[c, fr, nb_features-order:]
- for i in range(skip, frame_size):
- pred = -sum(a*pcm[f*frame_size + i - 1:f*frame_size + i - order-1:-1])
- fexc[0, 0, 1] = lin2ulaw(pred)
-
- p, state1, state2 = dec.predict([fexc, cfeat[:, fr:fr+1, :], state1, state2])
- #Lower the temperature for voiced frames to reduce noisiness
- p *= np.power(p, np.maximum(0, 1.5*features[c, fr, 37] - .5))
- p = p/(1e-18 + np.sum(p))
- #Cut off the tail of the remaining distribution
- p = np.maximum(p-0.002, 0).astype('float64')
- p = p/(1e-8 + np.sum(p))
-
- fexc[0, 0, 2] = np.argmax(np.random.multinomial(1, p[0,0,:], 1))
- pcm[f*frame_size + i] = pred + ulaw2lin(fexc[0, 0, 2])
- fexc[0, 0, 0] = lin2ulaw(pcm[f*frame_size + i])
- mem = coef*mem + pcm[f*frame_size + i]
- #print(mem)
- np.array([np.round(mem)], dtype='int16').tofile(fout)
- skip = 0
-
-
--- a/dnn/train_lpcnet.py
+++ /dev/null
@@ -1,125 +1,0 @@
-#!/usr/bin/python3
-'''Copyright (c) 2018 Mozilla
-
- 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.
-'''
-
-# Train a LPCNet model (note not a Wavenet model)
-
-import lpcnet
-import sys
-import numpy as np
-from keras.optimizers import Adam
-from keras.callbacks import ModelCheckpoint
-from ulaw import ulaw2lin, lin2ulaw
-import keras.backend as K
-import h5py
-
-import tensorflow as tf
-from keras.backend.tensorflow_backend import set_session
-config = tf.ConfigProto()
-
-# use this option to reserve GPU memory, e.g. for running more than
-# one thing at a time. Best to disable for GPUs with small memory
-config.gpu_options.per_process_gpu_memory_fraction = 0.44
-
-set_session(tf.Session(config=config))
-
-nb_epochs = 120
-
-# Try reducing batch_size if you run out of memory on your GPU
-batch_size = 64
-
-model, _, _ = lpcnet.new_lpcnet_model(training=True)
-
-model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
-model.summary()
-
-feature_file = sys.argv[1]
-pcm_file = sys.argv[2] # 16 bit unsigned short PCM samples
-frame_size = model.frame_size
-nb_features = 55
-nb_used_features = model.nb_used_features
-feature_chunk_size = 15
-pcm_chunk_size = frame_size*feature_chunk_size
-
-# u for unquantised, load 16 bit PCM samples and convert to mu-law
-
-data = np.fromfile(pcm_file, dtype='uint8')
-nb_frames = len(data)//(4*pcm_chunk_size)
-
-features = np.fromfile(feature_file, dtype='float32')
-
-# limit to discrete number of frames
-data = data[:nb_frames*4*pcm_chunk_size]
-features = features[:nb_frames*feature_chunk_size*nb_features]
-
-features = np.reshape(features, (nb_frames*feature_chunk_size, nb_features))
-
-sig = np.reshape(data[0::4], (nb_frames, pcm_chunk_size, 1))
-pred = np.reshape(data[1::4], (nb_frames, pcm_chunk_size, 1))
-in_exc = np.reshape(data[2::4], (nb_frames, pcm_chunk_size, 1))
-out_exc = np.reshape(data[3::4], (nb_frames, pcm_chunk_size, 1))
-del data
-
-print("ulaw std = ", np.std(out_exc))
-
-features = np.reshape(features, (nb_frames, feature_chunk_size, nb_features))
-features = features[:, :, :nb_used_features]
-features[:,:,18:36] = 0
-
-fpad1 = np.concatenate([features[0:1, 0:2, :], features[:-1, -2:, :]], axis=0)
-fpad2 = np.concatenate([features[1:, :2, :], features[0:1, -2:, :]], axis=0)
-features = np.concatenate([fpad1, features, fpad2], axis=1)
-
-
-periods = (.1 + 50*features[:,:,36:37]+100).astype('int16')
-
-in_data = np.concatenate([sig, pred, in_exc], axis=-1)
-
-del sig
-del pred
-del in_exc
-
-# dump models to disk as we go
-checkpoint = ModelCheckpoint('lpcnet30_384_10_G16_{epoch:02d}.h5')
-
-#Set this to True to adapt an existing model (e.g. on new data)
-adaptation = False
-
-if adaptation:
- #Adapting from an existing model
- model.load_weights('lpcnet24c_384_10_G16_120.h5')
- sparsify = lpcnet.Sparsify(0, 0, 1, (0.05, 0.05, 0.2))
- lr = 0.0001
- decay = 0
-else:
- #Training from scratch
- sparsify = lpcnet.Sparsify(2000, 40000, 400, (0.05, 0.05, 0.2))
- lr = 0.001
- decay = 5e-5
-
-model.compile(optimizer=Adam(lr, amsgrad=True, decay=decay), loss='sparse_categorical_crossentropy')
-model.save_weights('lpcnet30_384_10_G16_00.h5');
-model.fit([in_data, features, periods], out_exc, batch_size=batch_size, epochs=nb_epochs, validation_split=0.0, callbacks=[checkpoint, sparsify])
--- /dev/null
+++ b/dnn/training_tf2/test_lpcnet.py
@@ -1,0 +1,98 @@
+#!/usr/bin/python3
+'''Copyright (c) 2018 Mozilla
+
+ 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.
+'''
+
+import lpcnet
+import sys
+import numpy as np
+from ulaw import ulaw2lin, lin2ulaw
+import h5py
+
+
+model, enc, dec = lpcnet.new_lpcnet_model()
+
+model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
+#model.summary()
+
+feature_file = sys.argv[1]
+out_file = sys.argv[2]
+frame_size = model.frame_size
+nb_features = 55
+nb_used_features = model.nb_used_features
+
+features = np.fromfile(feature_file, dtype='float32')
+features = np.resize(features, (-1, nb_features))
+nb_frames = 1
+feature_chunk_size = features.shape[0]
+pcm_chunk_size = frame_size*feature_chunk_size
+
+features = np.reshape(features, (nb_frames, feature_chunk_size, nb_features))
+features[:,:,18:36] = 0
+periods = (.1 + 50*features[:,:,36:37]+100).astype('int16')
+
+
+
+model.load_weights('lpcnet34bq17_384_01.h5')
+
+order = 16
+
+pcm = np.zeros((nb_frames*pcm_chunk_size, ))
+fexc = np.zeros((1, 1, 3), dtype='int16')+128
+state1 = np.zeros((1, model.rnn_units1), dtype='float32')
+state2 = np.zeros((1, model.rnn_units2), dtype='float32')
+
+mem = 0
+coef = 0.85
+
+fout = open(out_file, 'wb')
+
+skip = order + 1
+for c in range(0, nb_frames):
+ cfeat = enc.predict([features[c:c+1, :, :nb_used_features], periods[c:c+1, :, :]])
+ for fr in range(0, feature_chunk_size):
+ f = c*feature_chunk_size + fr
+ a = features[c, fr, nb_features-order:]
+ for i in range(skip, frame_size):
+ pred = -sum(a*pcm[f*frame_size + i - 1:f*frame_size + i - order-1:-1])
+ fexc[0, 0, 1] = lin2ulaw(pred)
+
+ p, state1, state2 = dec.predict([fexc, cfeat[:, fr:fr+1, :], state1, state2])
+ #Lower the temperature for voiced frames to reduce noisiness
+ p *= np.power(p, np.maximum(0, 1.5*features[c, fr, 37] - .5))
+ p = p/(1e-18 + np.sum(p))
+ #Cut off the tail of the remaining distribution
+ p = np.maximum(p-0.002, 0).astype('float64')
+ p = p/(1e-8 + np.sum(p))
+
+ fexc[0, 0, 2] = np.argmax(np.random.multinomial(1, p[0,0,:], 1))
+ pcm[f*frame_size + i] = pred + ulaw2lin(fexc[0, 0, 2])
+ fexc[0, 0, 0] = lin2ulaw(pcm[f*frame_size + i])
+ mem = coef*mem + pcm[f*frame_size + i]
+ #print(mem)
+ np.array([np.round(mem)], dtype='int16').tofile(fout)
+ skip = 0
+
+
--- a/dnn/ulaw.py
+++ /dev/null
@@ -1,19 +1,0 @@
-
-import numpy as np
-import math
-
-scale = 255.0/32768.0
-scale_1 = 32768.0/255.0
-def ulaw2lin(u):
- u = u - 128
- s = np.sign(u)
- u = np.abs(u)
- return s*scale_1*(np.exp(u/128.*math.log(256))-1)
-
-
-def lin2ulaw(x):
- s = np.sign(x)
- x = np.abs(x)
- u = (s*(128*np.log(1+scale*x)/math.log(256)))
- u = np.clip(128 + np.round(u), 0, 255)
- return u.astype('int16')
--
⑨