
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.applications import VGG16
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing.image import load_img

# Global parameters
image_size = 256
train_folder = r'/home/hs/TF/LandUse/Images/train/'
test_folder = r'/home/hs/TF/LandUse/Images/test/'
train_batchsize = 64
val_batchsize = 16

def create_model_with_additional_layers(model_name, image_size):
    if model_name == "vgg16":
        pretrained_model = VGG16(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))
    # Freeze all the layers
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    # Check the trainable status of the individual layers
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    # Create the model
    model = models.Sequential()
    # Add the vgg convolutional base model
    model.add(pretrained_model)
    # Add new layers
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    # Show a summary of the model. Check the number of trainable parameters
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == "vgg16":
        pretrained_model = VGG16(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))
    
    # Freeze all the layers
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False

    # Check the trainable status of the individual layers
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)

    # Create the model
    model = models.Sequential()

    # Add the vgg convolutional base model
    model.add(pretrained_model)

    # Add new layers
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))

    # Show a summary of the model. Check the number of trainable parameters
    print(model.summary())

    return model


def train_model(model, train_folder, test_folder, train_batchsize, val_batchsize, image_size, filename,
                epochs = 3,classmode='categorical', lr=1e-4):
    # No Data augmentation
    train_datagen = ImageDataGenerator(rescale=1./255)
    validation_datagen = ImageDataGenerator(rescale=1./255)

    # Data Generator for Training data
    train_generator = train_datagen.flow_from_directory(
            train_folder,
            target_size=(image_size, image_size),
            batch_size=train_batchsize,
            class_mode=classmode)

    # Data Generator for Validation data
    validation_generator = validation_datagen.flow_from_directory(
            test_folder,
            target_size=(image_size, image_size),
            batch_size=val_batchsize,
            class_mode=classmode,
            shuffle=False)

    # Compile the model
    model.compile(loss='categorical_crossentropy',
                  optimizer=optimizers.RMSprop(lr=lr),
                  metrics=['acc'])

    # Train the Model
    history = model.fit_generator(
      train_generator, train_generator.n // train_batchsize, epochs=epochs, workers=4,
        validation_data=validation_generator, validation_steps=validation_generator.n // val_batchsize)

    # Save the Model
    model.save(filename)

    return model, history


def plot_training_process(history):
    # Plot the accuracy and loss curves
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']

    epochs = range(len(acc))

    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()

    plt.figure()

    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()

    plt.show()

from random import randint

def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1. / 255)

    # Create a generator for prediction
    validation_generator = validation_datagen.flow_from_directory(
        test_folder,
        target_size=(image_size, image_size),
        batch_size=val_batchsize,
        class_mode='categorical',
        shuffle=False)

    # Get the filenames from the generator
    fnames = validation_generator.filenames

    # Get the ground truth from generator
    ground_truth = validation_generator.classes

    # Get the label to class mapping from the generator
    label2index = validation_generator.class_indices

    # Getting the mapping from class index to class label
    idx2label = dict((v, k) for k, v in label2index.items())

    # Get the predictions from the model using the generator
    predictions = model.predict_generator(validation_generator,
                                          steps=validation_generator.samples / validation_generator.batch_size,
                                          verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)

    errors = np.where(predicted_classes != ground_truth)[0]
    print("No of errors = {}/{}".format(len(errors), validation_generator.samples))

    # Show the errors
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]

        title = 'Original label:{}, Prediction :{}, confidence : {:.3f}'.format(
            fnames[errors[i]].split('/')[0],
            pred_label,
            predictions[errors[i]][pred_class])

        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()

if __name__ == "__main__":
    # Try VGG 16
    model_vgg16 = create_model_with_additional_layers(model_name="vgg16", image_size=image_size)
    model_trained_vgg16, history_vgg16 = train_model(epochs=20, lr=1e-4, model=model_vgg16, train_folder=train_folder, test_folder=test_folder, train_batchsize=train_batchsize, val_batchsize=val_batchsize, image_size=image_size,filename="vgg16_add_layers.h5")
    plot_training_process(history=history_vgg16)
    show_result(model_trained_vgg16, test_folder=test_folder, image_size=image_size)
92c29fbc27a02a7bea625eb17a84743c309ae033
<mask token>


def create_model_with_additional_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


<mask token>


def plot_training_process(history):
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs = range(len(acc))
    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    plt.figure()
    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    plt.show()


<mask token>


def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode='categorical', shuffle=False)
    fnames = validation_generator.filenames
    ground_truth = validation_generator.classes
    label2index = validation_generator.class_indices
    idx2label = dict((v, k) for k, v in label2index.items())
    predictions = model.predict_generator(validation_generator, steps=
        validation_generator.samples / validation_generator.batch_size,
        verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)
    errors = np.where(predicted_classes != ground_truth)[0]
    print('No of errors = {}/{}'.format(len(errors), validation_generator.
        samples))
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]
        title = ('Original label:{}, Prediction :{}, confidence : {:.3f}'.
            format(fnames[errors[i]].split('/')[0], pred_label, predictions
            [errors[i]][pred_class]))
        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()


<mask token>

<mask token>


def create_model_with_additional_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def train_model(model, train_folder, test_folder, train_batchsize,
    val_batchsize, image_size, filename, epochs=3, classmode='categorical',
    lr=0.0001):
    train_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    train_generator = train_datagen.flow_from_directory(train_folder,
        target_size=(image_size, image_size), batch_size=train_batchsize,
        class_mode=classmode)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode=classmode, shuffle=False)
    model.compile(loss='categorical_crossentropy', optimizer=optimizers.
        RMSprop(lr=lr), metrics=['acc'])
    history = model.fit_generator(train_generator, train_generator.n //
        train_batchsize, epochs=epochs, workers=4, validation_data=
        validation_generator, validation_steps=validation_generator.n //
        val_batchsize)
    model.save(filename)
    return model, history


def plot_training_process(history):
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs = range(len(acc))
    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    plt.figure()
    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    plt.show()


<mask token>


def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode='categorical', shuffle=False)
    fnames = validation_generator.filenames
    ground_truth = validation_generator.classes
    label2index = validation_generator.class_indices
    idx2label = dict((v, k) for k, v in label2index.items())
    predictions = model.predict_generator(validation_generator, steps=
        validation_generator.samples / validation_generator.batch_size,
        verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)
    errors = np.where(predicted_classes != ground_truth)[0]
    print('No of errors = {}/{}'.format(len(errors), validation_generator.
        samples))
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]
        title = ('Original label:{}, Prediction :{}, confidence : {:.3f}'.
            format(fnames[errors[i]].split('/')[0], pred_label, predictions
            [errors[i]][pred_class]))
        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()


if __name__ == '__main__':
    model_vgg16 = create_model_with_additional_layers(model_name='vgg16',
        image_size=image_size)
    model_trained_vgg16, history_vgg16 = train_model(epochs=20, lr=0.0001,
        model=model_vgg16, train_folder=train_folder, test_folder=
        test_folder, train_batchsize=train_batchsize, val_batchsize=
        val_batchsize, image_size=image_size, filename='vgg16_add_layers.h5')
    plot_training_process(history=history_vgg16)
    show_result(model_trained_vgg16, test_folder=test_folder, image_size=
        image_size)

<mask token>
image_size = 256
train_folder = '/home/hs/TF/LandUse/Images/train/'
test_folder = '/home/hs/TF/LandUse/Images/test/'
train_batchsize = 64
val_batchsize = 16


def create_model_with_additional_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def train_model(model, train_folder, test_folder, train_batchsize,
    val_batchsize, image_size, filename, epochs=3, classmode='categorical',
    lr=0.0001):
    train_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    train_generator = train_datagen.flow_from_directory(train_folder,
        target_size=(image_size, image_size), batch_size=train_batchsize,
        class_mode=classmode)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode=classmode, shuffle=False)
    model.compile(loss='categorical_crossentropy', optimizer=optimizers.
        RMSprop(lr=lr), metrics=['acc'])
    history = model.fit_generator(train_generator, train_generator.n //
        train_batchsize, epochs=epochs, workers=4, validation_data=
        validation_generator, validation_steps=validation_generator.n //
        val_batchsize)
    model.save(filename)
    return model, history


def plot_training_process(history):
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs = range(len(acc))
    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    plt.figure()
    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    plt.show()


<mask token>


def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode='categorical', shuffle=False)
    fnames = validation_generator.filenames
    ground_truth = validation_generator.classes
    label2index = validation_generator.class_indices
    idx2label = dict((v, k) for k, v in label2index.items())
    predictions = model.predict_generator(validation_generator, steps=
        validation_generator.samples / validation_generator.batch_size,
        verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)
    errors = np.where(predicted_classes != ground_truth)[0]
    print('No of errors = {}/{}'.format(len(errors), validation_generator.
        samples))
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]
        title = ('Original label:{}, Prediction :{}, confidence : {:.3f}'.
            format(fnames[errors[i]].split('/')[0], pred_label, predictions
            [errors[i]][pred_class]))
        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()


if __name__ == '__main__':
    model_vgg16 = create_model_with_additional_layers(model_name='vgg16',
        image_size=image_size)
    model_trained_vgg16, history_vgg16 = train_model(epochs=20, lr=0.0001,
        model=model_vgg16, train_folder=train_folder, test_folder=
        test_folder, train_batchsize=train_batchsize, val_batchsize=
        val_batchsize, image_size=image_size, filename='vgg16_add_layers.h5')
    plot_training_process(history=history_vgg16)
    show_result(model_trained_vgg16, test_folder=test_folder, image_size=
        image_size)

import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.applications import VGG16
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing.image import load_img
image_size = 256
train_folder = '/home/hs/TF/LandUse/Images/train/'
test_folder = '/home/hs/TF/LandUse/Images/test/'
train_batchsize = 64
val_batchsize = 16


def create_model_with_additional_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == 'vgg16':
        pretrained_model = VGG16(weights='imagenet', include_top=False,
            input_shape=(image_size, image_size, 3))
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    model = models.Sequential()
    model.add(pretrained_model)
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    print(model.summary())
    return model


def train_model(model, train_folder, test_folder, train_batchsize,
    val_batchsize, image_size, filename, epochs=3, classmode='categorical',
    lr=0.0001):
    train_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    train_generator = train_datagen.flow_from_directory(train_folder,
        target_size=(image_size, image_size), batch_size=train_batchsize,
        class_mode=classmode)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode=classmode, shuffle=False)
    model.compile(loss='categorical_crossentropy', optimizer=optimizers.
        RMSprop(lr=lr), metrics=['acc'])
    history = model.fit_generator(train_generator, train_generator.n //
        train_batchsize, epochs=epochs, workers=4, validation_data=
        validation_generator, validation_steps=validation_generator.n //
        val_batchsize)
    model.save(filename)
    return model, history


def plot_training_process(history):
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs = range(len(acc))
    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    plt.figure()
    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    plt.show()


from random import randint


def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1.0 / 255)
    validation_generator = validation_datagen.flow_from_directory(test_folder,
        target_size=(image_size, image_size), batch_size=val_batchsize,
        class_mode='categorical', shuffle=False)
    fnames = validation_generator.filenames
    ground_truth = validation_generator.classes
    label2index = validation_generator.class_indices
    idx2label = dict((v, k) for k, v in label2index.items())
    predictions = model.predict_generator(validation_generator, steps=
        validation_generator.samples / validation_generator.batch_size,
        verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)
    errors = np.where(predicted_classes != ground_truth)[0]
    print('No of errors = {}/{}'.format(len(errors), validation_generator.
        samples))
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]
        title = ('Original label:{}, Prediction :{}, confidence : {:.3f}'.
            format(fnames[errors[i]].split('/')[0], pred_label, predictions
            [errors[i]][pred_class]))
        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()


if __name__ == '__main__':
    model_vgg16 = create_model_with_additional_layers(model_name='vgg16',
        image_size=image_size)
    model_trained_vgg16, history_vgg16 = train_model(epochs=20, lr=0.0001,
        model=model_vgg16, train_folder=train_folder, test_folder=
        test_folder, train_batchsize=train_batchsize, val_batchsize=
        val_batchsize, image_size=image_size, filename='vgg16_add_layers.h5')
    plot_training_process(history=history_vgg16)
    show_result(model_trained_vgg16, test_folder=test_folder, image_size=
        image_size)


import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.applications import VGG16
from tensorflow.keras import models
from tensorflow.keras import layers
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing.image import load_img

# Global parameters
image_size = 256
train_folder = r'/home/hs/TF/LandUse/Images/train/'
test_folder = r'/home/hs/TF/LandUse/Images/test/'
train_batchsize = 64
val_batchsize = 16

def create_model_with_additional_layers(model_name, image_size):
    if model_name == "vgg16":
        pretrained_model = VGG16(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))
    # Freeze all the layers
    for layer in pretrained_model.layers[:]:
        layer.trainable = False
    # Check the trainable status of the individual layers
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)
    # Create the model
    model = models.Sequential()
    # Add the vgg convolutional base model
    model.add(pretrained_model)
    # Add new layers
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))
    # Show a summary of the model. Check the number of trainable parameters
    print(model.summary())
    return model


def create_model_with_retrainable_layers(model_name, image_size):
    if model_name == "vgg16":
        pretrained_model = VGG16(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))
    
    # Freeze all the layers
    for layer in pretrained_model.layers[:-4]:
        layer.trainable = False

    # Check the trainable status of the individual layers
    for layer in pretrained_model.layers:
        print(layer, layer.trainable)

    # Create the model
    model = models.Sequential()

    # Add the vgg convolutional base model
    model.add(pretrained_model)

    # Add new layers
    model.add(layers.Flatten())
    model.add(layers.Dense(1024, activation='relu'))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(21, activation='softmax'))

    # Show a summary of the model. Check the number of trainable parameters
    print(model.summary())

    return model


def train_model(model, train_folder, test_folder, train_batchsize, val_batchsize, image_size, filename,
                epochs = 3,classmode='categorical', lr=1e-4):
    # No Data augmentation
    train_datagen = ImageDataGenerator(rescale=1./255)
    validation_datagen = ImageDataGenerator(rescale=1./255)

    # Data Generator for Training data
    train_generator = train_datagen.flow_from_directory(
            train_folder,
            target_size=(image_size, image_size),
            batch_size=train_batchsize,
            class_mode=classmode)

    # Data Generator for Validation data
    validation_generator = validation_datagen.flow_from_directory(
            test_folder,
            target_size=(image_size, image_size),
            batch_size=val_batchsize,
            class_mode=classmode,
            shuffle=False)

    # Compile the model
    model.compile(loss='categorical_crossentropy',
                  optimizer=optimizers.RMSprop(lr=lr),
                  metrics=['acc'])

    # Train the Model
    history = model.fit_generator(
      train_generator, train_generator.n // train_batchsize, epochs=epochs, workers=4,
        validation_data=validation_generator, validation_steps=validation_generator.n // val_batchsize)

    # Save the Model
    model.save(filename)

    return model, history


def plot_training_process(history):
    # Plot the accuracy and loss curves
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']

    epochs = range(len(acc))

    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()

    plt.figure()

    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()

    plt.show()

from random import randint

def show_result(model, test_folder, image_size, classmode='categorical'):
    validation_datagen = ImageDataGenerator(rescale=1. / 255)

    # Create a generator for prediction
    validation_generator = validation_datagen.flow_from_directory(
        test_folder,
        target_size=(image_size, image_size),
        batch_size=val_batchsize,
        class_mode='categorical',
        shuffle=False)

    # Get the filenames from the generator
    fnames = validation_generator.filenames

    # Get the ground truth from generator
    ground_truth = validation_generator.classes

    # Get the label to class mapping from the generator
    label2index = validation_generator.class_indices

    # Getting the mapping from class index to class label
    idx2label = dict((v, k) for k, v in label2index.items())

    # Get the predictions from the model using the generator
    predictions = model.predict_generator(validation_generator,
                                          steps=validation_generator.samples / validation_generator.batch_size,
                                          verbose=1)
    predicted_classes = np.argmax(predictions, axis=1)

    errors = np.where(predicted_classes != ground_truth)[0]
    print("No of errors = {}/{}".format(len(errors), validation_generator.samples))

    # Show the errors
    for i in range(5):
        ind = randint(0, len(errors) - 1)
        pred_class = np.argmax(predictions[errors[ind]])
        pred_label = idx2label[pred_class]

        title = 'Original label:{}, Prediction :{}, confidence : {:.3f}'.format(
            fnames[errors[i]].split('/')[0],
            pred_label,
            predictions[errors[i]][pred_class])

        original = load_img('{}/{}'.format(test_folder, fnames[errors[i]]))
        plt.figure(figsize=[7, 7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()

if __name__ == "__main__":
    # Try VGG 16
    model_vgg16 = create_model_with_additional_layers(model_name="vgg16", image_size=image_size)
    model_trained_vgg16, history_vgg16 = train_model(epochs=20, lr=1e-4, model=model_vgg16, train_folder=train_folder, test_folder=test_folder, train_batchsize=train_batchsize, val_batchsize=val_batchsize, image_size=image_size,filename="vgg16_add_layers.h5")
    plot_training_process(history=history_vgg16)
    show_result(model_trained_vgg16, test_folder=test_folder, image_size=image_size)