Home > Mobile >  Deep Learning Model gives inaccurate results in executable file program unlike the same script in py
Deep Learning Model gives inaccurate results in executable file program unlike the same script in py

Time:07-22

I made my first deep learning model for cancer detection using infrared image recognition through the Sequential DL model. I am able to run the following code through a GUI python script with the desired accuracy and results through the following code well enough when run in terminal/command.

from tkinter import *          # Tkinter is the Python interface to the Tk GUI(Graphical User Interface) toolkit - all libraries imported
from tkinter import filedialog #File dialog module will help open, save files or directories
import tkinter as tk         #Assigning alias to tkinter
import numpy as np                    #Importing Numpy as np alias
import pydot                                               #importing pydot for Graphviz
import graphviz                                            #Importing graphviz for graphing
import matplotlib.pyplot as plt                            #Importing matplotlib - Python Plot for graphing
import h5py                                                #For Data processing 
import tensorflow as tf                                    #Importing tensorflow model as tf alias
from keras.models import Sequential                        #Importing the Sequential model to train algorithm
from keras.layers import Dense                             #Importing Dense layer 
from keras.layers import Dropout                           #Importing Dropout layer for reducing associations
from keras.layers import Flatten                           #Importing Flatten Layer to compress multidimensional data to 1-D
from keras.layers.convolutional import Conv2D              
from keras.layers.convolutional import MaxPooling2D        #Importing 2D Convolutional Layers for training of algorithm 
from keras.utils import np_utils                            #Import NumPy related-utilities from keras utils
from keras import backend as K                              #Impoting Keras Backend API 
from keras.models import load_model                         #load_model can load a model for use which is saved by model.save
from keras.utils.vis_utils import plot_model                #Converts keras model to dot format and saves to a file.
import cv2                                                  #OpenCV library to visualise and extract Image data
import os                                                   #OS Module - to interact with underlying Operating System
import sys
import glob, random
from random import randint
from sklearn.model_selection import train_test_split        #Split arrays or matrices into random train and test subsets.
K.image_data_format()                                       #Returns the default image data format convention. - how backend treats image information
sys.setrecursionlimit(10**6)
def resource_path(relative_path):                               #Installs relative path over hard-coded path for EXE file to work
    """ Get absolute path to resource, works for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

model=1
path=r'C:\Users\Nitin_Sethi-PC\Desktop\PS-I\FINAL\Images'

#Creating window of standard size and giving Name to window
window = tk.Tk()
window.title("Graphical Interface for Cancer Detection Model")  
wd = str(window.winfo_screenwidth())   "x"   str(window.winfo_screenheight())
window.geometry(wd)

#Defining number of epochs, batchsize, folder path(to be made relative) and arrays for images and labels.
numepochs = 125
batchsize = 4
folder_path = r'C:\\Users\\Nitin_Sethi-PC\\Desktop\\PS-I\\FINAL\\Images'
images = []
labels = []
class_label = 0

#DEFINING FUNCTION FOR LOADING IMAGES FROM DATA/FOLDER - as done in earlier codes
def load_images_from_folder(folder,class_label):
    for filename in os.listdir(folder):                   #Until image is listed in folder
        img = cv2.imread(os.path.join(folder, filename))              #Read image using cv2.imread to read image from path
        if img is not None:
            img = cv2.resize(img,(140,92))                                 #Resizing img to specific size 140x92
            img = img.reshape(92,140,3)#Returns an array containing the same data with a new shape.
            #img = np.flip(img, axis=-1)                                    #Matplotlib and OpenCV load images inversely (RGB and BGR)
            #img_smt = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21) #NOISE REMOVAL INSTALLED - (image, ,FilterStrength,,templateWindowSize,searchWindowSize)        
            images.append(img)                                             #Resized image added to images array
            labels.append(class_label)                                     #Class_label appended to labels array
    class_label = class_label 1                                            #class_label value incremented for next image
    return class_label


# Defining FUNCTION For Larger(main) model, needed variables
def larger_model():
    # create model
    model = Sequential()  
    #1st Convolutional Layer(32 Filters)   MaxPooling2D
    model.add(Conv2D(32, (3, 3), padding="same",input_shape=(92,140,3), activation='relu'))  #(3,3) represents kernel size---> Always odd tuple
    #model.add(Conv2D(32, (3, 3), activation='relu',padding = 'same'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    #2nd Convolutional Layer(32 Filters)   MaxPooling2D
    model.add(Conv2D(32, (3, 3), activation='relu',padding = 'same'))
    #model.add(Conv2D(64, (3, 3), activation='relu',padding = 'same'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    #3rd Convolutional Layer(64 Filters)   MaxPooling2D
    model.add(Conv2D(64, (3, 3), activation='relu',padding = 'same'))
    #model.add(Conv2D(128, (3, 3), activation='relu',padding = 'same'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    #Dropping Associations and Flattening to 1 Dimesion
    model.add(Dropout(0.5))
    model.add(Flatten())
    model.add(Dropout(0.5))
    model.add(Dense(64, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(64, activation='relu'))
    model.add(Dropout(0.5))
    #model.add(Dense(50, activation='relu'))
    model.add(Dropout(0.5))
    
    #Output Layer   
    model.add(Dense(num_classes, activation='softmax'))                              
        
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

#Creating Class Labels and Loading Images From Benign, Malignant and Normal Folders
class_label = load_images_from_folder(folder_path '\\Benign',class_label)
class_label = load_images_from_folder(folder_path '\\Malignant',class_label)
class_label = load_images_from_folder(folder_path '\\Normal',class_label)

#Filling out Data and Labels array - asarray converts given input into array
Data = np.asarray(images)
Labels = np.asarray(labels)

#Creating variables for testing, training and splitting dataset as 20% to 80%
X_train,X_test,Y_train,Y_test=train_test_split(Data,Labels,test_size=0.2,random_state=2)

#X_train = tf.expand_dims(X_train, axis=-1) 

# Normalizing Pixel Inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs - Converting Categorical data into variables for Deep Learning model
Y_train = np_utils.to_categorical(Y_train)    #to_categorical Converts a class vector (integers) to binary class matrix.
Y_test = np_utils.to_categorical(Y_test)
num_classes = Y_test.shape[1]                 #Finds number of classes in Y_tests

#Printing sizes of various training and testing variables 
tr="Training Data shape:" "\n"
tr=tr "Testing Data shape:" "\n"
tr=tr str(X_test.shape) "\n"
tr=tr "Training Label shape:" "\n"
tr=tr str(Y_train.shape) "\n"
tr=tr "Testing Label shape:" "\n"
tr=tr str(Y_test.shape) "\n"


#FUNCTION FOR TRAINING THE MODEL MADE above
def training(X_train, Y_train,X_test, Y_test,tr):
    global hist                                      #Declaring Global Variable hist
    # Build the model
    model = larger_model()                           #Building model as larger_model made above
    # Fit the model - fit() => trains the model for a fixed number of epochs and set batchsize on X_train, Y_train and tests on X_test, Y_test
    hist  = model.fit(X_train, Y_train, validation_data = (X_test, Y_test), epochs = numepochs, batch_size = batchsize)
    #Giving Model Summary/Characteristics
    model.summary()
    # Ultimate Evaluation of the model - evaluate()- returns loss and metric value for the model in test mode. 
    scores = model.evaluate(X_test, Y_test, verbose=1,batch_size=batchsize)            #Verbose - allows us to see progress of each epoch
    model.save('BreastCancerDetector.h5')                                              #Saves the model made for use later
    print("Deep Neural Net Accuracy: %.2f%%" % (scores[1]*100)) 
    
    #Creating text field for printing Layer Architecture 
    greetings_disp = tk.Text(master = window, height=2, width=120, fg="midnight blue", font = ('Helvetica',14))  #Defining window, with height,width and foreground color
    greetings_disp.grid(column=0,row=3)                       #Positioning in Grid in the GUI Window
    greetings_disp2 = tk.Text(master = window, height=10, width=120, fg="midnight blue",font = ('Helvetica',14))  #Defining window, with height,width and foreground color
    greetings_disp2.grid(column=0,row=4)
    ly= ""                                                    #Layer ly string variable created - 
    
    #Printing Layer Architecture with training and accuracy results
    for layer in model.layers:
        ly=ly str(layer.name) "       "    "                layer input: \n" str(layer.input) "\n\n"          #str(layer.inbound_nodes) str(layer.outbound_nodes)      "            <<--inputs-->> \n\n"   tr 
    accuracy = ((scores[1]) *100)
    accuracyf = "{:.2f}".format(accuracy)
    greetings_disp.insert(tk.END ,"The Neural Network is trained with Accuracy  of: "  accuracyf  '%')
    greetings_disp2.insert(tk.END, "<<--DEEP LEARNING LAYER ARCHITECTURE-->> \n\n"  ly "\n")
    return model

#Defining varibles for plotting and actually Plotting in Matplotlib 
def graphh():

    # Visualizing losses and accuracy with number of epochs
    train_loss = hist.history['loss']                           #Training Loss
    val_loss   = hist.history['val_loss']                       #Validation Losses
    train_acc  = hist.history['accuracy']                       #Training Accuracy
    val_acc    = hist.history['val_accuracy']                   #Validation Accuracy
    xc         = range(numepochs)                               #Visualises for entire range of numepochs
 
    #plt.figure(1) - Training Loss and Validation Loss Trends - Loss Vs. Number of Epochs
    plt.figure(1, figsize = (10,5))
    plt.subplot(121)
    plt.plot(xc,train_loss)
    plt.plot(xc,val_loss)
    plt.xlabel('Number of Epochs')
    plt.ylabel('Loss')
    plt.title('Training Vs. Validation Loss')
    plt.grid(True)
    plt.legend(['Training','Validation'])
    plt.style.use(['classic'])

    #Training Accuracy and Validation Accuracy Trends - Accuracy Vs. Number of Epochs
    #plt.figure(2,figsize=(7,5))
    plt.subplot(122)
    plt.plot(xc,train_acc)
    plt.plot(xc,val_acc)
    plt.xlabel('Number of Epochs')
    plt.ylabel('Accuracy')
    plt.title('Training Vs. Validation Accuracy')
    plt.grid(True)

    plt.legend(['Training','Validation'],loc=4)
    plt.style.use(['classic'])
    plt.show()

#Testing a sample test image from the dataset   
def test_test(model):
    test_image = X_test[0:1]
    pa = model.predict(test_image)        #Predicting output based on test_image through model = output captured by pa
    classes_x = np.argmax(pa,axis=1)    #Returns the indices of the maximum values along an axis=1 Columns(Categories) = Maximum of 3 taken
    if(classes_x ==[0]):
        accuracy_b = ((pa[0][0]*100))
        accuracy_bf = "{:.2f}".format(accuracy_b)
        s="BENIGN with Accuracy: "   accuracy_bf   "%\n"
    elif(classes_x == [1]):
        accuracy_m = ((pa[0][1]*100))
        accuracy_mf = "{:.2f}".format(accuracy_m)
        s="MALIGNANT with Accuracy: "  accuracy_mf   "%\n"
    elif(classes_x ==[2]):
        accuracy_n = ((pa[0][2]*100))
        accuracy_nf = "{:.2f}".format(accuracy_n)
        s="NORMAL with Accuracy: "  accuracy_nf   "%\n"
    return s

#Testing Image uploaded by user through OpenCV
def test_random(model,path): 
    test_image = cv2.imread(path)                    #Reading image using OpenCV through imread function on path defined
    test_image= cv2.resize(test_image,(140,92))      #Resizing to desired dimensions
    test_image = test_image.reshape(92,140,3)        #Reshaping the desired dimensions - changing array structure
    test_image = np.array(test_image)                #Converting test image to numpy array for model input
    test_image = test_image.astype('float32')        #Casting to float values
    test_image /= 255                                #Normalizing to 1 from 255
    test_image= np.expand_dims(test_image, axis=0)   
    pa=model.predict(test_image)             
    classes_x = np.argmax(pa,axis=1)
    if(classes_x ==[0]):
        accuracy_b = ((pa[0][0]*100))
        accuracy_bf = "{:.2f}".format(accuracy_b)
        s="BENIGN with Accuracy: "   accuracy_bf   "%\n"
    elif(classes_x == [1]):
        accuracy_m = ((pa[0][1]*100))
        accuracy_mf = "{:.2f}".format(accuracy_m)
        s="MALIGNANT with Accuracy: "  accuracy_mf   "%\n"
    elif(classes_x ==[2]):
        accuracy_n = ((pa[0][2]*100))
        accuracy_nf = "{:.2f}".format(accuracy_n)
        s="NORMAL with Accuracy: "  accuracy_nf   "%\n"
    return s

#Function to Test Image from test_test functions
def b_test_test():
    greetings = test_test(model)
    #create text field and alloting position below relavant button
    greetings_disp = tk.Text(master = window,height = 1,width = 45 ,fg = "midnight blue", font = ('Helvetica',14))
    greetings_disp.grid(column = 0,row = 6)
    greetings_disp.insert(tk.END , greetings)

#Function to Show Random Image as selected by User - to view Processed image indpendently
def b_random_test_show():
    global path1
    path  = filedialog.askopenfilename(filetypes=(("JPG", ".jpg"), ("All files", "*.*")))
    path1 = path
    img   = cv2.imread(path1)                             #Reading image using OpenCV from path1 = path
    img   = np.flip(img, axis=-1) 
    plt.imshow(img)
    plt.show()

#Function for calling Model to Test Random Image as provided by User
def b_random_test():
    path = filedialog.askopenfilename(filetypes=(("JPG", ".jpg"), ("All files", "*.*")))
    greetings=test_random(model,path)
    #create text field
    greetings_disp =tk.Text(master=window,height=1,width=45 ,fg="midnight blue", font = ('Helvetica',14))
    greetings_disp.grid(column=0,row=12)
    greetings_disp.insert(tk.END , greetings)      #Shows output of model through test_random(model,path) function
    img=cv2.imread(path)
    plt.imshow(img)
    plt.show()

#Function for Training model on Training and Testing Data
def b_training():
    global model
    model = training(X_train, Y_train,X_test, Y_test,tr)

#Creating Heading Text in GUI Window
labelfont=('Proxima Nova', 39, 'bold')
label1 = tk.Label(text="Cancer Detection by Image Recognition using Deep Learning", anchor='n', font=labelfont , fg="midnight blue" , bg="mint cream", borderwidth = 5)
label1.grid(column=0,row=0)

#Create Instructions
labelfont2 = ('Proxima Nova', 16,'bold')
label2 = tk.Label(text='Please click \'Initiate Training\' to begin. Wait for the training to complete, the window might become unresponsive.', anchor ='w', font=labelfont2,fg="midnight blue" , bg="powder blue", bd=1, justify='left')
label2.grid(column=0, row=1)

#Creating Buttons under GUI and alloting space using the Grid System
buttonfont = ('Proxima Nova','13','bold')

button1 = tk.Button(border=2, text = "Initiate Training", command = b_training, bg = "powder blue", padx=66.8,pady=10) #17
button1.grid(column=0,row=2)
button1['font'] = buttonfont

button2 = tk.Button(text = "Test an Image from Dataset", command = b_test_test , bg = "powder blue",padx=20.3,pady=10) #26
button2.grid(column=0,row=5)
button2['font'] = buttonfont

button3 = tk.Button(text = "Display an Image from Dataset", command = b_random_test_show , bg = "powder blue", padx=9,pady=10) #28
button3.grid(column=0,row=8)
button3['font'] = buttonfont

button4 = tk.Button(text = "Upload Image for Testing", command = b_random_test, bg = "powder blue", padx=30,pady=10) #24
button4.grid(column=0,row=10)
button4['font'] = buttonfont

button5 = tk.Button(text = "See Loss and Accuracy plots", command = graphh, bg = "powder blue", padx=14,pady=10) #27
button5.grid(column=0,row=15)
button5['font'] = buttonfont

window.mainloop()

The above code brings up a GUI window with 5 buttons for the functions as seen above. I converted the above python script to an executable file through PyInstaller in an Virtual Environment. After multiple recursion errors(Recursion observed in opening binary cv2 extensions), caused by OpenCV, I installed an older version 4.5.5. which removed the recursion error and made the executable file as desired.

However, the functionality of classification of the cancer into benign, malignant and normal types was reduced considerably, as now the trained model classified almost all images as Benign with >99% accuracy. The same image from the two models is classified differently as shown here: By the EXE Model and By the GUIPython Script

I think possible errors may be occurring due to the hard-coded paths for the Image folders in the codes. While I have tried using resource_path function to find a relative path through '''sys._MEIPASS''' it might not be sufficient for making other paths relative as desired for optimum functioning of the .exe application.

Another issue can be that on switching to an earlier version of OpenCV, the recursion limit remained the same and did not allow multiple images in the dataset to be read, leading to a reduction in accuracy.

Please help as I am a novice to coding and deep learning, and am running into this issue without any clue on how to correct this.

CodePudding user response:

Solved the issue. Apparently using an earlier version of OpenCV to remove the recursion error leads to issues in image reading and inputting for the deep learning model involved. Increasing the recursion limit by using the '''--add data''' in pyinstaller command for .exe conversion increases recursion limit to 5000 from 1000, allowing the OpenCV function to work as desired and produce the results as needed.

  • Related