[英]Deep Learning Model gives inaccurate results in executable file program unlike the same script in python, messing up predictions
I made my first deep learning model for cancer detection using infrared image recognition through the Sequential DL model.我通过 Sequential DL 模型使用红外图像识别制作了我的第一个癌症检测深度学习模型。 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.在终端/命令中运行时,我能够通过 GUI python 脚本以所需的准确性运行以下代码,并通过以下代码获得足够好的结果。
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.上面的代码为上面看到的功能打开了一个带有 5 个按钮的 GUI 窗口。 I converted the above python script to an executable file through PyInstaller in an Virtual Environment.我在虚拟环境中通过 PyInstaller 将上述 python 脚本转换为可执行文件。 After multiple recursion errors(Recursion observed in opening binary cv2 extensions), caused by OpenCV, I installed an older version 4.5.5.在由 OpenCV 引起的多个递归错误(打开二进制 cv2 扩展时观察到递归)后,我安装了旧版本 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.然而,将癌症分类为良性、恶性和正常类型的功能大大降低,因为现在经过训练的模型将几乎所有图像分类为良性,准确率 > 99%。 The same image from the two models is classified differently as shown here: By the EXE Model and By the GUIPython Script来自两个模型的相同图像的分类方式不同,如下所示:按 EXE 模型和按 GUIPython 脚本
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.虽然我尝试使用 resource_path 函数通过 '''sys._MEIPASS''' 找到相对路径,但它可能不足以根据 .exe 应用程序的最佳功能使其他路径相对。
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.另一个问题可能是,在切换到早期版本的 OpenCV 时,递归限制保持不变,并且不允许读取数据集中的多个图像,从而导致准确性降低。
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.请帮助,因为我是编码和深度学习的新手,并且在没有任何关于如何纠正这个问题的线索的情况下遇到这个问题。
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.显然,使用早期版本的 OpenCV 来消除递归错误会导致所涉及的深度学习模型的图像读取和输入出现问题。 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.通过在 pyinstaller 命令中使用 '''--add data''' 来增加递归限制以进行 .exe 转换将递归限制从 1000 增加到 5000,从而允许 OpenCV 函数按需要工作并根据需要生成结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.