# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernel_info:
#     name: azureml_py38_tensorflow
#   kernelspec:
#     display_name: Python 3.8 - Tensorflow
#     language: python
#     name: azureml_py38_tensorflow
# ---

# + [markdown] pycharm={"name": "#%% md\n"}
# # 1. Imports

# + pycharm={"name": "#%%\n"} gather={"logged": 1634417615844}
from datetime import datetime
import matplotlib.pyplot as plt
import io
import numpy as np
import os
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import ResNet152V2
from tensorflow import keras
from tensorflow.keras import layers
from scipy.io import loadmat
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.applications.resnet_v2 import preprocess_input
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from azureml.core import Dataset, Run, Workspace
from imutils import paths

device_name = tf.test.gpu_device_name()
if device_name != '/device:GPU:0':
    raise SystemError('GPU device not found')
print('Found GPU at: {}'.format(device_name))
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
# -

# # 2. Setup constants

# + gather={"logged": 1634417615981}
path_names = {
        'DATA_PATH': os.path.join('data'),
        'MODEL_PATH': os.path.join('models'),
        'LOG_PATH': os.path.join('logs'),
        'TEST_PATH': os.path.join('test')
}

batch_size = 64
img_height = 224
img_width = 224

# + [markdown] nteract={"transient": {"deleting": false}}
# # 3. Download dataset

# + jupyter={"source_hidden": false, "outputs_hidden": true} nteract={"transient": {"deleting": false}} gather={"logged": 1634409363670}
run = Run.get_context()
ws = Workspace.from_config()

dataset_name = 'Smoking'

dataset = Dataset.get_by_name(workspace=ws, name=dataset_name)
dataset.download(path_names['DATA_PATH'])
# -

# # 4. Prepare labels and data

# + pycharm={"name": "#%%\n"} gather={"logged": 1634417944446}
data = []
labels = []
imagePaths = list(paths.list_images(path_names['DATA_PATH']))

for imagePath in imagePaths:
    label = imagePath.split(os.path.sep)[-2]
    image = load_img(imagePath, target_size=(224, 224))
    image = img_to_array(image)
    image = preprocess_input(image)
    data.append(image)
    labels.append(label)
data = np.array(data, dtype="float32")
labels = np.array(labels)
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels)
# -

# # 5. Load dataset

# + pycharm={"name": "#%%\n"} gather={"logged": 1634417945564}
(trainX, testX, trainY, testY) = train_test_split(data, labels,test_size=0.20, stratify=labels, random_state=42)

aug = ImageDataGenerator(
    rotation_range=20,
    zoom_range=0.15,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.15,
    horizontal_flip=True,
    fill_mode="nearest")
# -

# # 6. Build model

# + pycharm={"name": "#%%\n"} gather={"logged": 1634417950952}
backbone = ResNet152V2(weights='imagenet', include_top=False, input_shape=(img_width, img_height, 3))
backbone.trainable = False

input_layer = layers.Input((img_width, img_height, 3))

embedding = backbone(input_layer, training=False)
embedding = tf.keras.layers.AveragePooling2D(pool_size=(7, 7))(embedding)
embedding = tf.keras.layers.Flatten(name="flatten")(embedding)
embedding = tf.keras.layers.Dense(128, activation="relu")(embedding)
embedding = tf.keras.layers.Dropout(0.5)(embedding)
embedding = tf.keras.layers.Dense(2, activation="softmax")(embedding)

model = tf.keras.Model(inputs=[input_layer], outputs=[embedding])

opt = tf.keras.optimizers.Adam(lr=1e-4, decay=1e-8)
model.compile(loss="binary_crossentropy", optimizer=opt,metrics=["accuracy"])

model.summary()
# -

# # 7. Train only top layers

# + pycharm={"name": "#%%\n"} gather={"logged": 1634423432627}
early_stopping = tf.keras.callbacks.EarlyStopping(
    monitor="val_loss",
    min_delta=0.001,
    patience=10,
    mode="min",
    restore_best_weights=True,
)
log_dir = os.path.join(path_names['LOG_PATH'], datetime.now().strftime("%Y_%m_%d-%H_%M_%S"))
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=log_dir)

history = model.fit(aug.flow(trainX, trainY, batch_size=batch_size), epochs=1000, 
                    callbacks=[early_stopping, tensorboard_callback],
                    steps_per_epoch=len(trainX) // batch_size, validation_data=(testX, testY), 
                    validation_steps=len(testX) // batch_size)
# -

# # 8. Unfreeze backbone

# + pycharm={"name": "#%%\n"} gather={"logged": 1634423468465}
backbone.trainable = True

for layer in backbone.layers[:-110]:
    layer.trainable = False

model.compile(loss="binary_crossentropy", optimizer=opt,metrics=["accuracy"])


model.summary()
# -

# # 9. Train full model

# + pycharm={"name": "#%%\n"} gather={"logged": 1634425137202}
history = model.fit(aug.flow(trainX, trainY, batch_size=batch_size), epochs=1000, 
                    callbacks=[early_stopping, tensorboard_callback],
                    steps_per_epoch=len(trainX) // batch_size, validation_data=(testX, testY), 
                    validation_steps=len(testX) // batch_size)
# -

# # 10. Save model

# + pycharm={"name": "#%%\n"} gather={"logged": 1634425181651}
model.save(os.path.join(path_names['MODEL_PATH'], 'smoking.h5'))

# + [markdown] nteract={"transient": {"deleting": false}}
# # 11. Predict

# + jupyter={"source_hidden": false, "outputs_hidden": false} nteract={"transient": {"deleting": false}} gather={"logged": 1634428259545}
LABEL_MAP = {0:"Not smoking",
             1:"Smoking"}

fig,axes = plt.subplots(ncols=4,figsize=(4*4,4))

imagePaths = list(paths.list_images('test'))

for i in range(4):
    image = load_img(imagePaths[i], target_size=(224, 224))
    axes[i].imshow(image)
    axes[i].axis('off')
    image = img_to_array(image)
    image = preprocess_input(image)
    prediction = model.predict(np.expand_dims(image, 0))
    title = LABEL_MAP[0 if prediction[0][0] > 0.5 else 1]
    axes[i].set_title("{} {:0.2f}%".format(title, max(prediction[0]) * 100))

StarcoderdataJupyterScriptsDedupFiltered