from __future__ import print_function
import keras
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import advanced_activations as aact
import numpy as np

batch_size = 128
num_classes = 10
epochs = 0
data_augmentation = True

# input image dimensions
img_rows, img_cols = 32, 32
# The CIFAR10 images are RGB.
img_channels = 3

# The data, shuffled and split between train and test sets:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
y_test_np = np.array(y_test)
y_test_np = y_test_np.flatten()

# Convert class vectors to binary class matrices.
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

adam = keras.optimizers.Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.00001)
ELU_advanced = aact.ELU(alpha=1.1)
regularizer = keras.regularizers.l1(0.001)

tensorboard_caller = keras.callbacks.TensorBoard(log_dir='./logs/Result', histogram_freq=0, write_graph=True, write_images=False)

check_point = keras.callbacks.ModelCheckpoint(filepath='./weights_Result.hdf5', monitor='val_loss', verbose=1, save_best_only=True, save_weights_only=False, mode='auto', period=1)

model = Sequential()
model.add(Flatten(input_shape=x_train.shape[1:]))
model.add(Dense(1555, activation='elu', use_bias=True))
model.add(Dropout(0.5))
model.add(Dense(999, activation='elu', use_bias=True))
model.add(Dropout(0.2))

model.add(Dense(num_classes, use_bias=True, kernel_regularizer=regularizer))
model.add(Activation('softmax'))

# Let's train the model using RMSprop
model.compile(loss='categorical_crossentropy',
              optimizer=adam,
              metrics=['accuracy'])

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')

# x_train /= 255
# x_test /= 255

x_train = x_train / np.std(x_train)
x_train = x_train - np.mean(x_train)
x_test = x_test / np.std(x_test)
x_test = x_test - np.mean(x_test)

model.load_weights('./weights_7062.hdf5')

if not data_augmentation:
    print('Not using data augmentation.')
    model.fit(x_train, y_train,
              batch_size=batch_size,
              epochs=epochs,
              validation_data=(x_test, y_test),
              shuffle=True)
else:
    print('Using real-time data augmentation.')
    # This will do preprocessing and realtime data augmentation:
    datagen = ImageDataGenerator(
        featurewise_center=False,  # set input mean to 0 over the dataset
        samplewise_center=False,  # set each sample mean to 0
        featurewise_std_normalization=False,  # divide inputs by std of the dataset
        samplewise_std_normalization=False,  # divide each input by its std
        zca_whitening=False,  # apply ZCA whitening
        rotation_range=0,  # randomly rotate images in the range (degrees, 0 to 180)
        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)
        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)
        horizontal_flip=True,  # randomly flip images
        vertical_flip=False)  # randomly flip images

    # Compute quantities required for featurewise normalization
    # (std, mean, and principal components if ZCA whitening is applied).
    datagen.fit(x_train)

    # Fit the model on the batches generated by datagen.flow().
    model.fit_generator(datagen.flow(x_train, y_train,
                                     batch_size=batch_size),
                        steps_per_epoch=x_train.shape[0] // batch_size,
                        epochs=epochs,
                        validation_data=(x_test, y_test), callbacks=[tensorboard_caller, check_point], verbose=2)

# model.save('./model4.h5')
# scores = model.evaluate(x_test, y_test, verbose=1)
# print('Testing score is ', scores[0])
# print('Testing accuracy is ', scores[1])

scores = model.predict(x_test, 128, verbose=1)

y_test_pred = np.zeros(scores.shape[0])
for i in range(scores.shape[0]):
    y_test_pred[i] = np.argmax(scores[i])


num_correct = np.sum(y_test_pred == y_test_np)
accuracy = float(num_correct) / x_test.shape[0]

ccrn = np.zeros(10)

for i in range(x_test.shape[0]):
    if y_test_pred[i] == y_test_np[i]:
        ccrn[y_test_np[i]] += 1


print('\nGot ', num_correct, ' / ', x_test.shape[0], 'correct => accuracy:', accuracy)
print('CCRN of 10 Classes = ', ccrn/(y_test.shape[0]/ num_classes))
