Dog Breed Classification In Tensorflow 2

2313 views May 18, 2024

ကျွန်တော်တို့ ဒီနေ့ tutorial မှာတော့ ခွေးလေးတွေရဲ့ အမျိုးအစားကို ခွဲတဲ့ model လေးတစ်ခုကိုရေးပြသွားပါမယ်။ဒီမှာ Dataset သည် memory ပေါ်မှာ တင်ဖို့အဆင်မပြေတာကို ဘယ်လိုဖြေရှင်းသွားမလဲ နဲ့  transfer learning ပုံစံလေးရေးပြထားတာမို့ စိတ်ဝင်စားတယ့်သူများ အဆင်ပြေမယ်လို့ထင်ပါတယ်။

ပထမဦးဆုံး ကျွန်တော်တို့ Project Folder လေးကိုကြည့်လိုက်ရအောင်

dog_breed_classification
    data
    test_images
    config.py
    data_loader.py
    model.py
    test.py
    train.py
  •  

စသဖြင့် သူ့သက်ဆိုင်ရာနဲ့ရှိကြပါတယ်။data folder သည် dataset ထားဖို့ဖြစ်ပါတယ်။Dog breed classification dataset ဒီ link ကနေ Kaggle ကနေ download ဆွဲပြီး data folder ထဲမှာ train,test,labels.csv ဆိုပြီး extract လုပ်လိုက်ပါ။

ပထမဆုံးပြောချင်တာတော့ config.py ပါ။သူ့ထဲတွင် ကျွန်တော်တို့ လိုအပ်မယ့် configuration များအားလုံးရှိနေပါမယ်။data path နဲ့ ထားမယ့် batch size,epochs စသဖြင့်ရှိနေပါမယ်။

config.py

BASE_PATH = "./data"
EPOCHS = 5
size = 224  
lr = 1e-4 
BATCH_SIZE=64

data_loader.py

# import the necessary packages
import numpy as np
import cv2
import os
import tensorflow as tf 


def read_image(path, size):     
     image = cv2.imread(path, cv2.IMREAD_COLOR)     
     image = cv2.resize(image, (size, size),interpolation=cv2.INTER_AREA)     
     image = image / 255.0     
     image = image.astype(np.float32)     
     return image


def parse_data(x, y):
    x = x.decode()

    num_class = 120
    size = 224

    image = read_image(x, size)
    label = [0] * num_class
    label[y] = 1
    label = np.array(label,dtype=np.int32)
    return image, label

def tf_parse(x, y):
    x, y = tf.numpy_function(parse_data, [x, y], [tf.float32, tf.int32])
    x.set_shape((224, 224, 3))
    y.set_shape((120))
    return x, y


def tf_dataset(x, y, batch=64):
    dataset = tf.data.Dataset.from_tensor_slices((x, y))
    dataset = dataset.map(tf_parse)
    dataset = dataset.batch(batch)
    return dataset

data_loader.py သည် ကျွန်တော်တို့ data set သည် နည်းနည်းimage များပြီး ပုံများသည်လဲ size ကြီးတာမို့ memory ပေါ် အကုန်ပစ်တင်ထားရင် အဆင်မပြေနိုင်လို့ tensorflow data pipeline ကို အပေါ်ကတိုင်း သုံးထားပါတယ်။အဲ့တော့ image path တွေ label တွေကို tensorflow ကစီစဉ်ပေးပါလိမ့်မယ်။

model.py

import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras import backend as K

def build_model(size, num_classes=120, trainable=False):
    inputs = Input((size, size, 3))
    backbone = MobileNetV2(
        input_tensor=inputs, 
        include_top=False, 
        weights="imagenet")
    backbone.trainable = trainable
    x = backbone.output

    x = GlobalAveragePooling2D()(x)
    x = Dropout(0.2)(x)
    x = Dense(1024, activation="relu")(x)
    x = Dense(num_classes, activation="softmax")(x)

    model = tf.keras.Model(inputs, x)
    return model

ဒီမှာ ကျွန်တော်သည် train ရလွယ်အောင် accuracy နဲ့ model performance ကို သိပ်မကြည့်ပါဘူး။အဲ့တော့ model သည် သိပ်မကောင်းပါဘူး။MobileNetV2 ကိုပဲသုံးထားပါတယ်။tutorial purpose ပဲမို့ EPOCHS ကိုလဲ ၅ ပဲထားခဲ့တာတွေ့မှာပါ။မိတ်ဆွေကတော့ တကယ်ကောင်းကောင်းလေး လိုချင်ရင် epochs ကို ၂၀၀ လောက်ထားပြီး VGG16 ကိုသုံးကြည့်ပါလို့ အကြံပေးပါရစေ။အဲ့တော့ ကျွန်တော်တို့ လိုအပ်တဲ့ model တွေ လဲပြီးပြီဆိုတော့ train.py ကိုကြည့်ရအောင်။

train.py

import os
import numpy as np
import pandas as pd
from tensorflow.keras.callbacks import *
from tensorflow.keras.optimizers import SGD, Adam
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

from tensorflow.keras.models import load_model
from data_loader import tf_dataset
from model import build_model
from glob import glob
import matplotlib
import matplotlib.pyplot as plt
import config 
matplotlib.use("TkAgg")
import math

import tensorflow as tf
physical_devices = tf.config.experimental.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(physical_devices[0], True)

train_path = os.path.join(config.BASE_PATH, "train/*")     
labels_path = os.path.join(config.BASE_PATH, "labels.csv")

labels_df = pd.read_csv(labels_path)    
breed = labels_df["breed"].unique()       
print("Number of Breeds: ", len(breed))     
breed2id = {name:i for i, name in enumerate(breed)}
breeds = [name for i, name in enumerate(breed)]

image_paths = glob(train_path)
labels = []        
for image_path in image_paths:                 
    image_id = image_path.split("/")[-1].split(".")[0]                
    breed_name = list(labels_df[labels_df.id == image_id]["breed"])[0]                
    breed_idx = breed2id[breed_name]               
    labels.append(breed_idx)

# train test split
train_x, test_x = train_test_split(image_paths, test_size=0.2, random_state=42)
train_y, test_y = train_test_split(labels, test_size=0.2, random_state=42)

num_classes = len(breed)     

train_dataset = tf_dataset(train_x, train_y,batch=config.BATCH_SIZE)     
valid_dataset = tf_dataset(test_x, test_y,batch=config.BATCH_SIZE)


model = build_model(config.size,num_classes=num_classes,trainable=False)
model.compile(loss="categorical_crossentropy", optimizer=Adam(config.lr), metrics=["acc"])

callbacks = [
    ModelCheckpoint("model.h5", verbose=1),                 
    ReduceLROnPlateau(factor=0.1, patience=5, min_lr=1e-6)
]
H = model.fit(train_dataset,validation_data=valid_dataset,epochs=config.EPOCHS,callbacks=callbacks)

print("[INFO] evaluating network...")
predictions = model.predict(valid_dataset,batch_size=config.BATCH_SIZE)
print(classification_report(np.array(test_y),predictions.argmax(axis=1), target_names=breeds))

# plot model training
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, config.EPOCHS), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, config.EPOCHS), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, config.EPOCHS), H.history["acc"], label="acc")
plt.plot(np.arange(0, config.EPOCHS), H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.show()

ပထမဦးဆုံး ကျွန်တော် လိုအပ်တာတွေ import လုပ်လိုက်ပြီး ဒီမှာကျွန်တော် * တွေ import လုပ်ထားတာတွေ့မှာပါ။tutorial purpose ပဲမို့ပါ။မိတ်ဆွေတို့ကတော့ မလုပ်သင့်ပါဘူးနော်။

ပြီးရင်တော့ gpu memory growth error လေးတက်မှာဆိုးလို့ အောက်ကတိုင်းထားလိုက်ပါတယ်။

import tensorflow as tf
physical_devices = tf.config.experimental.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(physical_devices[0], True)

ပြီးရင်တော့ အောက်ကတိုင်း train path တွေ labels တွေ ကို read လုပ်လိုက်ပြီး scikitlearn ရဲ့ train_test_split နဲ့ train သက်သက် test သက်သက် ခွဲထုတ်ကာ data_loader.py တုန်းကရေးထားတဲ့ tf_dataset function ကိုခေါ်ကာ dataset တွေ ဆောက်လိုက်ပါတယ်။

train_path = os.path.join(config.BASE_PATH, "train/*")     
labels_path = os.path.join(config.BASE_PATH, "labels.csv")

labels_df = pd.read_csv(labels_path)    
breed = labels_df["breed"].unique()       
print("Number of Breeds: ", len(breed))     
breed2id = {name:i for i, name in enumerate(breed)}
breeds = [name for i, name in enumerate(breed)]

image_paths = glob(train_path)
labels = []        
for image_path in image_paths:                 
    image_id = image_path.split("/")[-1].split(".")[0]                
    breed_name = list(labels_df[labels_df.id == image_id]["breed"])[0]                
    breed_idx = breed2id[breed_name]               
    labels.append(breed_idx)

# train test split
train_x, test_x = train_test_split(image_paths, test_size=0.2, random_state=42)
train_y, test_y = train_test_split(labels, test_size=0.2, random_state=42)

num_classes = len(breed)     

train_dataset = tf_dataset(train_x, train_y,batch=config.BATCH_SIZE)     
valid_dataset = tf_dataset(test_x, test_y,batch=config.BATCH_SIZE)

ပြီးရင်တော့ model build လုပ်ကာ training data များထည့်ပြီး trainလိုက်ပါတယ်။ပြီးရင်တော့ train ပြီး loss တွေ accuracy တွေကို ကြည့်လိုက်ပါတယ်။

model = build_model(config.size,num_classes=num_classes,trainable=False)
model.compile(loss="categorical_crossentropy", optimizer=Adam(config.lr), metrics=["acc"])

callbacks = [
    ModelCheckpoint("model.h5", verbose=1),                 
    ReduceLROnPlateau(factor=0.1, patience=5, min_lr=1e-6)
]
H = model.fit(train_dataset,validation_data=valid_dataset,epochs=config.EPOCHS,callbacks=callbacks)

print("[INFO] evaluating network...")
predictions = model.predict(valid_dataset,batch_size=config.BATCH_SIZE)
print(classification_report(np.array(test_y),predictions.argmax(axis=1), target_names=breeds))

# plot model training
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, config.EPOCHS), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, config.EPOCHS), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, config.EPOCHS), H.history["acc"], label="acc")
plt.plot(np.arange(0, config.EPOCHS), H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.show()

အဲ့တော့ ကျွန်တော်တို့ python train.py ဆိုပြီး run လိုက်မယ်ဆို အောက်ကတိုင်းတွေ့ရပါလိမ့်မယ်။

ကျွန်တော်တို့ training ပြီးပြီဆိုတော့ ထွက်လာတဲ့ model ကိုအသုံးပြုကာ predict လုပ်ကြည့်ရတော့မှာမို့ test.py ကိုကြည့်ကြည့်ရအောင်။

test.py

import os
import numpy as np
import pandas as pd
import cv2
import config
import tensorflow as tf

def read_image(path, size):
    image = cv2.imread(path, cv2.IMREAD_COLOR)
    image = cv2.resize(image, (size, size))
    image = image / 255.0
    image = image.astype(np.float32)
    return image

if __name__ == "__main__":
    path = config.BASE_PATH
    labels_path = os.path.join(path, "labels.csv")

    labels_df = pd.read_csv(labels_path)
    breed = labels_df["breed"].unique()
    print("Number of Breed: ", len(breed))

    breednames = [name for i, name in enumerate(breed)]

    ## Model
    model = tf.keras.models.load_model("model.h5")

    image = read_image("./test_images/golden-retriever.jpg", 224)
    image = np.expand_dims(image, axis=0)
    pred = model.predict(image)[0]
    label_idx = np.argmax(pred)
    breed_name = breednames[label_idx]
    ori_image = cv2.imread("./test_images/golden-retriever.jpg", cv2.IMREAD_COLOR)

    ori_image = cv2.putText(ori_image, breed_name, (ori_image.shape[1] // 2, ori_image.shape[0] // 2), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 255), 2)
    cv2.imshow("Predicted",ori_image)
    cv2.waitKey(0) 

test.py သည် test_images folder ထဲက image ကို read လုပ်ပြီး model ထဲမှာ predict လုပ်ကာ ရလာတဲ့ result label ကို ပုံပေါ်မှာရေးပြီးပြပေးတာလေးပဲဖြစ်ပါတယ်။ကျွန်တော်တို့ test.py ကို run လိုက်မယ်ဆို အောက်ကတိုင်းတွေ့ရပါလိမ့်မယ်။
မှတ်ချက်။။test_images ထဲမှာ ပုံရှိရမယ်ဆိုတာတော့ သိပြီးသားဖြစ်မှာပါနော်။

လာရောက်ဖတ်ပေးတဲ့အတွက် အထူးကျေးဇူးတင်ပါတယ်ခင်ဗျာ။အဆင်ပြေကြပါစေ။

References

https://www.tensorflow.org/guide/data

https://github.com/nikhilroxtomar/Dog-Breed-Classifier-using-TF2.0