Debugging Python Code Visually. Using Birdseye for debugging Python... | by Himanshu Sharma | Towards Data Science

Are you one of those programmers who use the print() command for debugging your python code or functions? If the answer is yes then you are not alone, most of the python programmers who use Jupyter notebook debug their code like this. There is nothing wrong with it but it is not a convenient way of how we should debug our code.
Birdseye is an open-source python library that is used to debug python code. It records values of expressions in a particular function while it is running and you can visualize these values once the function is executed and debug it if there is an issue.
In this article, we will see how Birdseye is used for python code debugging.
Let’s get started...
Like any other python library, we will install Birdseye using pip installation. The command given below will perform the installation.
pip install --user birdseye
Next, we will import all the required libraries that will be used in this article.
from birdseye import eye
In order to see Birdseye in action, we need to have certain python code with functions so that we can debug it. You can use any code which has functions in it. I’m using my own code to create a neural network using different functions. To activate the Birdseye you just need to put ‘@eye’ before everyone we want to monitor.
from keras.datasets import mnistimport matplotlib.pyplot as pltimport numpy as npimport kerasfrom keras.layers import Dense, Dropout from keras.models import Sequential from birdseye import eyeimage_size = 28*28num_classes = 10class DigitRecoginzer:    @eye    def __init__(self):        # Setup train and test splits        (self.x_train, self.y_train), (self.x_test, self.y_test) = mnist.load_data()        self.x_train, self.x_test = self.x_train/255, self.x_test/255        #print("Training label shape: ", self.y_train.shape)         #print("Training Data Shape", self.x_train.shape)    @eye    def get_data(self):        return self.x_train, self.y_train, self.x_test, self.y_test                    # Convert to "one-hot" vectors using the to_categorical function    @eye    def one_hot_encoding(self):        #print("Data before one-hot encoding", self.y_train[:5])        num_classes = 10        self.y_train = keras.utils.to_categorical(self.y_train, num_classes)        self.y_test = keras.utils.to_categorical(self.y_test, num_classes)        #print("Data after one-hot encoding\n", self.y_train[:5])# Flatten the images    @eye    def flatten_image(self):        image_vector_size = 28*28        self.x_train = self.x_train.reshape(self.x_train.shape[0], image_vector_size)        self.x_test = self.x_test.reshape(self.x_test.shape[0], image_vector_size)        @eye    def GenericModel (self, image_size, num_classes, hyperP, dp=False):        try:            self.model = Sequential()            numHiddenLayers = hyperP["NumHiddenLayers"]            act = hyperP[1][1]            init = hyperP[1][2]            self.model.add(Dense(hyperP[1][0], activation=hyperP[1][1], input_shape=(image_size,),kernel_initializer= init))#kernel_regularizer=l22            for i in range(2, numHiddenLayers+1):                l = hyperP[i]                init = l[2]                self.model.add(Dense(l[0], activation=l[1], kernel_initializer=init))                   if(dp):                    self.model.add(Dropout(hyperP['dp_rate'][i-2]))            self.model.add(Dense(num_classes, activation='softmax'))opt =hyperP["opt"](hyperP["lr"])            self.model.compile(optimizer="adam", loss='categorical_crossentropy', metrics=['accuracy'])            self.model.summary()        except Exception as ke:            print ("Key is not defined", ke)            self.model = None    @eye    def train_model(self, epoch, batch_size):        self.history = self.model.fit(self.x_train, self.y_train, batch_size=batch_size, epochs=epoch, verbose=2, validation_split=0.1)        self.model.save('model.h5')    @eye        def get_accuracy(self):        loss, accuracy  = self.model.evaluate(self.x_test, self.y_test, verbose=False)        loss_train, accuracy_train = self.model.evaluate(self.x_train, self.y_train, verbose=False)        print(f'Train loss: {loss_train:.3}', f'Train accuracy: {accuracy_train:.3}')        print(f'Test loss: {loss:.3}',f'Test accuracy: {accuracy:.3}')        return accuracy_train    @eye                def predict(self, img):        result = np.around(self.model.predict(img)[0])        max1 = max(result)        return np.where(result == max1)[0][0]lr =[0.1, 0.01, 1, 10, 0.5, 0.05]objs = []for i in range(len(lr)):    HyperParam1 = {        #Training Level Hyper Params        "epochs": 300,        "lr": lr[i],        "batchSize": 2048,        "dp_rate": [0.2, 0.1, 0.05],        "opt": keras.optimizers.Adam,        #Network Level HyperParam        "NumHiddenLayers": 2,        1:[64, "sigmoid", keras.initializers.glorot_normal(seed=20)],        2:[32, "relu", keras.initializers.glorot_normal(seed=20)],    }    objs.append(DigitRecoginzer())    objs[i].one_hot_encoding()    objs[i].flatten_image()    objs[i].GenericModel(image_size, num_classes, HyperParam1, dp=False)
Now we will run the Birdseye Flask app using the command given below.
python -m birdseye
This is the home page of the Birdseye application where you will see all the function names that you need to monitor. We can have a closer look inside these functions by clicking them.
Here you can visualize the Start Time, Arguments of the functions, and results if any. This is how you can use Birdseye for code debugging. Go ahead try this with different functions and let me know your comments in the response section.
This article is in collaboration with Piyush Ingale.
Thanks for reading! If you want to get in touch with me, feel free to reach me at hmix13@gmail.com or my LinkedIn Profile. You can view my Github profile for different data science projects and packages tutorials. Also, feel free to explore my profile and read different articles I have written related to Data Science.