# ---
# 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
# ---

# + [markdown] id="nRhzDn1IObLk"
# # Colab-UnsupervisedClassification
#
# Original repo: [ardamavi/Unsupervised-Classification-with-Autoencoder](https://github.com/ardamavi/Unsupervised-Classification-with-Autoencoder)
#
# Original colab: [here](https://colab.research.google.com/github/ardamavi/Unsupervised-Classification-with-Autoencoder/blob/master/Unsupervised%20Classification%20With%20Autoencoder.ipynb)
#
# My fork: [styler00dollar/Colab-UnsupervisedClassification](https://github.com/styler00dollar/Colab-UnsupervisedClassification)
#
# Contains a few improvements, like fewer boxes, OpenCV, robuster data loading (jpg/png glob) and tqdm.

# + id="wmAp6M8YKySb"
# !nvidia-smi

# + id="GMX5UupjK2Rz" cellView="form"
#@title install
# !git clone https://github.com/ardamavi/Unsupervised-Classification-with-Autoencoder
# #!pip install scipy==1.1.0

# + [markdown] id="yVHfBLjoO3fJ"
# # Prepare data

# + id="8zYqdpu0KLIo" cellView="form"
#@title example dog/cat dataset
import os
import numpy as np
from os import listdir
from scipy.misc import imread, imresize
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
import keras
import numpy as np
from keras.datasets import mnist
import matplotlib.pyplot as plt
# %matplotlib inline

def get_img(data_path):
    # Getting image array from path:
    img_size = 64 #@param {type:"number"}
    #img = imread(data_path)
    #img = imresize(img, (img_size, img_size, 3))

    img = cv2.imread(data_path)
    img = cv2.resize(img, (img_size, img_size))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    return img

def get_dataset(dataset_path='/content/Unsupervised-Classification-with-Autoencoder/Examples/Dog-Cat/Data/Train_Data/'):
    # Getting all data from data path:
    try:
        X = np.load('Data/npy_train_data/X.npy')
        Y = np.load('Data/npy_train_data/Y.npy')
    except:
        labels = listdir(dataset_path) # Geting labels
        X = []
        Y = []
        for i, label in enumerate(labels):
            datas_path = dataset_path+'/'+label
            for data in listdir(datas_path):
                img = get_img(datas_path+'/'+data)
                X.append(img)
                Y.append(i)
        # Create dateset:
        X = np.array(X).astype('float32')/255.
        Y = np.array(Y).astype('float32')
        Y = to_categorical(Y, 2)
        if not os.path.exists('Data/npy_train_data/'):
            os.makedirs('Data/npy_train_data/')
        np.save('Data/npy_train_data/X.npy', X)
        np.save('Data/npy_train_data/Y.npy', Y)
    X, X_test, Y, Y_test = train_test_split(X, Y, test_size=0.1, random_state=42)
    return X, X_test, Y, Y_test

# Getting Dataset:
X_train, X_test, Y_train, Y_test = get_dataset()

# Checkpoints:
from keras.callbacks import ModelCheckpoint, TensorBoard
checkpoints = []
#checkpoints.append(TensorBoard(log_dir='/Checkpoints/logs'))

# + [markdown] id="i8hgn1YLPFod"
# Or use your own data and amount of classes. Example structure is [here](https://github.com/ardamavi/Unsupervised-Classification-with-Autoencoder/tree/master/Examples/Dog-Cat/Data/Train_Data).

# + cellView="form" id="qhh5-mr6P0ap"
#@title Mount Google Drive
from google.colab import drive
drive.mount('/content/drive')
print('Google Drive connected.')

# + cellView="form" id="zcRyxuoYQHUl"
#@title copy/extract data
# !cp /content/drive/MyDrive/classification.7z /content/dataset.7z
# %cd /content/
!7z x /content/dataset.7z

# + id="LH6NruuMQ1rg" cellView="form"
#@title example own data
import os
import numpy as np
from os import listdir
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
import keras
import numpy as np
from keras.datasets import mnist
import matplotlib.pyplot as plt
from tqdm import tqdm
import glob
import cv2
# %matplotlib inline

dataset_path = '/content/images/' #@param {type:"string"}
num_classes = 2 #@param {type:"number"}

def get_img(data_path):
    # Getting image array from path:
    img_size = 64 #@param {type:"number"}
    #img = imread(data_path)
    #img = imresize(img, (img_size, img_size, 3))

    img = cv2.imread(data_path)
    img = cv2.resize(img, (img_size, img_size))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    return img

def get_dataset(dataset_path=dataset_path):
    # Getting all data from data path:
    try:
        X = np.load('Data/npy_train_data/X.npy')
        Y = np.load('Data/npy_train_data/Y.npy')
    except:
        labels = listdir(dataset_path) # Geting labels
        X = []
        Y = []
        for i, label in enumerate(labels):
            datas_path = dataset_path+'/'+label
            #for data in listdir(datas_path):
            #print("datas_path")
            #print(datas_path)
            files = glob.glob(datas_path + '/**/*.png', recursive=True)
            files_jpg = glob.glob(datas_path + '/**/*.jpg', recursive=True)
            files.extend(files_jpg)
            for data in tqdm(files):

                img = get_img(data)
                X.append(img)
                Y.append(i)
        # Create dateset:
        X = np.array(X).astype('float32')/255.
        Y = np.array(Y).astype('float32')
        Y = to_categorical(Y, num_classes)
        if not os.path.exists('Data/npy_train_data/'):
            os.makedirs('Data/npy_train_data/')
        np.save('Data/npy_train_data/X.npy', X)
        np.save('Data/npy_train_data/Y.npy', Y)
    X, X_test, Y, Y_test = train_test_split(X, Y, test_size=0.1, random_state=42)
    return X, X_test, Y, Y_test

# Getting Dataset:
X_train, X_test, Y_train, Y_test = get_dataset()

# Checkpoints:
from keras.callbacks import ModelCheckpoint, TensorBoard
checkpoints = []
#checkpoints.append(TensorBoard(log_dir='/Checkpoints/logs'))

# + [markdown] id="SSpMEcPSPBI1"
# # Train

# + id="TQaTm4p_J8pC" cellView="form"
#@title display info
# About Dataset:
img_size = X_train.shape[1] # 64
print('Training shape:', X_train.shape)
print(X_train.shape[0], 'sample,',X_train.shape[1] ,'x',X_train.shape[2] ,'size RGB image.\n')
print('Test shape:', X_test.shape)
print(X_test.shape[0], 'sample,',X_test.shape[1] ,'x',X_test.shape[2] ,'size RGB image.\n')

print('Examples:')
n = 10
plt.figure(figsize=(20, 4))
for i in range(1, n+1):
    # Display some data:
    ax = plt.subplot(1, n, i)
    plt.imshow(X_train[i])
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

# Deep Learning Model:
from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, Dense
from keras.models import Model

input_img = Input(shape=(64, 64, 3))

x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)

x = Conv2D(64, (3, 3), activation='relu', padding='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(x)

autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='rmsprop', loss='mse')

autoencoder.summary()

# + id="IyvIcIgmJ8pE" cellView="form"
#@title train
# Creates live data:
# For better yield. The duration of the training is extended.

from keras.preprocessing.image import ImageDataGenerator
generated_data = ImageDataGenerator(featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, zca_whitening=False, rotation_range=0,  width_shift_range=0.1, height_shift_range=0.1, horizontal_flip = True, vertical_flip = False)
generated_data.fit(X_train)

epochs = 100 #@param {type:"number"}
batch_size = 16 #@param {type:"number"}

#autoencoder.fit_generator(generated_data.flow(X_train, X_train, batch_size=batch_size), steps_per_epoch=X.shape[0], epochs=epochs, validation_data=(X_test, X_test), callbacks=checkpoints)

# Training Model:
autoencoder.fit(X_train, X_train, batch_size=batch_size, epochs=epochs, validation_data=(X_test, X_test), shuffle=True, callbacks=checkpoints)

decoded_imgs = autoencoder.predict(X_test)

# + id="38aeS_2DJ8pF" cellView="form"
#@title plot images
n = 10 #@param {type:"number"}
plt.figure(figsize=(20, 4))
for i in range(1, n+1):
    # Display original:
    ax = plt.subplot(2, n, i)
    plt.imshow(X_test[i])
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # Display reconstruction:
    ax = plt.subplot(2, n, i+n)
    plt.imshow(decoded_imgs[i])
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

# + id="gzZIAapPJ8pF" cellView="form"
#@title model
# Describe the number of classes:
num_class = 2 #@param {type:"number"}

from keras import backend as K

# Custom classifier function:
def classifier_func(x):
    return x-x+K.one_hot(K.argmax(x, axis=1), num_classes=num_class)

# Deep Learning Model:
from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, Dense, Activation, Lambda, Flatten, concatenate, Reshape
from keras.models import Model

input_img = Input(shape=(64, 64, 3))

layer_1 = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
layer_1 = MaxPooling2D((2, 2))(layer_1)

layer_2 = Conv2D(64, (3, 3), activation='relu', padding='same')(layer_1)
layer_2 = MaxPooling2D((2, 2))(layer_2)

layer_3 = Conv2D(64, (3, 3), activation='relu', padding='same')(layer_2)
layer_3 = MaxPooling2D((2, 2))(layer_3)

flat_1 = Flatten()(layer_3)

fc_1 = Dense(256)(flat_1)
fc_1 = Activation('relu')(fc_1)

fc_2 = Dense(128)(fc_1)
fc_2 = Activation('relu')(fc_2)

fc_3 = Dense(num_class)(fc_2)
act_class = Lambda(classifier_func, output_shape=(num_class,))(fc_3)

# Merge Layers:

merge_1 = concatenate([act_class, fc_2])

#Decoder:
fc_4 = Dense(256)(merge_1)
fc_4 = Activation('relu')(fc_4)

fc_5 = Dense(4096)(fc_4)
fc_5 = Activation('relu')(fc_5)

reshape_1 = Reshape((8, 8, 64))(fc_5)

layer_4 = UpSampling2D((2, 2))(reshape_1)
layer_4 = Conv2D(64, (3, 3), activation='relu', padding='same')(layer_4)

layer_5 = UpSampling2D((2, 2))(layer_4)
layer_5 = Conv2D(64, (3, 3), activation='relu', padding='same')(layer_5)

layer_6 = UpSampling2D((2, 2))(layer_5)
layer_6 = Conv2D(32, (3, 3), activation='relu', padding='same')(layer_6)

layer_7 = Conv2D(3, (3, 3), activation='sigmoid', padding='same')(layer_6)

autoencoder = Model(input_img, layer_7)
autoencoder.compile(optimizer='rmsprop', loss='mse')

autoencoder.summary()

# + id="Cl85-fT7J8pG" cellView="form"
#@title train
# Creates live data:
# For better yield. The duration of the training is extended.

from keras.preprocessing.image import ImageDataGenerator
generated_data = ImageDataGenerator(featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, zca_whitening=False, rotation_range=0,  width_shift_range=0.1, height_shift_range=0.1, horizontal_flip = True, vertical_flip = False)
generated_data.fit(X_train)

#autoencoder.fit_generator(generated_data.flow(X_train, X_train, batch_size=batch_size), steps_per_epoch=X.shape[0], epochs=epochs, validation_data=(X_test, X_test), callbacks=checkpoints)

# Training Model:
epochs = 100 #@param {type:"number"}
batch_size = 16 #@param {type:"number"}
autoencoder.fit(X_train, X_train, batch_size=batch_size, epochs=epochs, validation_data=(X_test, X_test), shuffle=True, callbacks=checkpoints)

# + id="99JkbfQfJ8pH" cellView="form"
#@title plot
decoded_imgs = autoencoder.predict(X_test)
n = 10 #@param {type:"number"}
plt.figure(figsize=(20, 4))
for i in range(1, n):
    # display original
    ax = plt.subplot(2, n, i)
    plt.imshow(X_test[i])
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # display reconstruction
    ax = plt.subplot(2, n, i + n)
    plt.imshow(decoded_imgs[i])
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

# Split autoencoder:
encoder = Model(input_img, act_class)
encoder.summary()

# + id="0dUqyV2lJ8pI" cellView="form"
#@title show examples (edit cat_dog() if you have other classes)
encode = encoder.predict(X_train)

class_dict = np.zeros((num_class, num_class))
for i, sample in enumerate(Y_train):
    class_dict[np.argmax(encode[i], axis=0)][np.argmax(sample)] += 1
    
print(class_dict)
    
neuron_class = np.zeros((num_class))
for i in range(num_class):
    neuron_class[i] = np.argmax(class_dict[i], axis=0)

print(neuron_class)

# Getting class as string:
def cat_dog(model_output):
    if model_output == 0:
        return "Cat"
    else:
        return "Dog"

encode = encoder.predict(X_test)

predicted = np.argmax(encode, axis=1)
for i, sample in enumerate(predicted):
    predicted[i] = neuron_class[predicted[i]]

comparison = predicted == np.argmax(Y_test, axis=1)
loss = 1 - np.sum(comparison.astype(int))/Y_test.shape[0]

print('Loss:', loss)
print('Examples:')
for i in range(10):
    plt.imshow(X_test[i])
    plt.axis('off')
    plt.show()
    neuron = np.argmax(encode[i], axis=0)
    print('Class:',  cat_dog(np.argmax(Y_test[i], axis=0)), '- Model\'s Output Class:', cat_dog(neuron_class[neuron]),'\n'*2,'-'*40)

StarcoderdataJupyterScriptsDedupFiltered