AkidaNet/ImageNet inference

This CNN2SNN tutorial presents how to convert an AkidaNet pre-trained model into Akida.

As ImageNet images are not publicly available, performances are assessed using a set of 10 copyright free images that were found on Google using ImageNet class names.

1. Dataset preparation

Test images all have at least 256 pixels in the smallest dimension. They must be preprocessed to fit in the model. The imagenet.preprocessing.resize_and_crop function decodes, crops and extracts a square 224x224x3 patch from an input image.

Note

Input size is here set to 224x224x3 as this is what is used by the model presented in the next section.

import os
import numpy as np

from tensorflow.io import read_file
from tensorflow.keras.utils import get_file

from akida_models.imagenet import preprocessing

# Model specification and hyperparameters
NUM_CHANNELS = 3
IMAGE_SIZE = 224
NUM_CLASSES = 1000

num_images = 10

# Retrieve dataset file from Brainchip data server
file_path = get_file(
    "imagenet_like.zip",
    "http://data.brainchip.com/dataset-mirror/imagenet_like/imagenet_like.zip",
    cache_subdir='datasets/imagenet_like',
    extract=True)
data_folder = os.path.dirname(file_path)

# Load images for test set
x_test_files = []
x_test = np.zeros((num_images, 224, 224, 3)).astype('uint8')
for id in range(num_images):
    test_file = 'image_' + str(id + 1).zfill(2) + '.jpg'
    x_test_files.append(test_file)
    img_path = os.path.join(data_folder, test_file)
    base_image = read_file(img_path)
    image = preprocessing.resize_and_crop(image_buffer=base_image,
                                          output_width=IMAGE_SIZE,
                                          output_height=IMAGE_SIZE,
                                          num_channels=NUM_CHANNELS)
    x_test[id, :, :, :] = np.expand_dims(image, axis=0)

print(f'{num_images} images loaded and preprocessed.')

Out:

Downloading data from http://data.brainchip.com/dataset-mirror/imagenet_like/imagenet_like.zip

   16384/20418307 [..............................] - ETA: 16s
  163840/20418307 [..............................] - ETA: 50s
  196608/20418307 [..............................] - ETA: 1:19
  229376/20418307 [..............................] - ETA: 1:12
  311296/20418307 [..............................] - ETA: 56s 
  401408/20418307 [..............................] - ETA: 46s
  491520/20418307 [..............................] - ETA: 40s
  589824/20418307 [..............................] - ETA: 35s
  663552/20418307 [..............................] - ETA: 32s
  794624/20418307 [>.............................] - ETA: 28s
  925696/20418307 [>.............................] - ETA: 25s
 1056768/20418307 [>.............................] - ETA: 23s
 1187840/20418307 [>.............................] - ETA: 21s
 1318912/20418307 [>.............................] - ETA: 20s
 1449984/20418307 [=>............................] - ETA: 18s
 1581056/20418307 [=>............................] - ETA: 17s
 1712128/20418307 [=>............................] - ETA: 16s
 1843200/20418307 [=>............................] - ETA: 16s
 1933312/20418307 [=>............................] - ETA: 15s
 2031616/20418307 [=>............................] - ETA: 15s
 2105344/20418307 [==>...........................] - ETA: 15s
 2203648/20418307 [==>...........................] - ETA: 15s
 2334720/20418307 [==>...........................] - ETA: 14s
 2465792/20418307 [==>...........................] - ETA: 14s
 2605056/20418307 [==>...........................] - ETA: 13s
 2736128/20418307 [===>..........................] - ETA: 13s
 2867200/20418307 [===>..........................] - ETA: 12s
 2998272/20418307 [===>..........................] - ETA: 12s
 3088384/20418307 [===>..........................] - ETA: 12s
 3178496/20418307 [===>..........................] - ETA: 12s
 3276800/20418307 [===>..........................] - ETA: 12s
 3383296/20418307 [===>..........................] - ETA: 12s
 3514368/20418307 [====>.........................] - ETA: 11s
 3645440/20418307 [====>.........................] - ETA: 11s
 3784704/20418307 [====>.........................] - ETA: 11s
 3883008/20418307 [====>.........................] - ETA: 11s
 3891200/20418307 [====>.........................] - ETA: 12s
 3956736/20418307 [====>.........................] - ETA: 12s
 4022272/20418307 [====>.........................] - ETA: 12s
 4112384/20418307 [=====>........................] - ETA: 12s
 4202496/20418307 [=====>........................] - ETA: 12s
 4292608/20418307 [=====>........................] - ETA: 12s
 4390912/20418307 [=====>........................] - ETA: 12s
 4497408/20418307 [=====>........................] - ETA: 12s
 4628480/20418307 [=====>........................] - ETA: 11s
 4759552/20418307 [=====>........................] - ETA: 11s
 4898816/20418307 [======>.......................] - ETA: 11s
 5029888/20418307 [======>.......................] - ETA: 11s
 5160960/20418307 [======>.......................] - ETA: 10s
 5292032/20418307 [======>.......................] - ETA: 10s
 5431296/20418307 [======>.......................] - ETA: 10s
 5562368/20418307 [=======>......................] - ETA: 10s
 5693440/20418307 [=======>......................] - ETA: 10s
 5824512/20418307 [=======>......................] - ETA: 9s 
 5963776/20418307 [=======>......................] - ETA: 9s
 6094848/20418307 [=======>......................] - ETA: 9s
 6234112/20418307 [========>.....................] - ETA: 9s
 6496256/20418307 [========>.....................] - ETA: 8s
 6758400/20418307 [========>.....................] - ETA: 8s
 7020544/20418307 [=========>....................] - ETA: 8s
 7282688/20418307 [=========>....................] - ETA: 7s
 7544832/20418307 [==========>...................] - ETA: 7s
 7806976/20418307 [==========>...................] - ETA: 7s
 8069120/20418307 [==========>...................] - ETA: 6s
 8331264/20418307 [===========>..................] - ETA: 6s
 8593408/20418307 [===========>..................] - ETA: 6s
 8855552/20418307 [============>.................] - ETA: 6s
 9117696/20418307 [============>.................] - ETA: 5s
 9379840/20418307 [============>.................] - ETA: 5s
 9641984/20418307 [=============>................] - ETA: 5s
 9904128/20418307 [=============>................] - ETA: 5s
10166272/20418307 [=============>................] - ETA: 5s
10428416/20418307 [==============>...............] - ETA: 4s
10690560/20418307 [==============>...............] - ETA: 4s
10952704/20418307 [===============>..............] - ETA: 4s
11214848/20418307 [===============>..............] - ETA: 4s
11476992/20418307 [===============>..............] - ETA: 4s
11739136/20418307 [================>.............] - ETA: 3s
12001280/20418307 [================>.............] - ETA: 3s
12263424/20418307 [=================>............] - ETA: 3s
12525568/20418307 [=================>............] - ETA: 3s
12787712/20418307 [=================>............] - ETA: 3s
13049856/20418307 [==================>...........] - ETA: 3s
13312000/20418307 [==================>...........] - ETA: 3s
13574144/20418307 [==================>...........] - ETA: 2s
13836288/20418307 [===================>..........] - ETA: 2s
14098432/20418307 [===================>..........] - ETA: 2s
14360576/20418307 [====================>.........] - ETA: 2s
14622720/20418307 [====================>.........] - ETA: 2s
14884864/20418307 [====================>.........] - ETA: 2s
15147008/20418307 [=====================>........] - ETA: 2s
15409152/20418307 [=====================>........] - ETA: 1s
15671296/20418307 [======================>.......] - ETA: 1s
15933440/20418307 [======================>.......] - ETA: 1s
16195584/20418307 [======================>.......] - ETA: 1s
16457728/20418307 [=======================>......] - ETA: 1s
16719872/20418307 [=======================>......] - ETA: 1s
16982016/20418307 [=======================>......] - ETA: 1s
17244160/20418307 [========================>.....] - ETA: 1s
17506304/20418307 [========================>.....] - ETA: 1s
17768448/20418307 [=========================>....] - ETA: 0s
18030592/20418307 [=========================>....] - ETA: 0s
18292736/20418307 [=========================>....] - ETA: 0s
18554880/20418307 [==========================>...] - ETA: 0s
18817024/20418307 [==========================>...] - ETA: 0s
19079168/20418307 [===========================>..] - ETA: 0s
19341312/20418307 [===========================>..] - ETA: 0s
19603456/20418307 [===========================>..] - ETA: 0s
19865600/20418307 [============================>.] - ETA: 0s
20127744/20418307 [============================>.] - ETA: 0s
20389888/20418307 [============================>.] - ETA: 0s
20422656/20418307 [==============================] - 7s 0us/step

20430848/20418307 [==============================] - 7s 0us/step
10 images loaded and preprocessed.

Labels for test images are stored in the akida_models package. The matching between names (string) and labels (integer) is given through the imagenet.preprocessing.index_to_label method.

import csv

# Parse labels file
fname = os.path.join(data_folder, 'labels_validation.txt')
validation_labels = dict()
with open(fname, newline='') as csvfile:
    reader = csv.reader(csvfile, delimiter=' ')
    for row in reader:
        validation_labels[row[0]] = row[1]

# Get labels for the test set by index
labels_test = np.zeros(num_images)
for i in range(num_images):
    labels_test[i] = int(validation_labels[x_test_files[i]])

2. Create a Keras AkidaNet model

The AkidaNet architecture is available in the Akida model zoo as akidanet_imagenet. In this tutorial, the alpha = 0.5 version of AkidaNet will be used, where alpha is the parameter controlling the width of the model.

from tensorflow.keras.models import load_model

# Retrieve the float model with pretrained weights and load it
model_file = get_file(
    "akidanet_imagenet_224_alpha_50.h5",
    "http://data.brainchip.com/models/akidanet/akidanet_imagenet_224_alpha_50.h5",
    cache_subdir='models/akidanet_imagenet')
model_keras = load_model(model_file)
model_keras.summary()

Out:

Downloading data from http://data.brainchip.com/models/akidanet/akidanet_imagenet_224_alpha_50.h5

  16384/5704248 [..............................] - ETA: 4s
 204800/5704248 [>.............................] - ETA: 1s
 466944/5704248 [=>............................] - ETA: 1s
 729088/5704248 [==>...........................] - ETA: 1s
 991232/5704248 [====>.........................] - ETA: 1s
1253376/5704248 [=====>........................] - ETA: 1s
1515520/5704248 [======>.......................] - ETA: 1s
1777664/5704248 [========>.....................] - ETA: 0s
2039808/5704248 [=========>....................] - ETA: 0s
2301952/5704248 [===========>..................] - ETA: 0s
2564096/5704248 [============>.................] - ETA: 0s
2826240/5704248 [=============>................] - ETA: 0s
3088384/5704248 [===============>..............] - ETA: 0s
3350528/5704248 [================>.............] - ETA: 0s
3612672/5704248 [=================>............] - ETA: 0s
3874816/5704248 [===================>..........] - ETA: 0s
4136960/5704248 [====================>.........] - ETA: 0s
4399104/5704248 [======================>.......] - ETA: 0s
4661248/5704248 [=======================>......] - ETA: 0s
4923392/5704248 [========================>.....] - ETA: 0s
5185536/5704248 [==========================>...] - ETA: 0s
5447680/5704248 [===========================>..] - ETA: 0s
5709824/5704248 [==============================] - 1s 0us/step

5718016/5704248 [==============================] - 1s 0us/step
Model: "akidanet_0.50_224_1000"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0
_________________________________________________________________
rescaling (Rescaling)        (None, 224, 224, 3)       0
_________________________________________________________________
conv_0 (Conv2D)              (None, 112, 112, 16)      432
_________________________________________________________________
conv_0_BN (BatchNormalizatio (None, 112, 112, 16)      64
_________________________________________________________________
conv_0_relu (ReLU)           (None, 112, 112, 16)      0
_________________________________________________________________
conv_1 (Conv2D)              (None, 112, 112, 32)      4608
_________________________________________________________________
conv_1_BN (BatchNormalizatio (None, 112, 112, 32)      128
_________________________________________________________________
conv_1_relu (ReLU)           (None, 112, 112, 32)      0
_________________________________________________________________
conv_2 (Conv2D)              (None, 56, 56, 64)        18432
_________________________________________________________________
conv_2_BN (BatchNormalizatio (None, 56, 56, 64)        256
_________________________________________________________________
conv_2_relu (ReLU)           (None, 56, 56, 64)        0
_________________________________________________________________
conv_3 (Conv2D)              (None, 56, 56, 64)        36864
_________________________________________________________________
conv_3_BN (BatchNormalizatio (None, 56, 56, 64)        256
_________________________________________________________________
conv_3_relu (ReLU)           (None, 56, 56, 64)        0
_________________________________________________________________
separable_4 (SeparableConv2D (None, 28, 28, 128)       8768
_________________________________________________________________
separable_4_BN (BatchNormali (None, 28, 28, 128)       512
_________________________________________________________________
separable_4_relu (ReLU)      (None, 28, 28, 128)       0
_________________________________________________________________
separable_5 (SeparableConv2D (None, 28, 28, 128)       17536
_________________________________________________________________
separable_5_BN (BatchNormali (None, 28, 28, 128)       512
_________________________________________________________________
separable_5_relu (ReLU)      (None, 28, 28, 128)       0
_________________________________________________________________
separable_6 (SeparableConv2D (None, 14, 14, 256)       33920
_________________________________________________________________
separable_6_BN (BatchNormali (None, 14, 14, 256)       1024
_________________________________________________________________
separable_6_relu (ReLU)      (None, 14, 14, 256)       0
_________________________________________________________________
separable_7 (SeparableConv2D (None, 14, 14, 256)       67840
_________________________________________________________________
separable_7_BN (BatchNormali (None, 14, 14, 256)       1024
_________________________________________________________________
separable_7_relu (ReLU)      (None, 14, 14, 256)       0
_________________________________________________________________
separable_8 (SeparableConv2D (None, 14, 14, 256)       67840
_________________________________________________________________
separable_8_BN (BatchNormali (None, 14, 14, 256)       1024
_________________________________________________________________
separable_8_relu (ReLU)      (None, 14, 14, 256)       0
_________________________________________________________________
separable_9 (SeparableConv2D (None, 14, 14, 256)       67840
_________________________________________________________________
separable_9_BN (BatchNormali (None, 14, 14, 256)       1024
_________________________________________________________________
separable_9_relu (ReLU)      (None, 14, 14, 256)       0
_________________________________________________________________
separable_10 (SeparableConv2 (None, 14, 14, 256)       67840
_________________________________________________________________
separable_10_BN (BatchNormal (None, 14, 14, 256)       1024
_________________________________________________________________
separable_10_relu (ReLU)     (None, 14, 14, 256)       0
_________________________________________________________________
separable_11 (SeparableConv2 (None, 14, 14, 256)       67840
_________________________________________________________________
separable_11_BN (BatchNormal (None, 14, 14, 256)       1024
_________________________________________________________________
separable_11_relu (ReLU)     (None, 14, 14, 256)       0
_________________________________________________________________
separable_12 (SeparableConv2 (None, 7, 7, 512)         133376
_________________________________________________________________
separable_12_BN (BatchNormal (None, 7, 7, 512)         2048
_________________________________________________________________
separable_12_relu (ReLU)     (None, 7, 7, 512)         0
_________________________________________________________________
separable_13 (SeparableConv2 (None, 7, 7, 512)         266752
_________________________________________________________________
separable_13_global_avg (Glo (None, 512)               0
_________________________________________________________________
separable_13_BN (BatchNormal (None, 512)               2048
_________________________________________________________________
separable_13_relu (ReLU)     (None, 512)               0
_________________________________________________________________
reshape_1 (Reshape)          (None, 1, 1, 512)         0
_________________________________________________________________
dropout (Dropout)            (None, 1, 1, 512)         0
_________________________________________________________________
separable_14 (SeparableConv2 (None, 1, 1, 1000)        516608
_________________________________________________________________
act_softmax (Activation)     (None, 1, 1, 1000)        0
_________________________________________________________________
reshape_2 (Reshape)          (None, 1000)              0
=================================================================
Total params: 1,388,464
Trainable params: 1,382,480
Non-trainable params: 5,984
_________________________________________________________________

Top-1 accuracy on the actual ImageNet is 64.58%, the perfomance given below uses the 10 images subset.

from timeit import default_timer as timer


# Check model performance
def check_model_performances(model, x_test=x_test, labels_test=labels_test):
    num_images = len(x_test)

    start = timer()
    potentials_keras = model.predict(x_test, batch_size=100)
    end = timer()
    print(f'Keras inference on {num_images} images took {end-start:.2f} s.\n')

    preds_keras = np.squeeze(np.argmax(potentials_keras, 1))
    accuracy_keras = np.sum(np.equal(preds_keras, labels_test)) / num_images

    print(f"Keras accuracy: {accuracy_keras*100:.2f} %")


check_model_performances(model_keras)

Out:

Keras inference on 10 images took 0.32 s.

Keras accuracy: 90.00 %

3. Quantized model

Quantizing a model is done using cnn2snn.quantize.

The quantized model satisfies the Akida NSoC requirements:

  • the first layer has 8-bit weights,

  • all other convolutional layers have 4-bit weights,

  • all convolutional layers have 4-bit activations.

However, this model will suffer from a drop in accuracy due to quantization as shown in the table below for ImageNet and in the next cell for the 10 images set.

Float accuracy

Quantized accuracy

64.58 %

1.00 %

from cnn2snn import quantize

# Quantize the model to 4-bit weights and activations, 8-bit weights for the
# first convolutional layer
model_keras_quantized = quantize(model_keras, 4, 4, 8)

# Check Model performance
check_model_performances(model_keras_quantized)

Out:

Keras inference on 10 images took 0.49 s.

Keras accuracy: 0.00 %

4. Pretrained quantized model

The Akida models zoo also contains a pretrained quantized helper that was obtained after fine tuning the model for 10 epochs.

Tuning the model, that is training with a lowered learning rate, allows to recover performances up to the initial floating point accuracy.

Performances on the full ImageNet dataset are:

Float accuracy

Quantized accuracy

After tuning

64.58 %

1.00 %

61.30 %

from akida_models import akidanet_imagenet_pretrained

# Use a quantized model with pretrained quantized weights
model_keras_quantized_pretrained = akidanet_imagenet_pretrained(0.5)
model_keras_quantized_pretrained.summary()

Out:

Downloading data from http://data.brainchip.com/models/akidanet/akidanet_imagenet_224_alpha_50_iq8_wq4_aq4.h5

  16384/5613320 [..............................] - ETA: 4s
 139264/5613320 [..............................] - ETA: 2s
 401408/5613320 [=>............................] - ETA: 1s
 663552/5613320 [==>...........................] - ETA: 1s
 925696/5613320 [===>..........................] - ETA: 1s
1187840/5613320 [=====>........................] - ETA: 1s
1449984/5613320 [======>.......................] - ETA: 1s
1712128/5613320 [========>.....................] - ETA: 0s
1974272/5613320 [=========>....................] - ETA: 0s
2236416/5613320 [==========>...................] - ETA: 0s
2498560/5613320 [============>.................] - ETA: 0s
2760704/5613320 [=============>................] - ETA: 0s
3022848/5613320 [===============>..............] - ETA: 0s
3284992/5613320 [================>.............] - ETA: 0s
3547136/5613320 [=================>............] - ETA: 0s
3809280/5613320 [===================>..........] - ETA: 0s
4071424/5613320 [====================>.........] - ETA: 0s
4333568/5613320 [======================>.......] - ETA: 0s
4595712/5613320 [=======================>......] - ETA: 0s
4857856/5613320 [========================>.....] - ETA: 0s
5120000/5613320 [==========================>...] - ETA: 0s
5382144/5613320 [===========================>..] - ETA: 0s
5619712/5613320 [==============================] - 1s 0us/step

5627904/5613320 [==============================] - 1s 0us/step
Model: "akidanet_0.50_224_1000"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0
_________________________________________________________________
rescaling (Rescaling)        (None, 224, 224, 3)       0
_________________________________________________________________
conv_0 (QuantizedConv2D)     (None, 112, 112, 16)      448
_________________________________________________________________
conv_0_relu (ActivationDiscr (None, 112, 112, 16)      0
_________________________________________________________________
conv_1 (QuantizedConv2D)     (None, 112, 112, 32)      4640
_________________________________________________________________
conv_1_relu (ActivationDiscr (None, 112, 112, 32)      0
_________________________________________________________________
conv_2 (QuantizedConv2D)     (None, 56, 56, 64)        18496
_________________________________________________________________
conv_2_relu (ActivationDiscr (None, 56, 56, 64)        0
_________________________________________________________________
conv_3 (QuantizedConv2D)     (None, 56, 56, 64)        36928
_________________________________________________________________
conv_3_relu (ActivationDiscr (None, 56, 56, 64)        0
_________________________________________________________________
separable_4 (QuantizedSepara (None, 28, 28, 128)       8896
_________________________________________________________________
separable_4_relu (Activation (None, 28, 28, 128)       0
_________________________________________________________________
separable_5 (QuantizedSepara (None, 28, 28, 128)       17664
_________________________________________________________________
separable_5_relu (Activation (None, 28, 28, 128)       0
_________________________________________________________________
separable_6 (QuantizedSepara (None, 14, 14, 256)       34176
_________________________________________________________________
separable_6_relu (Activation (None, 14, 14, 256)       0
_________________________________________________________________
separable_7 (QuantizedSepara (None, 14, 14, 256)       68096
_________________________________________________________________
separable_7_relu (Activation (None, 14, 14, 256)       0
_________________________________________________________________
separable_8 (QuantizedSepara (None, 14, 14, 256)       68096
_________________________________________________________________
separable_8_relu (Activation (None, 14, 14, 256)       0
_________________________________________________________________
separable_9 (QuantizedSepara (None, 14, 14, 256)       68096
_________________________________________________________________
separable_9_relu (Activation (None, 14, 14, 256)       0
_________________________________________________________________
separable_10 (QuantizedSepar (None, 14, 14, 256)       68096
_________________________________________________________________
separable_10_relu (Activatio (None, 14, 14, 256)       0
_________________________________________________________________
separable_11 (QuantizedSepar (None, 14, 14, 256)       68096
_________________________________________________________________
separable_11_relu (Activatio (None, 14, 14, 256)       0
_________________________________________________________________
separable_12 (QuantizedSepar (None, 7, 7, 512)         133888
_________________________________________________________________
separable_12_relu (Activatio (None, 7, 7, 512)         0
_________________________________________________________________
separable_13 (QuantizedSepar (None, 7, 7, 512)         267264
_________________________________________________________________
separable_13_global_avg (Glo (None, 512)               0
_________________________________________________________________
separable_13_relu (Activatio (None, 512)               0
_________________________________________________________________
reshape_1 (Reshape)          (None, 1, 1, 512)         0
_________________________________________________________________
dropout (Dropout)            (None, 1, 1, 512)         0
_________________________________________________________________
separable_14 (QuantizedSepar (None, 1, 1, 1000)        516608
_________________________________________________________________
act_softmax (Activation)     (None, 1, 1, 1000)        0
_________________________________________________________________
reshape_2 (Reshape)          (None, 1000)              0
=================================================================
Total params: 1,379,488
Trainable params: 1,379,488
Non-trainable params: 0
_________________________________________________________________
# Check model performance
check_model_performances(model_keras_quantized_pretrained)

Out:

Keras inference on 10 images took 0.49 s.

Keras accuracy: 80.00 %

5. Conversion to Akida

5.1 Convert to Akida model

Here, the Keras quantized model is converted into a suitable version for the Akida NSoC. The cnn2snn.convert function needs as arguments the Keras model and the input scaling parameters.

from cnn2snn import convert

model_akida = convert(model_keras_quantized_pretrained)

The Model.summary method provides a detailed description of the Model layers.

model_akida.summary()

Out:

                 Model Summary
________________________________________________
Input shape    Output shape  Sequences  Layers
================================================
[224, 224, 3]  [1, 1, 1000]  1          15
________________________________________________

              SW/conv_0-separable_14 (Software)
_____________________________________________________________
Layer (type)              Output shape    Kernel shape
=============================================================
conv_0 (InputConv.)       [112, 112, 16]  (3, 3, 3, 16)
_____________________________________________________________
conv_1 (Conv.)            [112, 112, 32]  (3, 3, 16, 32)
_____________________________________________________________
conv_2 (Conv.)            [56, 56, 64]    (3, 3, 32, 64)
_____________________________________________________________
conv_3 (Conv.)            [56, 56, 64]    (3, 3, 64, 64)
_____________________________________________________________
separable_4 (Sep.Conv.)   [28, 28, 128]   (3, 3, 64, 1)
_____________________________________________________________
                                          (1, 1, 64, 128)
_____________________________________________________________
separable_5 (Sep.Conv.)   [28, 28, 128]   (3, 3, 128, 1)
_____________________________________________________________
                                          (1, 1, 128, 128)
_____________________________________________________________
separable_6 (Sep.Conv.)   [14, 14, 256]   (3, 3, 128, 1)
_____________________________________________________________
                                          (1, 1, 128, 256)
_____________________________________________________________
separable_7 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 256)
_____________________________________________________________
separable_8 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 256)
_____________________________________________________________
separable_9 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 256)
_____________________________________________________________
separable_10 (Sep.Conv.)  [14, 14, 256]   (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 256)
_____________________________________________________________
separable_11 (Sep.Conv.)  [14, 14, 256]   (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 256)
_____________________________________________________________
separable_12 (Sep.Conv.)  [7, 7, 512]     (3, 3, 256, 1)
_____________________________________________________________
                                          (1, 1, 256, 512)
_____________________________________________________________
separable_13 (Sep.Conv.)  [1, 1, 512]     (3, 3, 512, 1)
_____________________________________________________________
                                          (1, 1, 512, 512)
_____________________________________________________________
separable_14 (Sep.Conv.)  [1, 1, 1000]    (3, 3, 512, 1)
_____________________________________________________________
                                          (1, 1, 512, 1000)
_____________________________________________________________

5.2 Check performance

While we compute accuracy for the 10 images set in the next cell, the following table summarizes results obtained on ImageNet.

Keras accuracy

Akida accuracy

61.30 %

61.37 %

# Check Model performance
start = timer()
preds_akida = model_akida.predict(x_test)
end = timer()
print(f'Inference on {num_images} images took {end-start:.2f} s.\n')

accuracy_akida = np.sum(np.equal(preds_akida, labels_test)) / num_images

print(f"Accuracy: {accuracy_akida*100:.2f} %")

# For non-regression purpose
assert accuracy_akida == 0.9

Out:

Inference on 10 images took 0.32 s.

Accuracy: 90.00 %

5.3 Show predictions for a random image

import matplotlib.pyplot as plt
import matplotlib.lines as lines


# Functions used to display the top5 results
def get_top5(potentials, true_label):
    """
    Returns the top 5 classes from the output potentials
    """
    tmp_pots = potentials.copy()
    top5 = []
    min_val = np.min(tmp_pots)
    for ii in range(5):
        best = np.argmax(tmp_pots)
        top5.append(best)
        tmp_pots[best] = min_val

    vals = np.zeros((6,))
    vals[:5] = potentials[top5]
    if true_label not in top5:
        vals[5] = potentials[true_label]
    else:
        vals[5] = 0
    vals /= np.max(vals)

    class_name = []
    for ii in range(5):
        class_name.append(preprocessing.index_to_label(top5[ii]).split(',')[0])
    if true_label in top5:
        class_name.append('')
    else:
        class_name.append(
            preprocessing.index_to_label(true_label).split(',')[0])

    return top5, vals, class_name


def adjust_spines(ax, spines):
    for loc, spine in ax.spines.items():
        if loc in spines:
            spine.set_position(('outward', 10))  # outward by 10 points
        else:
            spine.set_color('none')  # don't draw spine
    # turn off ticks where there is no spine
    if 'left' in spines:
        ax.yaxis.set_ticks_position('left')
    else:
        # no yaxis ticks
        ax.yaxis.set_ticks([])
    if 'bottom' in spines:
        ax.xaxis.set_ticks_position('bottom')
    else:
        # no xaxis ticks
        ax.xaxis.set_ticks([])


def prepare_plots():
    fig = plt.figure(figsize=(8, 4))
    # Image subplot
    ax0 = plt.subplot(1, 3, 1)
    imgobj = ax0.imshow(np.zeros((224, 224, 3), dtype=np.uint8))
    ax0.set_axis_off()
    # Top 5 results subplot
    ax1 = plt.subplot(1, 2, 2)
    bar_positions = (0, 1, 2, 3, 4, 6)
    rects = ax1.barh(bar_positions, np.zeros((6,)), align='center', height=0.5)
    plt.xlim(-0.2, 1.01)
    ax1.set(xlim=(-0.2, 1.15), ylim=(-1.5, 12))
    ax1.set_yticks(bar_positions)
    ax1.invert_yaxis()
    ax1.yaxis.set_ticks_position('left')
    ax1.xaxis.set_ticks([])
    adjust_spines(ax1, 'left')
    ax1.add_line(lines.Line2D((0, 0), (-0.5, 6.5), color=(0.0, 0.0, 0.0)))
    txt_axlbl = ax1.text(-1, -1, 'Top 5 Predictions:', size=12)
    # Adjust Plot Positions
    ax0.set_position([0.05, 0.055, 0.3, 0.9])
    l1, b1, w1, h1 = ax1.get_position().bounds
    ax1.set_position([l1 * 1.05, b1 + 0.09 * h1, w1, 0.8 * h1])
    # Add title box
    plt.figtext(0.5,
                0.9,
                "Imagenet Classification by Akida",
                size=20,
                ha="center",
                va="center",
                bbox=dict(boxstyle="round",
                          ec=(0.5, 0.5, 0.5),
                          fc=(0.9, 0.9, 1.0)))

    return fig, imgobj, ax1, rects


def update_bars_chart(rects, vals, true_label):
    counter = 0
    for rect, h in zip(rects, yvals):
        rect.set_width(h)
        if counter < 5:
            if top5[counter] == true_label:
                if counter == 0:
                    rect.set_facecolor((0.0, 1.0, 0.0))
                else:
                    rect.set_facecolor((0.0, 0.5, 0.0))
            else:
                rect.set_facecolor('gray')
        elif counter == 5:
            rect.set_facecolor('red')
        counter += 1


# Prepare plots
fig, imgobj, ax1, rects = prepare_plots()

# Get a random image
img = np.random.randint(num_images)

# Predict image class
potentials_akida = model_akida.evaluate(np.expand_dims(x_test[img],
                                                       axis=0)).squeeze()

# Get top 5 prediction labels and associated names
true_label = int(validation_labels[x_test_files[img]])
top5, yvals, class_name = get_top5(potentials_akida, true_label)

# Draw Plots
imgobj.set_data(x_test[img])
ax1.set_yticklabels(class_name, rotation='horizontal', size=9)
update_bars_chart(rects, yvals, true_label)
fig.canvas.draw()
plt.show()
plot 2 akidanet imagenet

6. Hardware mapping and performance

6.1. Map on hardware

List Akida available devices and check that an NSoC V2 (production chip) is available

import akida

devices = akida.devices()
print(f'Available devices: {[dev.desc for dev in devices]}')
device = devices[0]
assert device.version == akida.NSoC_v2

Out:

Available devices: ['PCIe/NSoC_v2']

Map the model on the device

model_akida.map(device)

# Check model mapping: NP allocation and binary size
model_akida.summary()

Out:

                 Model Summary
________________________________________________
Input shape    Output shape  Sequences  Layers
================================================
[224, 224, 3]  [1, 1, 1000]  1          15
________________________________________________

     HW/conv_0-separable_14 (Hardware) - size: 1241484 bytes
__________________________________________________________________
Layer (type)              Output shape    Kernel shape       NPs
==================================================================
conv_0 (InputConv.)       [112, 112, 16]  (3, 3, 3, 16)      N/A
__________________________________________________________________
conv_1 (Conv.)            [112, 112, 32]  (3, 3, 16, 32)     4
__________________________________________________________________
conv_2 (Conv.)            [56, 56, 64]    (3, 3, 32, 64)     6
__________________________________________________________________
conv_3 (Conv.)            [56, 56, 64]    (3, 3, 64, 64)     3
__________________________________________________________________
separable_4 (Sep.Conv.)   [28, 28, 128]   (3, 3, 64, 1)      3
__________________________________________________________________
                                          (1, 1, 64, 128)
__________________________________________________________________
separable_5 (Sep.Conv.)   [28, 28, 128]   (3, 3, 128, 1)     2
__________________________________________________________________
                                          (1, 1, 128, 128)
__________________________________________________________________
separable_6 (Sep.Conv.)   [14, 14, 256]   (3, 3, 128, 1)     2
__________________________________________________________________
                                          (1, 1, 128, 256)
__________________________________________________________________
separable_7 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)     1
__________________________________________________________________
                                          (1, 1, 256, 256)
__________________________________________________________________
separable_8 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)     1
__________________________________________________________________
                                          (1, 1, 256, 256)
__________________________________________________________________
separable_9 (Sep.Conv.)   [14, 14, 256]   (3, 3, 256, 1)     1
__________________________________________________________________
                                          (1, 1, 256, 256)
__________________________________________________________________
separable_10 (Sep.Conv.)  [14, 14, 256]   (3, 3, 256, 1)     1
__________________________________________________________________
                                          (1, 1, 256, 256)
__________________________________________________________________
separable_11 (Sep.Conv.)  [14, 14, 256]   (3, 3, 256, 1)     1
__________________________________________________________________
                                          (1, 1, 256, 256)
__________________________________________________________________
separable_12 (Sep.Conv.)  [7, 7, 512]     (3, 3, 256, 1)     2
__________________________________________________________________
                                          (1, 1, 256, 512)
__________________________________________________________________
separable_13 (Sep.Conv.)  [1, 1, 512]     (3, 3, 512, 1)     4
__________________________________________________________________
                                          (1, 1, 512, 512)
__________________________________________________________________
separable_14 (Sep.Conv.)  [1, 1, 1000]    (3, 3, 512, 1)     7
__________________________________________________________________
                                          (1, 1, 512, 1000)
__________________________________________________________________

6.2. Performances measurement

Power measurement must be enabled on the device’ soc (disabled by default). After sending data for inference, performances measurements are available in the model statistics.

# Enable power measurement
device.soc.power_measurement_enabled = True

# Send data for inference
_ = model_akida.forward(x_test)

# Display floor current
floor_power = device.soc.power_meter.floor
print(f'Floor power: {floor_power:.2f} mW')

# Retrieve statistics
print(model_akida.statistics)

Out:

Floor power: 881.10 mW

Sequence HW/conv_0-separable_14
Average framerate = 18.69 fps
Last inference power range (mW):  Avg 1001.00 / Min 881.00 / Max 1123.00 / Std 115.25
Last inference energy consumed (mJ/frame): 53.55

Total running time of the script: ( 0 minutes 18.321 seconds)

Gallery generated by Sphinx-Gallery