Friday 1 February 2019

how to convert CPU usage to Movidius in Keras


I used a simple Keras example as a starting point. 
Develop Your First Neural Network in Python With Keras Step-By-Step
I took the first half of this example:

# MLP for Pima Indians Dataset Serialize to JSON and HDF5
from keras.models import Sequential
from keras.layers import Dense
from keras.models import model_from_json
import numpy
import os
# fix random seed for reproducibility
numpy.random.seed(7)
# load pima indians dataset
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# split into input (X) and output (Y) variables
X = dataset[:,0:8]
Y = dataset[:,8]
# create model
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Fit the model
model.fit(X, Y, epochs=150, batch_size=10, verbose=0)
x=numpy.array([[0.42030057, 0.78084083, 0.76165254, 0.19794683, 0.78010274, 0.24512312, 0.17131911, 0.03071891]])
print(x)
yy=model.predict(x, batch_size=None, verbose=0, steps=None)
print(yy)

and I added prediction stuff:
x=numpy.array([[0.42030057, 0.78084083, 0.76165254, 0.19794683, 0.78010274, 0.24512312, 0.17131911, 0.03071891]])
print(x)
yy=model.predict(x, batch_size=None, verbose=0, steps=None)
print(yy)

the output follows:
runfile('C:/Users/ars/.spyder-py3/ars-test/keras_first_network.py', wdir='C:/Users/ars/.spyder-py3/ars-test')

768/768 [==============================] - 0s 13us/step

acc: 79.30%
[[0.42030057 0.78084083 0.76165254 0.19794683 0.78010274 0.24512312
  0.17131911 0.03071891]]
[[0.00283898]]
This was all done with Anaconda using Keras.  I put this to make a comparison later on.

pimasARS.py is the same as the Keras version.
# MLP for Pima Indians Dataset Serialize to JSON and HDF5
from keras.models import Sequential
from keras.layers import Dense
from keras.models import model_from_json
import numpy
import os
# fix random seed for reproducibility
numpy.random.seed(7)
# load pima indians dataset
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# split into input (X) and output (Y) variables
X = dataset[:,0:8]
Y = dataset[:,8]
# create model
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Fit the model
model.fit(X, Y, epochs=150, batch_size=10, verbose=0)
# evaluate the model
scores = model.evaluate(X, Y, verbose=0)
print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))

but it saves the model to Keras model files JSON and HDF5.

# serialize model to JSON
model_json = model.to_json()
with open("model.json", "w") as json_file:
    json_file.write(model_json)
# serialize weights to HDF5
model.save_weights("model.h5")
print("Saved model to disk")

Movidius needs to work with TensorFlow  graph files.  So I used
Convert-pimas file from

How to run Keras model on Movidius neural compute stick


convert-pimas.py
from keras.models import model_from_json
from keras import backend as K
import tensorflow as tf
from keras.models import model_from_json
from keras import backend as K
import tensorflow as tf

model_file = "model.json"
weights_file = "model.h5"

with open(model_file, "r") as file:
    config = file.read()

K.set_learning_phase(0)
model = model_from_json(config)
model.load_weights(weights_file)

saver = tf.train.Saver()
sess = K.get_session()
saver.save(sess, "./TF_Model/tf_model")

fw = tf.summary.FileWriter('logs', sess.graph)
fw.close()
model_file = "model.json"
weights_file = "model.h5"

with open(model_file, "r") as file:
    config = file.read()

K.set_learning_phase(0)
model = model_from_json(config)
model.load_weights(weights_file)

saver = tf.train.Saver()
sess = K.get_session()
saver.save(sess, "./TF_Model/tf_model")

fw = tf.summary.FileWriter('logs', sess.graph)
fw.close()

if you notice, this program does not produce a TensorFlow
graph file.  This job is done with the statement below
which you can find in the Makefile.

.PHONY: compile
compile: weights
                test -f graph || ${NCCOMPILE} -s 12 ${MODEL_FILENAME} ${INPUT_NODE_FLAG} ${OUTPUT_NODE_FLAG}

mvNCCompile -s 12 TF_Model/tf_model.meta -in=dense_1_input -on=dense_3/Sigmoid
-in and –on parameters can be found in the logs/events.out.tfevents.1549033801.ars files

After this we have to prepare the Movidius stick, open, load etc.
İn the predict-pimas.py.

#!/usr/bin/env python3.5

# [NCSDK2 API](https://movidius.github.io/ncsdk/ncapi/ncapi2/py_api/readme.html)
from mvnc import mvncapi as mvnc
from keras import backend as K
import numpy
import cv2

# Using NCS Predict
# set the logging level for the NC API
# mvnc.global_set_option(mvnc.GlobalOption.RW_LOG_LEVEL, 0)

# get a list of names for all the devices plugged into the system
devices = mvnc.enumerate_devices()
if len(devices) == 0:
    print('No devices found')
    quit()

# get the first NCS device by its name.  For this program we will always open the first NCS device.
dev = mvnc.Device(devices[0])

# try to open the device.  this will throw an exception if someone else has it open already
try:
    dev.open()
except:
    print("Error - Could not open NCS device.")
    quit()

Once Movidius stick is ready we have to load the graph to it

# Read a compiled network graph from file (set the graph_filepath correctly for your graph file)
with open("graph", mode='rb') as f:
    graphFileBuff = f.read()

graph = mvnc.Graph('graph1')

then we have to put in the test data (the same as the complete Keras version)
# Allocate the graph on the device and create input and output Fifos
in_fifo, out_fifo = graph.allocate_with_fifos(dev, graphFileBuff)

testInput=numpy.array([[0.42030057, 0.78084083, 0.76165254, 0.19794683, 0.78010274, 0.24512312, 0.17131911, 0.03071891]])
# Write the input to the input_fifo buffer and queue an inference in one call
#graph.queue_inference_with_fifo_elem(in_fifo, out_fifo, testInput.astype('float32'), 'user object')
graph.queue_inference_with_fifo_elem(in_fifo, out_fifo, testInput.astype('float32'),'object1')

read the output and print
# Read the result to the output Fifo
output, userobj = out_fifo.read_elem()

# Deallocate and destroy the fifo and graph handles, close the device, and destroy the device handle
try:
    in_fifo.destroy()
    out_fifo.destroy()
    graph.destroy()
    dev.close()
    dev.destroy()
except:
    print("Error - could not close/destroy Graph/NCS device.")
    quit()

#print("NCS \r\n", output, '\r\nPredicted:',output.argmax())
print(output)

The output :
arsaral@ars:~/ncsdk/ncappzoo/apps/pimas$ python3  predict-pimas.py
Using TensorFlow backend.
/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/ops.py:936: DeprecationWarning: builtin type EagerTensor has no __module__ attribute
  EagerTensor = c_api.TFE_Py_InitEagerTensor(_EagerTensorBase)
/usr/local/lib/python3.5/dist-packages/tensorflow/python/util/tf_inspect.py:75: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() instead
  return _inspect.getargspec(target)
/usr/local/lib/python3.5/dist-packages/mvnc/mvncapi.py:416: DeprecationWarning: The binary mode of fromstring is deprecated, as it behaves surprisingly on unicode inputs. Use frombuffer instead
  tensor = numpy.fromstring(tensor.raw, dtype=numpy.float32)
[0.00512314]
arsaral@ars:~/ncsdk/ncappzoo/apps/pimas$

A Keras only test output: [0.00283898]
A Movidius test output:  [0.00512314]