Getting error when building audio classification firmware for Nicla Voice board

Project ID:
363328

Context/Use case:
I’m following the example RC project to deploy an audio classification model to my Nicla Voice board. All the steps are exactly the same, except that I modified the model in expert mode (specifically, I replaced the 2-cov model with a MobileNet V2 alpha 0.1 model). Here is my modified code block:

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, InputLayer, Dropout, Conv1D, Conv2D, Flatten, Reshape, MaxPooling1D, MaxPooling2D, AveragePooling2D, BatchNormalization, Permute, ReLU, Softmax
from tensorflow.keras.optimizers.legacy import Adam

import math, requests
from tensorflow.keras import Model
from tensorflow.keras.layers import (
    Dense, InputLayer, Dropout, Conv1D, Flatten, Reshape, MaxPooling1D, BatchNormalization,
    Conv2D, GlobalMaxPooling2D, Lambda, GlobalAveragePooling2D)
from tensorflow.keras.optimizers.legacy import Adam, Adadelta
from tensorflow.keras.losses import categorical_crossentropy

EPOCHS = args.epochs or 150
LEARNING_RATE = args.learning_rate or 0.002
# If True, non-deterministic functions (e.g. shuffling batches) are not used.
# This is False by default.
ENSURE_DETERMINISM = args.ensure_determinism
# this controls the batch size, or you can manipulate the tf.data.Dataset objects yourself
BATCH_SIZE = args.batch_size or 32
if not ENSURE_DETERMINISM:
    train_dataset = train_dataset.shuffle(buffer_size=BATCH_SIZE*4)
train_dataset=train_dataset.batch(BATCH_SIZE, drop_remainder=False)
validation_dataset = validation_dataset.batch(BATCH_SIZE, drop_remainder=False)

channels = 1
columns = 40
rows = int(input_length / (columns * channels))
INPUT_SHAPE = (rows, columns, channels)

base_model = tf.keras.applications.MobileNetV2(
    input_shape = INPUT_SHAPE, alpha=0.1,
    weights = None
)
base_model.trainable = True

model = Sequential()

model.add(Reshape(INPUT_SHAPE, input_shape=(input_length, )))
model.add(Permute((2,1,3))) # H and W are reversed for NDP120 Conv 2D input

model.add(InputLayer(input_shape=INPUT_SHAPE, name='x_input'))
last_layer_index = -3
model.add(Model(inputs=base_model.inputs, outputs=base_model.layers[last_layer_index].output))
model.add(Reshape((-1, model.layers[-1].output.shape[3])))
model.add(Dense(8, activation='relu'))
model.add(Dropout(0.1))
model.add(Flatten())
model.add(Dense(classes, activation='softmax'))

# this controls the learning rate
opt = Adam(learning_rate=LEARNING_RATE, beta_1=0.9, beta_2=0.999)
callbacks.append(BatchLoggerCallback(BATCH_SIZE, train_sample_count, epochs=EPOCHS, ensure_determinism=ENSURE_DETERMINISM))

# # train the neural network
# model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
    
# model.fit(train_dataset, epochs=EPOCHS, validation_data=validation_dataset, verbose=2, callbacks=callbacks)

model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
                loss='categorical_crossentropy',
                metrics=['accuracy'])
model.fit(train_dataset, validation_data=validation_dataset, epochs=EPOCHS, verbose=2, callbacks=callbacks)


# Use this flag to disable per-channel quantization for a model.
# This can reduce RAM usage for convolutional models, but may have
# an impact on accuracy.
disable_per_channel_quantization = False

Error:
After training the model for 150 epochs, I got good precisions. However, when I tried to build the firmware, I got the error output below:

Creating job... OK (ID: 17614803)

Scheduling job in cluster...
Container image pulled!
Job started
Writing templates OK

Scheduling job in cluster...
Container image pulled!
Job started
Removing clutter...
Removing clutter OK

Copying output...
Copying output OK

Scheduling job in cluster...
Container image pulled!
Job started
generate_synpkg for NDP120
Extracting model...
Extracting model OK

Found Audio block
Loading neural network...
Loading neural network OK

Loading data set...
Loading data set OK, found 3232 items

Converting sequential model to functional API...
Reshape layer detected
(None, 40, 40, 1)
Skipping Permute layer
Reshape layer detected
(None, 4, 1280)
Traceback (most recent call last):
  File "/app/generate_synpkg.py", line 206, in <module>
    print('Reshape layer should contain 40 columns', e, flush=True)
NameError: name 'e' is not defined
Application exited with code 1
Job failed (see above)

I’m not super familiar with Syntiant, but it seems to be coupled tightly with Edge Impulse. For example, I could not find the generate_synpkg.py file anywhere. In this case, I really wish to get help from you.

Guess:
I noticed that there is a comment in your expert mode of model code block: # Syntiant TDK supports only valid padding. I’m just guessing randomly, but could this be the reason for the error?

Hello @xinyew,

Can you confirm that you are following this tutorial:
Responding to your voice - Syntiant - RC Commands | Edge Impulse Documentation.

Also, can you make sure you used the DSP Audio (Syntiant) block:

And lastly, looking at the error you have:

Traceback (most recent call last):
File “/app/generate_synpkg.py”, line 206, in
print(‘Reshape layer should contain 40 columns’, e, flush=True)

It seems the issue comes from your Reshape layers.

Best,

Louis

Yes, I’m following the tutorial from the link that you provided and I’m also using the right DSP block with the same configuration in the tutorial.
I’ve modified my model to this and got rid of the reshape issue:

base_model = tf.keras.applications.MobileNetV2(
    input_shape = INPUT_SHAPE, alpha=0.1,
    weights = None
)
base_model.trainable = True

model = Sequential()

model.add(Reshape((rows, columns, channels), input_shape=(input_length, )))
model.add(Permute((2,1,3))) # H and W are reversed for NDP120 Conv 2D input

last_layer_index = -3
model.add(Model(inputs=base_model.inputs, outputs=base_model.layers[last_layer_index].output))

model.add(Flatten())
model.add(Dense(classes, activation='softmax'))

But I still get some error:

Creating job... OK (ID: 17637976)

Scheduling job in cluster...
Container image pulled!
Job started
Writing templates OK

Scheduling job in cluster...
Container image pulled!
Job started
Removing clutter...
Removing clutter OK

Copying output...
Copying output OK

Scheduling job in cluster...
Container image pulled!
Job started
generate_synpkg for NDP120
Extracting model...
Extracting model OK

Found Audio block
Loading neural network...
Loading neural network OK

Loading data set...
Loading data set OK, found 3232 items

Converting sequential model to functional API...
Reshape layer detected
(None, 40, 40, 1)
Skipping Permute layer
Converting sequential model to functional API OK
Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_3 (InputLayer)        [(None, 40, 40, 1)]       0         
                                                                 
 model (Functional)          (None, 2, 2, 1280)        93168     
                                                                 
 flatten (Flatten)           (None, 5120)              0         
                                                                 
 dense (Dense)               (None, 12)                61452     
                                                                 
=================================================================
Total params: 154,620
Trainable params: 147,388
Non-trainable params: 7,232
_________________________________________________________________
Copying output OK

Attached to job 17637976...
Attached to job 17637976...

Keras functional score (loss: 0.8101733326911926, accuracy: 0.791769802570343

Converting Keras model to Syntiant format...
Traceback (most recent call last):
  File "/app/generate_synpkg.py", line 242, in <module>
    fl_model, model = convertKerasToSyntiant(ei_model_func, x_eval=x_eval_subset, chip="NDP120_B0")
  File "/usr/local/lib/python3.8/site-packages/syntiant_networks/experimental/model_converter.py", line 80, in convertKerasToSyntiant
    syntiant_float_model = converter.convert_model_from_sample_input(x_eval)
  File "/usr/local/lib/python3.8/site-packages/syntiant_networks/experimental/model_converter.py", line 287, in convert_model_from_sample_input
    ma = ModelAnalyzer(self._build_tf_model_from_graph(graph))
  File "/usr/local/lib/python3.8/site-packages/syntiant_networks/experimental/model_analyzer.py", line 37, in __init__
    model if isinstance(model, PartialModel) else PartialModel(model)
  File "/usr/local/lib/python3.8/site-packages/syntiant_networks/experimental/partial_model.py", line 43, in __init__
    self.partial_models = self._get_partial_model(
  File "/usr/local/lib/python3.8/site-packages/syntiant_networks/experimental/partial_model.py", line 121, in _get_partial_model
    partial_models[layer.name] = tf.keras.Model(inputs, outputs, **model_kwargs)
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/training/tracking/base.py", line 530, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/keras/engine/functional.py", line 146, in __init__
    self._init_graph_network(inputs, outputs)
  File "/usr/local/lib/python3.8/site-packages/tensorflow/python/training/tracking/base.py", line 530, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/keras/engine/functional.py", line 229, in _init_graph_network
    nodes, nodes_by_depth, layers, _ = _map_graph_network(
  File "/usr/local/lib/python3.8/site-packages/keras/engine/functional.py", line 1036, in _map_graph_network
    raise ValueError(
ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(type_spec=TensorSpec(shape=(None, 40, 40, 1), dtype=tf.float32, name='input_1'), name='input_1', description="created by layer 'input_1'") at layer "Conv1". The following previous layers were accessed without issue: []
Application exited with code 1
Job failed (see above)

Do you know what should I do to get it work?