Introduction
With edge devices (mobiles, IoT, and the like) becoming progressively powerful in computing and storage, the prevailing trend is to deploy models and running them directly on such devices. Models in such cases, however, must be optimized for memory usage and CPU. End-to-end ML applications frequently comprise of components written in multiple programming languages. A data scientist may select Python, R, Scala, or any other language to create one model depending on the use case, and then another language for the second model. Every language has several accessible tool kits and frameworks. TensorFlow, Theano, and PyTorch are compatible with Python, but each of them is tuned for a particular operation type, and the output of each is a slightly dissimilar type of model. Data scientists use a multitude of tool kits and frameworks to select a tool and language that best suits the given problem. This article touches on Tensorflow on Raspberry Pi.
Tensorflow Overview
TensorFlow is essentially a Python library where users can express arbitrary computation as data flows’ graphs. The graph nodes represent mathematical operations, and edges represent data that is communicated from one particular node to another. Data present in TensorFlow are denoted as tensors. The latter are multidimensional arrays.
TensorFlow key functionalities
TensorFlow offers a readable and accessible syntax essential for making user-friendly programming resources. In contrast, Machine Learning’s (ML’s) advanced nature gives it a complex syntax which developers find inconvenient.
TensorFlow offers superior services and functionalities compared to other popular Deep Learning (DL) frameworks. Such high-level operations are a must for executing complex parallel computations. They are also needed for making advanced neural network models.
TensorFlow is a flexible low-level library. You can define own services or functionalities for your models. This is a vital parameter for researchers as it permits them to vary the model depending on changeable user requirements.
TensorFlow enables more network control. This allows researchers and developers to comprehend how operations get implemented over the network. It is thus possible to keep track of new changes done over time.
Tensors
A Tensor is described as a multidimensional numbers array. The following figure shows Rank0 tensor, Rank1 tensor, Rank2 tensor, and Rank3 tensors.
Figure 1: Tensors
Installation of Tensorflow and supported libraries
You must install Tensorflow2.0 on Raspberry Pi along with other libraries to work on it. The complete procedure is:
sudo apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev
python3 -m pip install keras_applications==1.0.8 --no-deps
python3 -m pip install keras_preprocessing==1.1.0 --no-deps
python3 -m pip install h5py==2.9.0
sudo apt-get install -y openmpi-bin libopenmpi-dev
sudo apt-get install -y libatlas-base-dev
python3 -m pip install -U six wheel mock
python3 -m pip uninstall tensorflow
python3 -m pip install tensorflow-2.0.0-cp37-none-linux_armv7l.whl
sudo apt-get install python3-scipy
sudo apt-get install build-essential cmake pkg-config
sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libxvidcore-dev libx264-dev
sudo apt-get install libfontconfig1-dev libcairo2-dev
sudo apt-get install libgdk-pixbuf2.0-dev libpango1.0-dev
sudo apt-get install libgtk2.0-dev libgtk-3-dev
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install libhdf5-dev libhdf5-serial-dev libhdf5-103
sudo apt-get install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5
sudo apt-get install python3-dev
pip3 install opencv-contrib-python==4.1.0.25
pip3 install scikit-learn
pip3 install --upgrade numpy
Tensorflow Graphs and getting started with basics
TensorFlow programs first build a Tensor objects graph, specifying the computation of each tensor based on other available tensors. The programs then run parts of such a graph to achieve the desired results. TensorFlow is founded on graph-based computation. Consider the following expression: a=(b+c)*(c+2). The equations are graphically represented in Figure 2. The two computations d=(b+c) and e=(c+2) are performed in parallel across GPU and CPU thus reducing computational time.
Figure 2: Simple Computational Graph
import tensorflow as tf
tf.compat.v1.disable_eager_execution()
# first, create a TensorFlow constant
const = tf.constant(2.0, name="const")
# create TensorFlow variables
b = tf.Variable(2.0, name='b')
c = tf.Variable(1.0, name='c')
d = tf.add(b, c, name='d')
e = tf.add(c, const, name='e')
a = tf.multiply(d, e, name='a')
# setup the variable initialisation
init_op = tf.compat.v1.global_variables_initializer()
# start the session
with tf.compat.v1.Session() as sess:
# initialise the variables
sess.run(init_op)
# compute the output of the graph
a_out = sess.run(a)
print("Variable a is {}".format(a_out))
[OUTPUT: Variable a is 9.0]
Machine Learning (ML) concerns data, training based on that data, and subsequent deployment on devices. We will now gather data, train, and inference with the help of TensorFlow2.0.
Gather and Label Data
TensorFlow must have hundreds (minimum) of images of any object to train a good detection classifier. To meet the exacting criteria, the training images must contain random objects along with the desired object. There should be a diversity of backgrounds and varied lighting conditions. The desired object must be partially obscured in some images or overlapped with some other, or only halfway in the picture.
Use a phone to snap pictures of objects or download images of the object from Google Image Search. You must obtain a minimum of 400 images.
Save data to different folders based on name; for example, parrot, dogs, and apple. You then obtain the location of every image and assign a suitable label to each image.
The following code will assign a label to all images. The images must be resized to 32x32 pixel.
imageLoc = sorted(list(paths.list_images(r"home/pi/ tensorflow_test /train_data")))
for imagePath in imageLoc:
image = cv2.imread(imagePath)
image = cv2.resize(image, (32, 32)).flatten()
data.append(image)
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
Creating the neural network Model
Once the data is ready, it is time to generate the neural network model. We can use one input layer, two hidden layers, and one output layer. The input layer along with the first hidden layer has the input shape of 3072 as 32x32x3=3072 pixels make up a flattened input image. The first hidden layer consists of 1024 nodes and the second 512 nodes. The concealed layers are Dense (interconnected). The neuron population for each layer is set. The activation constraint stipulates a function that selects whether "the opinion" of a specific neuron, in a layer, be included and to what degree. You may use several activation functions.
Activation functions are vital for an Artificial Neural Network (A-NN). It helps the network to learn and then make sense of Non-linear complex functional and complicated mappings between response variable and inputs. Non-linear properties are introduced into the Network. The principal aim is to convert a node’s input signal in an A-NN to the output signal, which is then used as input in the stack’s next layer.
In A-NN, the sum of products of inputs (X) and their corresponding Weights (W) is done and an Activation function f(x) is applied to it to obtain layer output and feed it as input to next layer.
The nodes population in the final output layer will be several possible class labels. In this particular case, the output layer has three nodes, one for each class label (“Apple”, “Parrot” and “Dog” respectively).
Figure 3: Neural Network Layers
The following code generates the neural network model:
model = tf.keras.Sequential()
model.add(Dense(1024, input_shape=(3072,), activation="sigmoid"))
model.add(Dense(512, activation="sigmoid"))
model.add(Dense(len(lb.classes_), activation="softmax"))
Train the neural network model
The generated Neural networks model is dumb. You need to train the model to do useful work. TensorFlow allows you to choose the optimizer algorithm.
Optimizers refer to methods or algorithms used to change neural network attributes like weights and the learning rate in order to cut losses.
Gradient Descent is a basic but frequently utilized optimization algorithm. It finds heavy use in classification algorithms and linear regression. Back-propagation in neural networks uses gradient descent algorithm. Gradient descent is first-order optimization algorithm dependent on a loss function’s first order derivative. It calculates the way the weights must be altered to ensure that the function reach a minima. The loss gets transferred via back-propogation from one particular layer to another. The weights (model parameters) undergoes modification depending on losses to minimize the loss.
We can use CategoricalCrossentropy and Stochastic Gradient Descent (SGD) as a loss function. It’s a Gradient Descent variant and frequently update the model’s parameters. In this instance, the model parameters are modified post loss computation each training example. It means, if a dataset has 1000 rows, SGD will update model parameters 1000 times in one cycle of the dataset and not just one time as in Gradient Descent.
Categorical crossentropy is termed a loss function and used for single label categorization. This is applied when only one category can be applied to each data point. In other words, an example may be restricted to one class only.
Actual training occurs when the fit method gets called. Both training data and validation data are given and the number of epochs you are trained for is specified. Use the following code to train the model:
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit(trainX, trainY, validation_data=(testX, testY),epochs=EPOCHS, batch_size=32)
The image data is made of trainX and testX while labels are made of trainY and testY.
It is recommended you train the model on a PC and then transfer that trained model to Raspberry Pi. Otherwise, the computation will take an inordinately long time. The generated model is saved to disk in the “neuralNetModel” folder. You can move it to Raspberry Pi.
Deploying and testing the model on Raspberry Pi
The Raspberry Pi can now accept the trained model. The model is loaded to predict identical test images for which the model is trained. Collate a few images and then save them to disk.
The following sample code load images and model from the disk:
path = r'/home/pi/tensorflow_test/test_image/apple.png’
image = cv2.imread(path)
model=tf.keras.models.load_model( r’/home/pi/tensorflow_test/neuralNetModel’)
Click here to download the entire source code.