Mengenal Pre-Trained Model: EfficientNet
Image Classification Series
Part I: Mengenal Convolutional Neural Network (CNN)
Part II: Pengenalan Jenis Bunga Menggunakan CNN
Part III: Mengenal Pre-trained Model CNN
Pada part sebelumnya, kita telah menyelesaikan project pengenalan jenis bunga menggunakan CNN. Salah satu cara untuk meningkatkan akurasi yaitu dengan menggunakan pre-trained model yang telah dilatih pada data yang besar. Nah, di part III ini kita akan membahas mengenai pre-trained model tersebut beserta praktiknya. Dalam hal ini masih digunakan data yang sama. Namun, pada bahasan kali ini akan fokus pada 1 model saja yaitu EfficientNet. Berikut disediakan Kaggle Notebook yang saya gunakan untuk project kali ini: [link]. Download dataset: [link].
Pre-trained Model
Pre-trained model merupakan suatu metode yang memanfaatkan model yang telah dilatih sebelumnya untuk mengatasi permasalahan baru dengan cara menjadikannya sebagai titik awal kemudian dilakukan pembaruan parameter sehingga cocok digunakan untuk permasalahan baru tersebut. Beberapa pre-trained model yang sering digunakan yaitu ResNet, DenseNet, Inception, AmoebaNet, NasNet, dan EfficientNet. Nah, pada bahasan kali ini kita akan fokus pada EfficientNet saja.
EfficientNet
EfficientNet merupakan salah satu pre-trained model CNN yang dikembangkan oleh Google pada tahun 2019. EfficientNet ini dirancang untuk mengatasi permasalahan pengenalan objek/gambar. EfficientNet ini memiliki 8 arsitektur, yaitu EfficientNet-B0 hingga EfficientNet-B7. Dimana semakin tinggi blok yang digunakan maka akan semakin tinggi juga jumlah parameter yang dihasilkan, namun hal ini juga diikuti oleh emakin tinggi akurasi yang diperoleh. EfficientNet ini terbukti mampu memprediksi gambar yang terdiri dari 1000 kelas dengan baik, bahkan mampu mengungguli pre-trained model yang telah ada sebelumnya.
Pada umumnya, model scaling dibangun dengan meningkatkan karakteristik lebar, kedalaman, dan resolusi ke tingkat yang jauh lebih tinggi lagi. Hal tersebut mampu meningkatkan akurasi, namun hal ini tentunya akan membuat model memiliki parameter yang sangat banyak sehingga cenderung tidak efisien. EfficientNet hadir untuk mengatasi permasalahan tersebut, model scaling dilakukan dengan cara bertahap pada semua karakteristik baik lebar, kedalaman, maupun resolusi ke tingkat yang lebih optimal atau efisien sehingga dinamakan dengan EfficentNet. Berikut ini ilustrasi penskalaan model pada EfficientNet.
Pada kompetisi ImageNet tahun 2019 yang bertujuan mendeteksi objek dan klasifikasi gambar dengan skala besar, EfficientNet mampu memberikan performa yang luar biasa dimana algoritma ini mampu memberikan akurasi yang lebih tinggi dibandingkan pre-trained model sebelumnya bahkan dengan jumlah parameter yang lebih sedikit seperti gambar berikut.
Arsitektur EfficientNet
Hal paling mendasar dari neural network adalah batang (stem) dilanjutkan dengan pembangunan arsitektur dimulai untuk kedelapan blok kemudian lapisan terakhir (final layers). Arsitektur dari stem dan final layers ditunjukkan oleh gambar berikut.
EfficientNet memiliki 8 arsitektur/blok. Setiap blok tersusun atas beberapa sub-blok (modul) yang bervariasi dan terus bertambah dari EfficientNet-B0 ke EfficientNet-B7. Berikut ini arsitektur dari sub-blok pada EfficientNet.
Kemudian, berikut ini 8 arsitektur/blok EfficientNet yang tersusun atas sub-blok mulai dari EfficientNet-B0 hingga EfficientNet-B7.
Terlihat jelas perbedaan kedelapan arsitektur EfficientNet yaitu terletak pada jumlah sub-blok yang akan meningkatkan jumlah parameternya.
Pengenalan Jenis Bunga Menggunakan EfficientNet
Untuk pengenalan jenis bunga menggunakan EfficientNet ini saya akan mencontohkan dengan model EfficientNet-B0.
Pertama-tama, impor package yang dibutuhkan untuk impor data serta menampilkan data dalam.
import os
from tqdm import tqdm
import numpy as np
import pandas as pd
import random
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import seaborn as sns
# Ignore the warnings
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
Lalu, untuk melihat jenis bunga yang terdapat pada data gunakan syntax berikut
import os
print(os.listdir('/kaggle/input/flowers-recognition/flowers'))
Maka akan terlihat jenis bunga yang ada pada data yaitu seperti berikut.
Data ini berisikan gambar-gambar yang telah dikelompokkan dalam 5 folder. 1 folder mewakili 1 jenis bunga. Lebih jelasnya, perhatikan gambar berikut.
Folder daisy semuanya berisi gambar bunga daisy, begitu juga dengan folder lain.
Impor Data
Dalam hal ini proses impor akan dilakukan dengan cara mengimpor 1 folder dan berikan label pada seluruh gambar di folder tersebut, lalu ulangi untuk folder lainnya. Pada proses impor ini, semua gambar juga akan diubah ke dalam ukuran yang sudah dianjurkan untuk EfficientNet seperti berikut.
Berikut ini syntax untuk mengimpor data beserta labelnya.
X=[]
L=[]
IMG_SIZE = 224
DAISY = '/kaggle/input/flowers-recognition/flowers/daisy'
SUNFLOWER = '/kaggle/input/flowers-recognition/flowers/sunflower'
TULIP = '/kaggle/input/flowers-recognition/flowers/tulip'
DANDELION = '/kaggle/input/flowers-recognition/flowers/dandelion'
ROSE = '/kaggle/input/flowers-recognition/flowers/rose'
def assign_label(img,flower_type):
return flower_type
def make_train_data(flower_type,DIR):
for img in tqdm(os.listdir(DIR)):
label = assign_label(img, flower_type)
path = os.path.join(DIR, img)
img = cv2.imread(path, cv2.IMREAD_COLOR)
img = cv2.resize(img, (IMG_SIZE,IMG_SIZE))
X.append(np.array(img))
L.append(str(label))
Dalam hal ini ukuran gambar untuk model EfficientNet-B0 yaitu 224x224 pixel. Lalu, impor data bunga dengan menggunakan fungsi make_train_data(jenis_bunga,directory) yang telah dibuat sebelumnya.
make_train_data('Daisy',DAISY)
make_train_data('Sunflower',SUNFLOWER)
make_train_data('Tulip',TULIP)
make_train_data('Dandelion',DANDELION)
make_train_data('Rose',ROSE)
print(len(X))
Maka, akan muncul output sebagai berikut.
Terlihat bahwa jumlah data yaitu sebanyak 4317 gambar bunga.
Setelah itu impor package yang dibutuhkan untuk pembuatan model seperti berikut.
import tensorflow as tf
#model selection
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import LabelEncoder
#preprocess.
from keras import backend as K
from keras.preprocessing.image import ImageDataGenerator
# specifically for cnn
from efficientnet.tfkeras import EfficientNetB0
from keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.callbacks import ReduceLROnPlateau
from tensorflow.keras.utils import to_categorical
Image Pre-processing
Pada tahap ini, akan dilakukan stadarisasi pada data gambar yang awalnya berada di rentang [0,255] akan diubah menjadi [0,1]. Selain itu, akan dilakukan categorical encoding pada label gambar menggunakan metode One-Hot Encoding. Syntax yang digunakan sebagai berikut.
# Standardization
X = np.array(X)
X = X/255
# Categorical encoding
le = LabelEncoder()
Y = le.fit_transform(L)
Y = to_categorical(Y,5)
Train-Test Split
Tahap selanjutnya yaitu membagi data menjadi data train dan data test. Hal ini dilakukan untuk proses validasi model yang diperoleh apakah baik digunakan untuk prediksi data baru. Dalam hal ini saya akan menggunakan perbandingan 80%:20%.
np.random.seed(2023)
random.seed(2023)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=42)
print("X_train: ", X_train.shape)
print("X_test: ", X_test.shape)
print("Y_train: ", Y_train.shape)
print("Y_test: ", Y_test.shape)
Maka akan diperoleh hasil sebagai berikut.
Dari gambar di atas dapat diketahui bahwa data yang dilakukan untuk proses training berjumlah 3453 sedangkan data yang digunakan untuk proses validasi berjumlah 864.
Training
Pada tahap training, layer pertama yaitu pre-trained model perlu di-freeze agar tidak terjadi pelatihan ulang sehingga bobot dan informasi yang telah dilatih sebelumnya tidak berubah. Untuk melakukan freeze layer dilakukan dengan mengubah argumen trainable menjadi False. Kemudian, layer setelah pre-trained model yaitu classifier layer dilatih dan akan mempelajari serta memperbarui bobot dan informasi dari fitur lama untuk memprediksi data baru. Model yang telah dibuat akan di-compile dengan epoch yang telah diatur sebanyak 20 epoch dengan batch size sebanyak 64 dan steps per epoch sebanyak 53.
Gunakan syntax berikut untuk melakukan pemodelan.
model = tf.keras.Sequential([
EfficientNetB0(weights='noisy-student', # imagenet
include_top=False,
pooling='avg'), # max
Dense(1024, activation='relu'),
Dropout(0.2),
Dense(5, activation='softmax')
])
model.layers[0].trainable = False
model.summary()
Maka akan diperoleh hasil sebagai berikut.
Output di atas menunjukkan arsitektur EfficientNet-B0 yang telah dibangun. Arsitektur tersebut memiliki total parameter sebesar 5366433 dengan parameter yang diatih sebanyak 1316869. Detail tipe layer, output layer, serta jumlah parameter juga dapat dilihat dari output di atas.
Lalu, compile model yang telah dibentuk. Dalam hal ini akan digunakan optimizer Adam dengan learning rate sebesar 0.001, categorical cross entropy loss, dan mertics accuracy untuk menentukan tingkat akurasi model karena kelas yang diprediksi terdiri dari 5 kelas bukan biner.
model.compile(optimizer = tf.keras.optimizers.Adam(lr=0.001), loss = 'categorical_crossentropy', metrics = ['accuracy'])Setelah itu, mengatur jumlah batch size dan epoch. Selain itu juga mengatur learning rate untuk mereduksi learning rate jika metrik akurasi tidak menunjukkan perkembangan.
Setelah itu, mengatur jumlah batch size dan epoch. Selain itu juga mengatur learning rate untuk mereduksi learning rate jika metrik akurasi tidak menunjukkan perkembangan.
batch_size = 64
epochs = 20
from keras.callbacks import ReduceLROnPlateau
red_lr = ReduceLROnPlateau(monitor = 'val_accuracy', patience = 3, verbose = 1, factor = 0.1)
Selanjutnya, melakukan augmentasi gambar untuk mengindari overfitting. Dalam hal ini saya akan melakukan rotasi (putar), shift (geser), serta flip (balik) pada gambar.
datagen = ImageDataGenerator(
featurewise_center = False, # set input mean to 0 over the dataset
samplewise_center = False, # set each sample mean to 0
featurewise_std_normalization = False, # divide inputs by std of the dataset
samplewise_std_normalization = False, # divide each input by its std
zca_whitening = False, # apply ZCA whitening
rotation_range = 10, # randomly rotate images in the range (degrees, 0 to 180)
zoom_range = 0.1, # Randomly zoom image
width_shift_range = 0.2, # randomly shift images horizontally (fraction of total width)
height_shift_range = 0.2, # randomly shift images vertically (fraction of total height)
horizontal_flip = True, # randomly flip images
vertical_flip = False) # randomly flip images
datagen.fit(X_train)
Setelah dibentuk model, lalu dilakukan fitting model. Dalam hal ini akan dilakukan perulangan (epoch) sebanyak 20 kali dan batch size sebanyak 128. Syntax yang digunakan sebagai berikut.
History = model.fit_generator(datagen.flow(X_train, Y_train, batch_size = batch_size),
epochs = epochs, validation_data = (X_test,Y_test),
verbose = 1, steps_per_epoch = X_train.shape[0] // batch_size)
Maka akan diperoleh hasil sebagai berikut.
Performa Model
Untuk mempermudah dalam melihat tingkat akurasi model, buatlah plot dari Training dan Validation Accuracy dengan syntax berikut.
plt.plot(History.history['loss'])
plt.plot(History.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.legend(['Train Loss', 'Test Loss'])
plt.show()
# Training and Vaidation Accuracy
plt.plot(History.history['accuracy'])
plt.plot(History.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend(['Train Accuracy', 'Test Accuracy'])
plt.show()
Dari hasil tersebut dapat diketahui bahwa tingkat akurasi model cukup bagus. Hal ini dapat dilihat dari training accuracy yang tinggi mencapai 96.43% dan validation accuracy yang tinggi mencapai 90.62%. Dapat dilihat juga bahwa model memiliki training loss yang rendah mencapai 0.1048 dan validation loss yang rendah mencapai 0.3044.
Selain itu, tingkat akurasi juga dapat dilihat dari confusion matrix. Berikut ini syntax yang digunakan untuk membuat confusion matrix. Dalam hal ini, saya akan menggunakan data validasi.
# Look at confusion matrix
from sklearn.metrics import confusion_matrix, accuracy_score
import itertools
def plot_confusion_matrix(cm, classes, normalize = False, title = 'Confusion matrix', cmap = plt.cm.Blues):
plt.imshow(cm, interpolation = 'nearest', cmap = cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation = 45)
plt.yticks(tick_marks, classes)
if normalize:
cm = cm.astype('float') / cm.sum(axis = 1)[:, np.newaxis]
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, cm[i, j], horizontalalignment = "center",
color = "white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
# Predict the values from the validation dataset
Y_pred = model.predict(X_test)
# Convert predictions classes to one hot vectors
Y_pred_classes = np.argmax(Y_pred,axis = 1)
# Convert validation observations to one hot vectors
Y_true = np.argmax(Y_test,axis = 1)
# compute the confusion matrix
confusion_mtx = confusion_matrix(Y_true, Y_pred_classes)
# plot the confusion matrix
plot_confusion_matrix(confusion_mtx, classes = range(5))
# accuracy
print("Accuracy : ", accuracy_score(Y_true, Y_pred_classes))
Maka akan diperoleh hasil sebagai berikut:
Dari confusion matrix di atas, x-axis merupakan data prediksi sedangkan y-axis merupakan data aktual. Sehingga, prediksi benar berada pada diagonal confusion matrix tersebut. Dari hasil tersebut diketahui bahwa tingkat akurasi model untuk memprediksi data validasi yaitu sebesar 89,58%. Dari hasil ini dapat disimpulkan bahwa model mampu memprediksi data baru.
Perbandingan dengan model CNN (part sebelumnya)
Sekarang coba kita bandingkan dengan model CNN yang telah dibuat sebelumnya.
Loss
Akurasi
Confusion matrix
Terihat bahwa EfficientNet lebih unggul jika dibandingkan dengan model CNN yang telah dibuat sebelumnya, lebih unggul dalam loss, acuracy, dan confusion matrix. Dan dapat kita lihat juga kenaikan akurasinya cukup signifikan.
Fine Tuning
Di proses sebelumnya, proses pelatihan hanya dilakukan pada classifier layer, sedangkan layer pre-trained model di-freeze dan bobotnya tidak berubah selama pelatihan. Salah satu cara untuk meningkatkan akurasi model yaitu melakukan fine tuning dilakukan dengan meng-unfreeze beberapa layer pre-trained model, sehingga akan membuat bobot menjadi lebih cocok dan spesifik pada data baru yaitu data jenis bunga ini. Fine tuning ini diterapkan secara efisien pada beberapa layer teratas dari pre-trained model karena semakin spesifik layer tersebut, sehingga layer-layer tersebut perlu beradaptasi/dicocokkan dengan data baru. Pada kali ini akan dilakukan fine tuning pada 20 layer teratas dari pre-trained model dan di-compile menggunakan 20 epochs dengan learning rate diturunkan menjadi 0.0001, sebelumnya 0.001.
Untuk melakukan unfreeze layer dilakukan dengan mengubah argumen trainable menjadi True. Berikut ini syntax untuk melakukan fine tuning.
from tensorflow.keras import layers
def unfreeze_model(model):
# We unfreeze the top 20 layers while leaving BatchNorm layers frozen
for layer in model.layers[-20:]:
if not isinstance(layer, layers.BatchNormalization):
layer.trainable = True
model.compile(optimizer = tf.keras.optimizers.Adam(lr=0.0001), loss = 'categorical_crossentropy', metrics = ['accuracy'])
unfreeze_model(model)
summary(model)
Maka, akan diperoleh hasil sebagai berikut.
Dari output tersebut dapat dilihat bahwa jumlah parameter yang dilatih menjadi lebih banyak yaitu sebesar 5324417, sebelumnya 1316869.
Kemudian, lakukan fitting model dengan syntax berikut.
ft_history = model.fit_generator(datagen.flow(X_train, Y_train, batch_size = batch_size),
epochs = epochs, validation_data = (X_test,Y_test),
verbose = 1, steps_per_epoch = X_train.shape[0] // batch_size)
Performa Model Setelah Fine Tuning
Untuk mempermudah dalam melihat tingkat akurasi model, buatlah plot dari Training dan Validation Loss serta Accuracy dengan syntax berikut.
# Get training and test loss histories
ft_training_loss = ft_history.history['loss']
ft_test_loss = ft_history.history['val_loss']
# Create count of the number of epochs
epoch_count = range(1, len(ft_training_loss) + 1)
# Visualize loss history
plt.plot(epoch_count, ft_training_loss, 'r--')
plt.plot(epoch_count, ft_test_loss, 'b-')
plt.legend(['Training Loss', 'Test Loss'])
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()
# Get training and test accuracy histories
ft_training_acc = ft_history.history['accuracy']
ft_test_acc = ft_history.history['val_accuracy']
# Create count of the number of epochs
epoch_count = range(1, len(ft_training_acc) + 1)
# Visualize accuracy history
plt.plot(epoch_count, ft_training_acc, 'r--')
plt.plot(epoch_count, ft_test_acc, 'b-')
plt.legend(['Training Accuracy', 'Test Accuracy'], loc='lower right')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.show()
Dari hasil tersebut dapat diketahui bahwa tingkat akurasi model sudah lebih bagus. Hal ini dapat dilihat dari training accuracy yang lebih tinggi mencapai 99.41% (sebelumnya 96.43%) dan validation accuracy yang lebih tinggi mencapai 93.63% (sebelumnya 90.62%). Dapat dilihat juga bahwa model memiliki training loss yang lebih rendah mencapai 0.0174 (sebelumnya 0.1048) dan validation loss yang lebih rendah mencapai 0.2724 (sebelumnya 0.3044).
Selain itu, tingkat akurasi juga dapat dilihat dari confusion matrix. Berikut ini syntax yang digunakan untuk membuat confusion matrix. Dalam hal ini, saya akan menggunakan data validasi.
# Predict the values from the validation dataset
Y_pred = model.predict(X_test)
# Convert predictions classes to one hot vectors
Y_pred_classes = np.argmax(Y_pred,axis = 1)
# Convert validation observations to one hot vectors
Y_true = np.argmax(Y_test,axis = 1)
# compute the confusion matrix
confusion_mtx = confusion_matrix(Y_true, Y_pred_classes)
# plot the confusion matrix
plot_confusion_matrix(confusion_mtx, classes = range(5))
# accuracy
print("Accuracy : ", accuracy_score(Y_true, Y_pred_classes))
print("Confusion Matrix : \n", confusion_mtx)
Maka akan diperoleh hasil sebagai berikut:
Dari hasil tersebut diketahui bahwa tingkat akurasi model untuk memprediksi data validasi sudah lebih tinggi dari sebelumnya yaitu sebesar 92,94%, sebelumnya 89,58%.
Kesimpulan
Dari percobaan yang teah dilakukan dapat kita simpulkan bahwa pre-trained model EfficientNet-B0 ini lebih unggul daripada model CNN konvensional sebelumnya, hal ini dikarenakan EfficientNet sudah dilatih untuk data yang jumlahnya sangat besar sehingga EfficientNet ini mampu memprediksi data yang jumlahnya lebih sedikit dengan baik. Tentunya tidak hanya EfficientNet saja melainkan masih banyak pre-trained model yang perlu dicoba.
Salah satu metode untuk meningkatkan akurasi pada pre-trained model yaitu dengan meakukan fine tuning dengan meng-unfreeze beberapa layer pre-trained model, sehingga akan membuat bobot menjadi lebih cocok dan spesifik pada data baru. Dari percobaan yang telah dilakukan, terlihat bahwa model memiliki performa yang lebih baik setelah dilakukan fine tuning sehingga fine tuning ini juga wajib dicoba ketika melakukan pemodelan menggunakan pre-trained model.
Sekian dan Terima kasih
Sumber:
- Agarwal, V. (2020, May 24). Complete Architectural Details of all EfficientNet Models. Diambil kembali dari Towards Data Science: https://towardsdatascience.com/complete-architectural-details-of-all-efficientnet-models-5fd5b736142
- Tan, M. & Quoc V. L. (2019). EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks. International Conference on Machine Learning, (hal. 36–46).