"""
    File name:      classification_act.py
    Author:         Tetsuro Tatsuoka
    Date created:   04/12/2018
    Last modified:  04/12/2018
    Version:        1.0.0
    Python version: 3.6.3
    Description:    Classification of activity of daily living by LSTM
    Reference:
        Human-Activity-Recognition
        https://github.com/servomac/Human-Activity-Recognition

    Revision history:
        1.0.0   04/12/2018  - Initial coding.
"""
import os
import numpy as np
import pandas as pd
import tensorflow as tf
import random as rn
import matplotlib.pyplot as plt
import seaborn as sns

# Fix random seed
os.environ['PYTHONHASHSEED'] = '0'
np.random.seed(15)
rn.seed(15)
tf.set_random_seed(15)

session_conf = tf.ConfigProto(
    intra_op_parallelism_threads=1,
    inter_op_parallelism_threads=1
)

from keras import backend as K
from keras.callbacks import ModelCheckpoint

from keras.models import Sequential
from keras.layers import LSTM
from keras.layers.core import Dense, Dropout

from keras.utils.vis_utils import plot_model

from load_data_act import load_data

sns.reset_orig()

epochs = 40
batch_size = 16
n_hidden = 32

X_train, X_test, Y_train, Y_test = load_data()

timesteps = len(X_train[0])
input_dim = len(X_train[0][0])
n_classes = len(set([tuple(category) for category in Y_train]))

sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
K.set_learning_phase(1)

""" Classification of activity """

# Define model
model = Sequential()
model.add(LSTM(n_hidden, input_shape=(timesteps, input_dim)))
model.add(Dropout(0.5))
model.add(Dense(n_classes, activation='sigmoid'))

# Generate model
model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

# Plot model structure    
plot_model(model,to_file='model_lstm.png', show_shapes=True)

# Define callback function
is_save_all_weights = False
if(is_save_all_weights):
    weights_path = 'model_lstm_{epoch:04d}.h5'
    model_cp = ModelCheckpoint(weights_path, monitor='val_acc', verbose=1, save_best_only=False)
else:
    weights_path = 'model_lstm_best.h5'
    model_cp = ModelCheckpoint(weights_path, monitor='val_acc', verbose=1, save_best_only=True)

# Train model
history = model.fit(X_train,
                    Y_train,
                    batch_size=batch_size,
                    validation_data=(X_test, Y_test),
                    callbacks=[model_cp],
                    verbose=1,
                    epochs=epochs)

model.save_weights('model_lstm.h5')

# Evaluate
ACTIVITIES = {
    0: 'WALKING',
    1: 'WALKING_UP',    # 1: 'WALKING_UPSTAIRS',
    2: 'WALKING_DOWN',  # 2: 'WALKING_DOWNSTAIRS',
    3: 'SITTING',
    4: 'STANDING',
    5: 'LAYING',
}
Y_pred = model.predict(X_test)
y_true = pd.Series([ACTIVITIES[y] for y in np.argmax(Y_test, axis=1)])
y_pred = pd.Series([ACTIVITIES[y] for y in np.argmax(Y_pred, axis=1)])
print(pd.crosstab(y_true, y_pred, rownames=['True'], colnames=['Pred']))

# Close session
sess.close()

# Plot train curve
# Accuracy
plt.figure()
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# Loss
plt.figure()
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
