import os
import random
import pandas as pd
import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models,Sequential
import cv2, numpy as np
import os
"""
## We are using pretrained weights of inceptionV3
### [from->https://www.kaggle.com/ekaterinadranitsyna/keras-applications-models](https://www.kaggle.com/ekaterinadranitsyna/keras-applications-models)
adding it to our dataset,
"""
train_data_csv = '../input/petfinder-pawpularity-score/train.csv'
test_data_csv  = '../input/petfinder-pawpularity-score/test.csv'
train_folder = '../input/petfinder-pawpularity-score/train'
test_folder  = '../input/petfinder-pawpularity-score/test'
"""
## Hyperparameter for our newtowk
"""
y = 'Pawpularity'
validation_size = 0.25
autotune = tf.data.experimental.AUTOTUNE
img_size = 299
batch_size = 8
dropout = 0.2
lr = 1e-3
decay_steps = 100
decay_rate = 0.96
epochs = 30
def id_to_path(img_id,dir):
    return os.path.join(dir, f'{img_id}.jpg')
def get_image(path):
    image = tf.image.decode_jpeg(tf.io.read_file(path), channels=3)
    image = tf.cast(tf.image.resize_with_pad(image, img_size, img_size), dtype=tf.float32)
    return tf.keras.applications.inception_v3.preprocess_input(image)
def process_dataset(path, label):
    return get_image(path), label
def get_dataset(x, y=None):
    if y is not None:
        ds = tf.data.Dataset.from_tensor_slices((x, y))
        return ds.map(process_dataset, num_parallel_calls=autotune) \
            .batch(batch_size).prefetch(buffer_size=autotune)
    else:
        ds = tf.data.Dataset.from_tensor_slices(x)
        return ds.map(get_image, num_parallel_calls=autotune) \
            .batch(batch_size).prefetch(buffer_size=autotune)
data_train = pd.read_csv(train_data_csv)
data_train.head()
data_test = pd.read_csv(test_data_csv)
data_test.head()
data_train['path'] = data_train['Id'].apply(lambda x: id_to_path(x, train_folder))
data_test['path'] = data_test['Id'].apply(lambda x: id_to_path(x, test_folder))

train_subset, valid_subset = train_test_split(
    data_train[['path', y]],
    test_size=validation_size, shuffle=True, random_state=5
)
data_train.head()
data_train.path
train_data = get_dataset(x=train_subset['path'], y=train_subset[y]/100.).shuffle(1000)
valid_data = get_dataset(x=valid_subset['path'], y=valid_subset[y]/100.).shuffle(1000)
test_data = get_dataset(x=data_test['path'])
model = tf.keras.models.load_model('../input/keras-applications-models/InceptionV3.h5')
#model.trainable = False
len(model.layers)
for layer in model.layers[300:]:
    layer.trainable = True
model= tf.keras.models.Sequential(
    [
        tf.keras.layers.Input(shape=(img_size, img_size, 3)),
        tf.keras.layers.experimental.preprocessing.RandomFlip(mode="horizontal_and_vertical"),
        model,
        tf.keras.layers.BatchNormalization(),
        tf.keras.layers.Dropout(dropout, name='top_dropout'),
        tf.keras.layers.Dense(32, activation='elu'),
        tf.keras.layers.Dense(1)
    ]
)
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate=lr,
    decay_steps=decay_steps, decay_rate=decay_rate,staircase=True)

lr =tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.5, patience=5, verbose=90)
early_stop = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', patience=5, restore_best_weights=True)
from tensorflow.keras import backend as K
def rmse(y_true, y_pred):
    return K.sqrt(K.mean(K.square(y_true*100 - y_pred*100)))

model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),
                    loss=rmse,
                    metrics=[rmse])
history=model.fit(train_data,validation_data=valid_data, epochs=epochs,verbose=1,callbacks=[early_stop,lr],use_multiprocessing=True, workers=-1)
data_test[y] = model.predict(test_data,use_multiprocessing=True, workers=os.cpu_count())*100
data_test[['Id', y]].to_csv('submission.csv', index=False)
data_test[['Id', y]].head()