|
|
|
"""Butterfly classification with CNN.ipynb |
|
|
|
Automatically generated by Colab. |
|
|
|
Original file is located at |
|
https://colab.research.google.com/drive/18Jo5pBel2xJCse_nNq61zkDnPN_zzg_u |
|
|
|
# Import Libraries and Load Data |
|
""" |
|
|
|
|
|
import warnings |
|
warnings.filterwarnings("ignore") |
|
|
|
|
|
import numpy as np |
|
import pandas as pd |
|
import os |
|
|
|
|
|
import matplotlib.pyplot as plt |
|
import plotly.express as px |
|
import seaborn as sns |
|
import plotly.graph_objects as go |
|
|
|
|
|
import cv2 |
|
from tensorflow.keras.preprocessing.image import ImageDataGenerator |
|
|
|
|
|
from tensorflow.keras.models import Sequential, Model |
|
from tensorflow.keras.layers import Input, Dense , Conv2D , Dropout , Flatten , Activation, MaxPooling2D , GlobalAveragePooling2D |
|
from tensorflow.keras.optimizers import Adam , RMSprop |
|
from tensorflow.keras.layers import BatchNormalization |
|
from tensorflow.keras.callbacks import ReduceLROnPlateau , EarlyStopping , ModelCheckpoint , LearningRateScheduler |
|
from tensorflow.keras.applications import ResNet50V2 |
|
|
|
df = pd.read_csv('C:/Users/kamel/Documents/Image Classification/butterfly-dataset/butterflies and moths.csv') |
|
IMAGE_DIR = 'C:/Users/kamel/Documents/Image Classification/butterfly-dataset' |
|
df['filepaths'] = IMAGE_DIR + '/' + df['filepaths'] |
|
df.head() |
|
|
|
train_df = df.loc[df['data set'] == 'train'] |
|
val_df = df.loc[df['data set'] == 'valid'] |
|
test_df = df.loc[df['data set'] == 'test'] |
|
|
|
"""# Exploratory Data Analysis""" |
|
|
|
label_counts = df['labels'].value_counts()[:10] |
|
|
|
fig = px.bar(x=label_counts.index, |
|
y=label_counts.values, |
|
color=label_counts.values, |
|
text=label_counts.values, |
|
color_continuous_scale='Blues') |
|
|
|
fig.update_layout( |
|
title_text='Labels Distribution', |
|
template='plotly_white', |
|
xaxis=dict( |
|
title='Label', |
|
), |
|
yaxis=dict( |
|
title='Count', |
|
) |
|
) |
|
|
|
fig.update_traces(marker_line_color='black', |
|
marker_line_width=1.5, |
|
opacity=0.8) |
|
|
|
fig.show() |
|
|
|
"""# Generate Image using ImageDataGenerator""" |
|
|
|
|
|
train_gen = ImageDataGenerator(horizontal_flip=True, vertical_flip=True, rescale=1/255.) |
|
val_gen = ImageDataGenerator(rescale=1/255.) |
|
|
|
train_dir = 'C:/Users/kamel/Documents/Image Classification/butterfly-dataset/train' |
|
val_dir = 'C:/Users/kamel/Documents/Image Classification/butterfly-dataset/valid' |
|
|
|
BATCH_SIZE = 16 |
|
SEED = 56 |
|
IMAGE_SIZE = (244, 244) |
|
|
|
train_flow_gen = train_gen.flow_from_directory(directory=train_dir, |
|
class_mode='sparse', |
|
batch_size=BATCH_SIZE, |
|
target_size=IMAGE_SIZE, |
|
seed=SEED) |
|
|
|
val_flow_gen = val_gen.flow_from_directory(directory=val_dir, |
|
class_mode='sparse', |
|
batch_size=BATCH_SIZE, |
|
target_size=IMAGE_SIZE, |
|
seed=SEED) |
|
|
|
"""# Create Model""" |
|
|
|
verbose=False |
|
|
|
input_tensor = Input(shape=(224, 224, 3)) |
|
|
|
base_model = ResNet50V2(input_tensor=input_tensor, include_top=False, weights='imagenet') |
|
|
|
bm_output = base_model.output |
|
|
|
x = GlobalAveragePooling2D()(bm_output) |
|
x = Dense(1024, activation='relu')(x) |
|
x = Dropout(rate=0.5)(x) |
|
output = Dense(100, activation='softmax')(x) |
|
model = Model(inputs=input_tensor, outputs=output) |
|
|
|
if verbose: |
|
model.summary() |
|
|
|
"""# ResNet Modelling""" |
|
|
|
model.compile(optimizer=Adam(lr=0.001), loss='sparse_categorical_crossentropy', metrics=['accuracy']) |
|
|
|
rlr_cb = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, mode='min', verbose=0) |
|
early_cb = EarlyStopping(monitor='val_loss', patience=5, mode='min', verbose=0) |
|
|
|
model.fit(train_flow_gen, epochs=5, |
|
steps_per_epoch=int(np.ceil(train_df.shape[0]/BATCH_SIZE)), |
|
validation_data=val_flow_gen, |
|
validation_steps=int(np.ceil(val_df.shape[0]/BATCH_SIZE)), |
|
callbacks=[rlr_cb, early_cb]) |
|
|
|
test_dir = 'C:/Users/kamel/Documents/Image Classification/butterfly-dataset/test' |
|
test_gen = ImageDataGenerator(rescale=1/255.) |
|
test_flow_gen = test_gen.flow_from_directory(directory=test_dir, |
|
class_mode='sparse', |
|
batch_size=BATCH_SIZE, |
|
target_size=IMAGE_SIZE, |
|
seed=SEED) |
|
|
|
print('ResNet Test Data Accuracy: {0}'.format(model.evaluate(test_flow_gen)[1:][0])) |
|
|
|
|
|
model.save('C:/Users/kamel/Documents/Image Classification/model_checkpoint_manual_effnet.h5') |
|
|
|
"""# Deployment""" |
|
|
|
import gradio as gr |
|
import tensorflow as tf |
|
from tensorflow.keras.models import load_model |
|
import numpy as np |
|
import cv2 |
|
|
|
|
|
model_path = 'C:/Users/kamel/Documents/Image Classification/model_checkpoint_manual_effnet.h5' |
|
model = load_model(model_path) |
|
|
|
class_names = ['ADONIS', 'AFRICAN GIANT SWALLOWTAIL', 'AMERICAN SNOOT', 'AN 88', 'APPOLLO', 'ARCIGERA FLOWER MOTH', 'ATALA', 'ATLAS MOTH', 'BANDED ORANGE HELICONIAN', 'BANDED PEACOCK'] |
|
|
|
|
|
def preprocess_image(img): |
|
|
|
if isinstance(img, str): |
|
|
|
img = cv2.imread(img) |
|
img = cv2.resize(img, (224, 224)) |
|
img = img / 255.0 |
|
img = np.expand_dims(img, axis=0) |
|
elif isinstance(img, np.ndarray): |
|
|
|
img = cv2.resize(img, (224, 224)) |
|
img = img / 255.0 |
|
img = np.expand_dims(img, axis=0) |
|
else: |
|
raise ValueError("Unsupported input type. Please provide a file path or a NumPy array.") |
|
|
|
return img |
|
|
|
|
|
def classify_image(img): |
|
|
|
img = preprocess_image(img) |
|
|
|
|
|
predictions = model.predict(img) |
|
|
|
|
|
predicted_class = np.argmax(predictions) |
|
|
|
|
|
predicted_class_name = class_names[predicted_class] |
|
|
|
return f"Predicted Class: {predicted_class_name}" |
|
|
|
|
|
iface = gr.Interface(fn=classify_image, |
|
inputs="image", |
|
outputs="text", |
|
live=True) |
|
|
|
|
|
iface.launch() |
|
|
|
|