1. Load packages
1) Common packages
import os
from os.path import join, abspath, dirname
from tqdm import tqdm
import numpy as np
import pandas as pd
from dask import delayed, compute
from dask.diagnostics import ProgressBar
import sklearn
import cv2
2) TensorFlow packages
import tensorflow as tf
from tensorflow import keras
import tensorflow_addons as tfa
for gpu in tf.config.experimental.list_physical_devices('GPU'):
tf.config.experimental.set_memory_growth(gpu, True)
3) Parameters
class PATH:
root = abspath(dirname('../'))
input = join(root, 'open')
train = join(input, 'train')
test = join(input, 'test')
TEST_SIZE = 0.3
LABEL = 'label'
SIZE = 128
INPUT_SHAPE = (SIZE, SIZE, 3)
BATCH_SIZE = 32
RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)
tf.random.set_seed(RANDOM_STATE)
sklearn.random.seed(RANDOM_STATE)
2. Load dataset
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
@delayed
def load_image(path, size):
return cv2.resize(cv2.imread(path), (size, size)) / 255
train_full_data_meta = pd.read_csv(join(PATH.input, 'train_df.csv'), index_col=0)
train_data_meta, val_data_meta = train_test_split(train_full_data_meta, test_size=TEST_SIZE, stratify=train_full_data_meta[LABEL])
test_data_meta = pd.read_csv(join(PATH.input, 'test_df.csv'), index_col=0)
with ProgressBar():
X_train = np.array(compute(*[load_image(join(PATH.train, name), SIZE) for name in train_data_meta['file_name']]))
X_val = np.array(compute(*[load_image(join(PATH.train, name), SIZE) for name in val_data_meta['file_name']]))
X_test = np.array(compute(*[load_image(join(PATH.test, name), SIZE) for name in test_data_meta['file_name']]))
y_enc = OneHotEncoder(sparse=False)
y_train = y_enc.fit_transform(train_data_meta[['label']])
y_val = y_enc.transform(val_data_meta[['label']])
N_CLASSES = len(y_enc.categories_[0])
[########################################] | 100% Completed | 5.3s
[########################################] | 100% Completed | 2.1s
[########################################] | 100% Completed | 3.5s
def generate_dataset(X, y=None, batch_size=32):
MEAN_TRAIN = [0.485, 0.456, 0.406]
STD_TRAIN = [0.229, 0.224, 0.225]
normalize = lambda X, y=None: ((X-MEAN_TRAIN)/STD_TRAIN, y)
if y is None:
ds = tf.data.Dataset.from_tensor_slices(X)
else:
ds = tf.data.Dataset.from_tensor_slices((X, y)).shuffle(buffer_size=1000)
return ds.batch(batch_size).map(normalize, num_parallel_calls=tf.data.AUTOTUNE).cache().prefetch(tf.data.AUTOTUNE)
%%time
ds_train = generate_dataset(X_train, y_train, batch_size=BATCH_SIZE)
ds_val = generate_dataset(X_val, y_val, batch_size=BATCH_SIZE)
ds_test = generate_dataset(X_test, batch_size=BATCH_SIZE)
CPU times: user 6.68 s, sys: 5.6 s, total: 12.3 s
Wall time: 12.9 s
3. Training
1) Fix pretrained model
base_model = keras.applications.EfficientNetB0(include_top=False, input_shape=INPUT_SHAPE)
base_model.trainable = False
inputs = keras.layers.Input(INPUT_SHAPE)
hidden = base_model(inputs, training=False)
hidden = keras.layers.GlobalAveragePooling2D()(hidden)
outputs = keras.layers.Dense(N_CLASSES, activation='softmax')(hidden)
model = keras.Model(inputs, outputs)
model.compile(optimizer=keras.optimizers.Adam(2e-3), loss='categorical_crossentropy', metrics=[tfa.metrics.F1Score(num_classes=N_CLASSES, average='macro'), 'accuracy'])
model.summary()
Model: "model_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_4 (InputLayer) [(None, 128, 128, 3)] 0
_________________________________________________________________
efficientnetb0 (Functional) (None, 4, 4, 1280) 4049571
_________________________________________________________________
global_average_pooling2d_1 ( (None, 1280) 0
_________________________________________________________________
dense_1 (Dense) (None, 88) 112728
=================================================================
Total params: 4,162,299
Trainable params: 112,728
Non-trainable params: 4,049,571
_________________________________________________________________
from tensorflow.keras.callbacks import EarlyStopping
H = model.fit(ds_train, validation_data=ds_val, epochs=5, callbacks=[EarlyStopping(patience=5, restore_best_weights=True)])
Epoch 1/5
94/94 [==============================] - 12s 89ms/step - loss: 3.1952 - f1_score: 0.0196 - accuracy: 0.1627 - val_loss: 2.8756 - val_f1_score: 0.0133 - val_accuracy: 0.1526
Epoch 2/5
94/94 [==============================] - 7s 76ms/step - loss: 2.8180 - f1_score: 0.0373 - accuracy: 0.2693 - val_loss: 2.6708 - val_f1_score: 0.0389 - val_accuracy: 0.2967
Epoch 3/5
94/94 [==============================] - 7s 76ms/step - loss: 2.6575 - f1_score: 0.0525 - accuracy: 0.3425 - val_loss: 2.5371 - val_f1_score: 0.0553 - val_accuracy: 0.3684
Epoch 4/5
94/94 [==============================] - 8s 83ms/step - loss: 2.5429 - f1_score: 0.0621 - accuracy: 0.3939 - val_loss: 2.4350 - val_f1_score: 0.0604 - val_accuracy: 0.4011
Epoch 5/5
94/94 [==============================] - 7s 76ms/step - loss: 2.4522 - f1_score: 0.0694 - accuracy: 0.4347 - val_loss: 2.3517 - val_f1_score: 0.0632 - val_accuracy: 0.4174
2) Fine-tuning
base_model.trainable = True
model.compile(optimizer=keras.optimizers.Adam(2e-4), loss='categorical_crossentropy', metrics=[tfa.metrics.F1Score(num_classes=N_CLASSES, average='macro'), 'accuracy'])
H = model.fit(ds_train, validation_data=ds_val, epochs=5, callbacks=[EarlyStopping(patience=5, restore_best_weights=True)])
Epoch 1/5
94/94 [==============================] - 53s 363ms/step - loss: 3.7166 - f1_score: 0.0079 - accuracy: 0.0845 - val_loss: 3.2655 - val_f1_score: 0.0071 - val_accuracy: 0.0911
Epoch 2/5
94/94 [==============================] - 20s 218ms/step - loss: 3.1042 - f1_score: 0.0171 - accuracy: 0.1554 - val_loss: 2.4854 - val_f1_score: 0.0504 - val_accuracy: 0.3777
Epoch 3/5
94/94 [==============================] - 21s 225ms/step - loss: 1.7701 - f1_score: 0.0972 - accuracy: 0.5376 - val_loss: 1.1653 - val_f1_score: 0.1392 - val_accuracy: 0.7204
Epoch 4/5
94/94 [==============================] - 20s 217ms/step - loss: 1.2021 - f1_score: 0.1356 - accuracy: 0.6990 - val_loss: 1.0036 - val_f1_score: 0.1489 - val_accuracy: 0.7282
Epoch 5/5
94/94 [==============================] - 20s 216ms/step - loss: 1.0728 - f1_score: 0.1423 - accuracy: 0.7287 - val_loss: 0.9888 - val_f1_score: 0.1524 - val_accuracy: 0.7235
4. Inference
pred_test = model.predict(ds_test)
pred_test = y_enc.inverse_transform(pred_test)
pred_test.shape
(2154, 1)
PREVIOUSEtc