shithub: opus

Download patch

ref: 144b7311bc84ff4985b692642a633fb29f990b81
parent: a3ef5968222befeca0619c5ce7eda4a42332b88b
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Wed Oct 13 19:18:57 EDT 2021

Dumping 16-bit linear training data

--- a/dnn/dump_data.c
+++ b/dnn/dump_data.c
@@ -75,10 +75,10 @@
 }
 
 
-void write_audio(LPCNetEncState *st, const short *pcm, const int *noise, FILE *file, int nframes, int e2e) {
+void write_audio(LPCNetEncState *st, const short *pcm, const int *noise, FILE *file, int nframes) {
   int i, k;
   for (k=0;k<nframes;k++) {
-  unsigned char data[4*FRAME_SIZE];
+  short data[2*FRAME_SIZE];
   for (i=0;i<FRAME_SIZE;i++) {
     float p=0;
     float e;
@@ -85,18 +85,10 @@
     int j;
     for (j=0;j<LPC_ORDER;j++) p -= st->features[k][NB_BANDS+2+j]*st->sig_mem[j];
     e = lin2ulaw(pcm[k*FRAME_SIZE+i] - p);
-    /* Signal. */
-    data[4*i] = lin2ulaw(st->sig_mem[0]);
-    /* Prediction. */
-    data[4*i+1] = lin2ulaw(p);
-    /* Excitation in. */
-    data[4*i+2] = st->exc_mem;
-    /* Excitation out. */
-    if (e2e) {
-      data[4*i+3] = lin2ulaw(pcm[k*FRAME_SIZE+i]);
-    } else {
-      data[4*i+3] = e;
-    }
+    /* Signal in. */
+    data[2*i] = st->sig_mem[0];
+    /* Signal out. */
+    data[2*i+1] = pcm[k*FRAME_SIZE+i];
     /* Simulate error on excitation. */
     e += noise[k*FRAME_SIZE+i];
     e = IMIN(255, IMAX(0, e));
@@ -119,7 +111,6 @@
 int main(int argc, char **argv) {
   int i;
   char *argv0;
-  int e2e=0;
   int count=0;
   static const float a_hp[2] = {-1.99599, 0.99600};
   static const float b_hp[2] = {-2, 1};
@@ -151,11 +142,6 @@
   srand(getpid());
   st = lpcnet_encoder_create();
   argv0=argv[0];
-  if (argc > 2 && strcmp(argv[1], "-end2end")==0) {
-      e2e = 1;
-      argv++;
-      argc--;
-  }
   if (argc == 5 && strcmp(argv[1], "-train")==0) training = 1;
   if (argc == 5 && strcmp(argv[1], "-qtrain")==0) {
       training = 1;
@@ -281,7 +267,7 @@
     
     if (!quantize) {
       process_single_frame(st, ffeat);
-      if (fpcm) write_audio(st, pcm, &noisebuf[st->pcount*FRAME_SIZE], fpcm, 1, e2e);
+      if (fpcm) write_audio(st, pcm, &noisebuf[st->pcount*FRAME_SIZE], fpcm, 1);
     }
     st->pcount++;
     /* Running on groups of 4 frames. */
@@ -289,7 +275,7 @@
       if (quantize) {
         unsigned char buf[8];
         process_superframe(st, buf, ffeat, encode, quantize);
-        if (fpcm) write_audio(st, pcmbuf, noisebuf, fpcm, 4, e2e);
+        if (fpcm) write_audio(st, pcmbuf, noisebuf, fpcm, 4);
       }
       st->pcount = 0;
     }
--- a/dnn/training_tf2/dataloader.py
+++ b/dnn/training_tf2/dataloader.py
@@ -1,5 +1,6 @@
 import numpy as np
 from tensorflow.keras.utils import Sequence
+from ulaw import lin2ulaw
 
 def lpc2rc(lpc):
     #print("shape is = ", lpc.shape)
@@ -12,13 +13,13 @@
     return rc
 
 class LPCNetLoader(Sequence):
-    def __init__(self, data, features, periods, batch_size, lpc_out=False):
+    def __init__(self, data, features, periods, batch_size, e2e=False):
         self.batch_size = batch_size
         self.nb_batches = np.minimum(np.minimum(data.shape[0], features.shape[0]), periods.shape[0])//self.batch_size
         self.data = data[:self.nb_batches*self.batch_size, :]
         self.features = features[:self.nb_batches*self.batch_size, :]
         self.periods = periods[:self.nb_batches*self.batch_size, :]
-        self.lpc_out = lpc_out
+        self.e2e = e2e
         self.on_epoch_end()
 
     def on_epoch_end(self):
@@ -27,15 +28,18 @@
 
     def __getitem__(self, index):
         data = self.data[self.indices[index*self.batch_size:(index+1)*self.batch_size], :, :]
-        in_data = data[: , :, :3]
-        out_data = data[: , :, 3:4]
+        in_data = data[: , :, :1]
+        out_data = data[: , :, 1:]
         features = self.features[self.indices[index*self.batch_size:(index+1)*self.batch_size], :, :-16]
         periods = self.periods[self.indices[index*self.batch_size:(index+1)*self.batch_size], :, :]
         outputs = [out_data]
-        if self.lpc_out:
-            lpc = self.features[self.indices[index*self.batch_size:(index+1)*self.batch_size], 2:-2, -16:]
+        inputs = [in_data, features, periods]
+        lpc = self.features[self.indices[index*self.batch_size:(index+1)*self.batch_size], 2:-2, -16:]
+        if self.e2e:
             outputs.append(lpc2rc(lpc))
-        return ([in_data, features, periods], outputs)
+        else:
+            inputs.append(lpc)
+        return (inputs, outputs)
 
     def __len__(self):
         return self.nb_batches
--- a/dnn/training_tf2/dump_lpcnet.py
+++ b/dnn/training_tf2/dump_lpcnet.py
@@ -252,7 +252,7 @@
     cond_size = min(f['model_weights']['feature_dense1']['feature_dense1']['kernel:0'].shape)
     e2e = 'rc2lpc' in f['model_weights']
 
-model, _, _ = lpcnet.new_lpcnet_model(rnn_units1=units, rnn_units2=units2, flag_e2e = flag_e2e, cond_size=cond_size)
+model, _, _ = lpcnet.new_lpcnet_model(rnn_units1=units, rnn_units2=units2, flag_e2e = e2e, cond_size=cond_size)
 model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['sparse_categorical_accuracy'])
 #model.summary()
 
--- a/dnn/training_tf2/lossfuncs.py
+++ b/dnn/training_tf2/lossfuncs.py
@@ -12,7 +12,7 @@
     def loss(y_true,y_pred):
         p = y_pred[:,:,0:1]
         model_out = y_pred[:,:,1:]
-        e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+        e_gt = tf_l2u(y_true - p)
         e_gt = tf.round(e_gt)
         e_gt = tf.cast(e_gt,'int32')
         sparse_cel = tf.keras.losses.SparseCategoricalCrossentropy(reduction=tf.keras.losses.Reduction.NONE)(e_gt,model_out)
@@ -24,9 +24,10 @@
 # Also adds a probability compensation (to account for matching cross entropy in the linear domain), weighted by gamma
 def interp_mulaw(gamma = 1):
     def loss(y_true,y_pred):
+        y_true = tf.cast(y_true, 'float32')
         p = y_pred[:,:,0:1]
         model_out = y_pred[:,:,1:]
-        e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+        e_gt = tf_l2u(y_true - p)
         prob_compensation = tf.squeeze((K.abs(e_gt - 128)/128.0)*K.log(256.0))
         alpha = e_gt - tf.math.floor(e_gt)
         alpha = tf.tile(alpha,[1,1,256])
@@ -42,7 +43,7 @@
 def metric_oginterploss(y_true,y_pred):
     p = y_pred[:,:,0:1]
     model_out = y_pred[:,:,1:]
-    e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+    e_gt = tf_l2u(y_true - p)
     prob_compensation = tf.squeeze((K.abs(e_gt - 128)/128.0)*K.log(256.0))
     alpha = e_gt - tf.math.floor(e_gt)
     alpha = tf.tile(alpha,[1,1,256])
@@ -57,7 +58,7 @@
 def metric_icel(y_true, y_pred):
     p = y_pred[:,:,0:1]
     model_out = y_pred[:,:,1:]
-    e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+    e_gt = tf_l2u(y_true - p)
     alpha = e_gt - tf.math.floor(e_gt)
     alpha = tf.tile(alpha,[1,1,256])
     e_gt = tf.cast(e_gt,'int32')
@@ -68,9 +69,10 @@
 
 # Non-interpolated (rounded) cross entropy loss metric
 def metric_cel(y_true, y_pred):
+    y_true = tf.cast(y_true, 'float32')
     p = y_pred[:,:,0:1]
     model_out = y_pred[:,:,1:]
-    e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+    e_gt = tf_l2u(y_true - p)
     e_gt = tf.round(e_gt)
     e_gt = tf.cast(e_gt,'int32')
     e_gt = tf.clip_by_value(e_gt,0,255) 
@@ -80,7 +82,7 @@
 # Variance metric of the output excitation
 def metric_exc_sd(y_true,y_pred):
     p = y_pred[:,:,0:1]
-    e_gt = tf_l2u(tf_u2l(y_true) - tf_u2l(p))
+    e_gt = tf_l2u(y_true - p)
     sd_egt = tf.keras.losses.MeanSquaredError(reduction=tf.keras.losses.Reduction.NONE)(e_gt,128)
     return sd_egt
 
--- a/dnn/training_tf2/lpcnet.py
+++ b/dnn/training_tf2/lpcnet.py
@@ -230,8 +230,9 @@
 
 constraint = WeightClip(0.992)
 
-def new_lpcnet_model(rnn_units1=384, rnn_units2=16, nb_used_features=20, batch_size=128, training=False, adaptation=False, quantize=False, flag_e2e = False, cond_size=128):
-    pcm = Input(shape=(None, 3), batch_size=batch_size)
+def new_lpcnet_model(rnn_units1=384, rnn_units2=16, nb_used_features=20, batch_size=128, training=False, adaptation=False, quantize=False, flag_e2e = False, cond_size=128, lpc_order=16):
+    pcm = Input(shape=(None, 1), batch_size=batch_size)
+    dpcm = Input(shape=(None, 3), batch_size=batch_size)
     feat = Input(shape=(None, nb_used_features), batch_size=batch_size)
     pitch = Input(shape=(None, 1), batch_size=batch_size)
     dec_feat = Input(shape=(None, cond_size))
@@ -257,20 +258,19 @@
 
     cfeat = fdense2(fdense1(cfeat))
 
-    if not flag_e2e:
-        embed = Embedding(256, embed_size, embeddings_initializer=PCMInit(), name='embed_sig')
-        cpcm = Reshape((-1, embed_size*3))(embed(pcm))
-    else:
-        Input_extractor = Lambda(lambda x: K.expand_dims(x[0][:,:,x[1]],axis = -1))
-        error_calc = Lambda(lambda x: tf_l2u(tf_u2l(x[0]) - tf.roll(tf_u2l(x[1]),1,axis = 1)))
+    Input_extractor = Lambda(lambda x: K.expand_dims(x[0][:,:,x[1]],axis = -1))
+    error_calc = Lambda(lambda x: tf_l2u(x[0] - tf.roll(x[1],1,axis = 1)))
+    if flag_e2e:
         lpcoeffs = diff_rc2lpc(name = "rc2lpc")(cfeat)
-        tensor_preds = diff_pred(name = "lpc2preds")([Input_extractor([pcm,0]),lpcoeffs])
-        past_errors = error_calc([Input_extractor([pcm,0]),tensor_preds])
-        embed = diff_Embed(name='embed_sig',initializer = PCMInit())
-        cpcm = Concatenate()([Input_extractor([pcm,0]),tensor_preds,past_errors])
-        cpcm = Reshape((-1, embed_size*3))(embed(cpcm))
-        cpcm_decoder = Concatenate()([Input_extractor([pcm,0]),Input_extractor([pcm,1]),Input_extractor([pcm,2])])
-        cpcm_decoder = Reshape((-1, embed_size*3))(embed(cpcm_decoder))
+    else:
+        lpcoeffs = Input(shape=(None, lpc_order), batch_size=batch_size)
+    tensor_preds = diff_pred(name = "lpc2preds")([Input_extractor([pcm,0]),lpcoeffs])
+    past_errors = error_calc([Input_extractor([pcm,0]),tensor_preds])
+    embed = diff_Embed(name='embed_sig',initializer = PCMInit())
+    cpcm = Concatenate()([tf_l2u(Input_extractor([pcm,0])),tf_l2u(tensor_preds),past_errors])
+    cpcm = Reshape((-1, embed_size*3))(embed(cpcm))
+    cpcm_decoder = Concatenate()([Input_extractor([dpcm,0]),Input_extractor([dpcm,1]),Input_extractor([dpcm,2])])
+    cpcm_decoder = Reshape((-1, embed_size*3))(embed(cpcm_decoder))
 
     
     rep = Lambda(lambda x: K.repeat_elements(x, frame_size, 1))
@@ -301,10 +301,10 @@
         md.trainable=False
         embed.Trainable=False
     
+    m_out = Concatenate(name='pdf')([tensor_preds,ulaw_prob])
     if not flag_e2e:
-        model = Model([pcm, feat, pitch], ulaw_prob)
+        model = Model([pcm, feat, pitch, lpcoeffs], m_out)
     else:
-        m_out = Concatenate(name='pdf')([tensor_preds,ulaw_prob])
         model = Model([pcm, feat, pitch], [m_out, cfeat])
     model.rnn_units1 = rnn_units1
     model.rnn_units2 = rnn_units2
@@ -321,5 +321,8 @@
     dec_gru_out2, state2 = rnn2(Concatenate()([dec_gru_out1, dec_feat]), initial_state=dec_state2)
     dec_ulaw_prob = Lambda(tree_to_pdf_infer)(md(dec_gru_out2))
 
-    decoder = Model([pcm, dec_feat, dec_state1, dec_state2], [dec_ulaw_prob, state1, state2])
+    if flag_e2e:
+        decoder = Model([dpcm, dec_feat, dec_state1, dec_state2], [dec_ulaw_prob, state1, state2])
+    else:
+        decoder = Model([pcm, dec_feat, dec_state1, dec_state2, lpcoeffs], [dec_ulaw_prob, state1, state2])
     return model, encoder, decoder
--- a/dnn/training_tf2/tf_funcs.py
+++ b/dnn/training_tf2/tf_funcs.py
@@ -30,7 +30,7 @@
 # The inputs xt and lpc conform with the shapes in lpcnet.py (the '2400' is coded keeping this in mind)
 class diff_pred(Layer):
     def call(self, inputs, lpcoeffs_N = 16, frame_size = 160):
-        xt = tf_u2l(inputs[0])
+        xt = inputs[0]
         lpc = inputs[1]
 
         rept = Lambda(lambda x: K.repeat_elements(x , frame_size, 1))
@@ -39,7 +39,7 @@
         
         pred = -Multiply()([rept(lpc),cX(zpX(xt))])
 
-        return tf_l2u(K.sum(pred,axis = 2,keepdims = True))
+        return K.sum(pred,axis = 2,keepdims = True)
 
 # Differentiable Transformations (RC <-> LPC) computed using the Levinson Durbin Recursion 
 class diff_rc2lpc(Layer):
--- a/dnn/training_tf2/train_lpcnet.py
+++ b/dnn/training_tf2/train_lpcnet.py
@@ -125,7 +125,7 @@
 with strategy.scope():
     model, _, _ = lpcnet.new_lpcnet_model(rnn_units1=args.grua_size, rnn_units2=args.grub_size, batch_size=batch_size, training=True, quantize=quantize, flag_e2e = flag_e2e, cond_size=args.cond_size)
     if not flag_e2e:
-        model.compile(optimizer=opt, loss='sparse_categorical_crossentropy', metrics='sparse_categorical_crossentropy')
+        model.compile(optimizer=opt, loss=metric_cel, metrics=metric_cel)
     else:
         model.compile(optimizer=opt, loss = [interp_mulaw(gamma=gamma), loss_matchlar()], loss_weights = [1.0, 2.0], metrics={'pdf':[metric_cel,metric_icel,metric_exc_sd,metric_oginterploss]})
     model.summary()
@@ -140,19 +140,17 @@
 
 # u for unquantised, load 16 bit PCM samples and convert to mu-law
 
-data = np.memmap(pcm_file, dtype='uint8', mode='r')
-nb_frames = (len(data)//(4*pcm_chunk_size)-1)//batch_size*batch_size
+data = np.memmap(pcm_file, dtype='int16', mode='r')
+nb_frames = (len(data)//(2*pcm_chunk_size)-1)//batch_size*batch_size
 
 features = np.memmap(feature_file, dtype='float32', mode='r')
 
 # limit to discrete number of frames
-data = data[4*2*frame_size:]
-data = data[:nb_frames*4*pcm_chunk_size]
+data = data[2*2*frame_size:]
+data = data[:nb_frames*2*pcm_chunk_size]
 
 
-data = np.reshape(data, (nb_frames, pcm_chunk_size, 4))
-#in_data = data[:,:,:3]
-#out_exc = data[:,:,3:4]
+data = np.reshape(data, (nb_frames, pcm_chunk_size, 2))
 
 #print("ulaw std = ", np.std(out_exc))
 
@@ -187,7 +185,7 @@
 
 model.save_weights('{}_{}_initial.h5'.format(args.output, args.grua_size))
 
-loader = LPCNetLoader(data, features, periods, batch_size, lpc_out=flag_e2e)
+loader = LPCNetLoader(data, features, periods, batch_size, e2e=flag_e2e)
 
 callbacks = [checkpoint, sparsify, grub_sparsify]
 if args.logdir is not None:
--