# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
import numpy as np
import matplotlib.pyplot as plt

# %matplotlib inline

import tensorflow as tf
from tensorflow import keras

from tensorflow.keras.preprocessing.image import load_img
path = './clothing-dataset-small/train/t-shirt'
name = '01d1fed7-996d-496b-b3ae-73ab724f29cc.jpg'
fullname = f'{path}/{name}'
img = load_img(fullname, target_size=(299, 299))
print(img)
display(img)
imgArray = np.array(img)


# +
# Pre-Trained Convolutional Neural Networks

# using existing model from https://keras.io/api/applications/xception/

from tensorflow.keras.applications.xception import Xception
from tensorflow.keras.applications.xception import preprocess_input
from tensorflow.keras.applications.xception import decode_predictions

model = Xception(weights='imagenet', input_shape=(299,299,3))

X = np.array([imgArray])
X = preprocess_input(X)
print(X.shape)
pred = model.predict(X)
print(pred.shape)

decode_predictions(pred)

# +
# Convolutional Neural Networks

# Transfer Learning, train base model

from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications.xception import preprocess_input

# generate data with augmentation. Generates more images by applying the image functions
train_gen = ImageDataGenerator(preprocessing_function=preprocess_input,
#                                rotation_range=30,
#                                width_shift_range=10.0,
#                                height_shift_range=10.0,
                               shear_range=10,
                               zoom_range=0.1,
                               vertical_flip=True)

train_ds = train_gen.flow_from_directory('./clothing-dataset-small/train', 
                                         target_size=(150,150), 
                                         batch_size=32)
print("Infered class_indices from folders:", train_ds.class_indices)
print()
print("Folders:")
# !ls -l clothing-dataset-small/train

X, y = next(train_ds)



val_gen = ImageDataGenerator(preprocessing_function=preprocess_input) #no augmentation, we want realistic results

val_ds = val_gen.flow_from_directory('./clothing-dataset-small/validation', 
                                     target_size=(150,150), 
                                     batch_size=32,
                                     shuffle=False)

base_model = Xception(weights='imagenet', 
                      include_top=False, #don't include the dense layers
                     input_shape=(150,150,3))

base_model.trainable = False #freeze convolutional layers

# +
# Build 4D model
inputs = keras.Input(shape=(150,150,3))
base = base_model(inputs, training=False)

outputs = base

model = keras.Model(inputs, outputs)
preds = model.predict(X)
print ("4D model shape:", preds.shape)

# Build 2D model
inputs = keras.Input(shape=(150,150,3))
base = base_model(inputs, training=False)
pooling=keras.layers.GlobalAveragePooling2D()
vectors = pooling(base)

outputs = vectors

model = keras.Model(inputs,outputs)
preds = model.predict(X)
print ("2D model shape:", preds.shape)

# +
# Build dense layer:
inputs = keras.Input(shape=(150,150,3))
base = base_model(inputs, training=False)
vectors = keras.layers.GlobalAveragePooling2D()(base)
outputs = keras.layers.Dense(10)(vectors)
model = keras.Model(inputs,outputs)
preds = model.predict(X)
preds.shape

learning_rate = 0.01
optimizer = keras.optimizers.Adam(learning_rate=learning_rate)
loss = keras.losses.CategoricalCrossentropy(from_logits=True)

model.compile (optimizer=optimizer, loss=loss, metrics=['accuracy'])
history = model.fit(train_ds, epochs=10, validation_data=val_ds)
# -

plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='val')
plt.xticks(np.arange(10))
plt.legend()

# +
from tensorflow.keras.applications.xception import Xception
from tensorflow.keras.applications.xception import preprocess_input
from tensorflow.keras.applications.xception import decode_predictions

def make_model(learning_rate=0.01, size_inner=10, droprate=0.5):
    base_model = Xception(weights='imagenet', 
                          include_top=False, #don't include the dense layers
                          input_shape=(150,150,3))

    base_model.trainable = False #freeze convolutional layers

    ### Build architecture:
    
    inputs = keras.Input(shape=(150,150,3))

    base = base_model(inputs, training=False)
    
    vectors = keras.layers.GlobalAveragePooling2D()(base)
    
    inner = keras.layers.Dense(size_inner, activation='relu')(vectors)
    drop = keras.layers.Dropout(droprate)(inner) #regularization to drop percetage of data when training (to randomly exclude logos)
    
    outputs = keras.layers.Dense(10)(inner)
    
    model = keras.Model(inputs,outputs)

    ### Build model:
    
    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)
    
    loss = keras.losses.CategoricalCrossentropy(from_logits=True)

    model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])
    
    return model

# try different learing rates:
scores = {}
for lr in [0.0001, 0.001, 0.01]:
    print("lr =",lr)
    model = make_model(lr)
    history = model.fit(train_ds, epochs=10, validation_data=val_ds)
    scores[lr] = history.history

# +
for lr, hist in scores.items():
    plt.plot(hist['accuracy'], label=lr)
#     plt.plot(hist['val_accuracy'], label=lr)
    
plt.xticks(np.arange(10))
plt.legend()

# +
# Checkpointing
# model.save_weights('model_v1.h5', save_format='h5')

learning_rate = 0.001
checkpoint = keras.callbacks.ModelCheckpoint('xception_v01_{epoch:02d}_{val_accuracy:.3f}.h5',
                                  save_best_only=True,
                                  monitor='val_accuracy',
                                  mode='auto')
model = make_model(learning_rate)
history = model.fit(train_ds, 
                    epochs=10, 
                    validation_data=val_ds,
                    callbacks=[checkpoint])



# +
# Adding More Layers

learning_rate = 0.001
scores = {}

for size in [10, 100, 1000]:
    print(lr)
    
    model = make_model(learning_rate=learning_rate, size_inner=size)
    history = model.fit(train_ds, epochs=2, validation_data=val_ds)
    scores[lr] = history.history
    
for size, hist in scores.items():
    plt.plot(hist['accuracy'], label=size)
#     plt.plot(hist['val_accuracy'], label=lr)
    
plt.xticks(np.arange(2))
plt.legend()    

# +
# Regularization
# A OLX logo on a Tshirt trains the model that the logo means TShirt. This is incorrect.
# playing with droprate

learning_rate = 0.001
size = 100

scores = {}

for droprate in [0.0, 0.2, 0.5, 0.8]:
    print(size)
    model = make_model(learning_rate=learning_rate,
                       size_inner=size,
                       droprate=droprate)
    history = model.fit(train_ds, epochs=3, validation_data=val_ds)
    scores[droprate] = history.history
    
    

# +
for dr, hist in scores.items():
    plt.plot(hist['accuracy'], label=dr)
#     plt.plot(hist['val_accuracy'], label=dr)
    
plt.xticks(np.arange(30))
plt.legend()

# +
# Test best model on test dataset

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications.xception import preprocess_input

best_model = keras.models.load_model('xception_v01_08_0.839.h5')

val_gen = ImageDataGenerator(preprocessing_function=preprocess_input)

test_ds = train_gen.flow_from_directory(
    './clothing-dataset-small/test',
    target_size=(299,299),
    batch_size=32,
    shuffle=False
)

best_model.evaluate(test_ds)

# +
# Apply best model to an image
from tensorflow.keras.preprocessing.image import load_img
import numpy as np

path = 'clothing-dataset-small/test/pants/c8d21106-bbdb-4e8d-83e4-bf3d14e54c16.jpg'
img = load_img(path, target_size=(150,150))
display(img)

x = np.array(img)
X = np.array([x])
print(X.shape)

X = preprocess_input(X)

pred = best_model.predict(X)
types = train_ds.class_indices.keys()
dict(zip(types, pred[0]))

StarcoderdataJupyterScriptsDedupFiltered