Human Activity Recognition(HAR)

Rubeen Mohammad
13 min readSep 18, 2019

--

HAR is a model that predicts human activities such as Walking, Walking_Upstairs, Walking_Downstairs, Sitting, Standing or Laying.

Introduction

Human activity recognition is the problem of classifying sequences of accelerometer data recorded by specialized harnesses or smartphones into known well-defined movements. Classical approaches involve hand crafting features from the observations and applying Machine Learning Models which is quite different because we need to be deeply expertise to acquire features from Data. Rather than this, we can go for Deep Learning Algorithms which can automatically engineer features from Raw Time Series data.

About Data

This dataset is collected from 30 persons(referred to subjects in this dataset), performing different activities with a smartphone to their waists. The data is recorded with the help of sensors (accelerometer and Gyroscope) in that smartphone. This experiment was video recorded to label the data manually. Using Accerlerometer we can measure Accerelation, using Gyroscope we can measure Angular Velocity.

By using sensors they have captured ‘3-axial linear acceleration’(tAcc-XYZ) from the accelerometer and ‘3-axial angular velocity’ (tGyro-XYZ) from Gyroscope with several variations. Our input is 6-Time Series data and output is predicted activity from the 6Classes. This can be considered as a Multi-class Classification problem.

  1. These sensor signals are preprocessed by applying noise filters and then sampled in fixed-width windows(sliding windows) of 2.56 seconds each with a 50% overlap. ie., each window has 128 readings.
  2. From each window, a feature vector was obtained by calculating variables from the time and frequency domain.

For every signal, now we have 128 dim vectors. In addition to the 6 time-series data, Domain experts have added some other Engineered Features.

  1. The acceleration signal was separated into Body and Gravity acceleration signals(tBodyAcc-XYZ and tGravityAcc-XYZ) using some low pass filter with a corner frequency of 0.3Hz.
  2. After that, the body linear acceleration and angular velocity were derived in time to obtain jerk signals (tBodyAccJerk-XYZ and tBodyGyroJerk-XYZ).
  3. The magnitude of these 3-dimensional signals was calculated using the Euclidian norm. These magnitudes are represented as features with names like tBodyAccMag, tGravityAccMag, tBodyAccJerkMag, tBodyGyroMag and tBodyGyroJerkMag.
  4. Finally, We’ve got frequency domain signals from some of the available signals by applying an FFT (Fast Fourier Transform). These signals obtained were labeled with prefix ‘f’ just like original signals with prefix ‘t’. These signals are labeled as fBodyAcc-XYZ, fBodyGyroMag etc.
  • tBodyAcc-XYZ
  • tGravityAcc-XYZ
  • tBodyAccJerk-XYZ
  • tBodyGyro-XYZ
  • tBodyGyroJerk-XYZ
  • tBodyAccMag
  • tGravityAccMag
  • tBodyAccJerkMag
  • tBodyGyroMag
  • tBodyGyroJerkMag
  • fBodyAcc-XYZ
  • fBodyAccJerk-XYZ
  • fBodyGyro-XYZ
  • fBodyAccMag
  • fBodyAccJerkMag
  • fBodyGyroMag
  • fBodyGyroJerkMag

We can estimate some set of variables from the above signals. ie., We will estimate the following properties on each and every signal that we recorded so far: mean(), std(), mad(),max(), min(),energy(), entropy(), iqr(), correlation(), angle() etc

jerk= rate of change of acceleration

acc=rate of change of velocity

mag=magnitude

Y_Labels(Encoded)

  • In the dataset, Y_labels are represented as numbers from 1 to 6 as their identifiers.
  • WALKING as 1
  • WALKING_UPSTAIRS as 2
  • WALKING_DOWNSTAIRS as 3
  • SITTING as 4
  • STANDING as 5
  • LAYING as 6

Train-Test Split

Totally we have 30persons and using 70–30 split, we did split 21persons data into train data and 9persons data into test data.

X_train=Expert Engineered Features for each window

y_train= class labels{1,2,3,4,5,6}

Interial_signals= Actual time series data(raw data)-> 128 dim vectors for each window

A quick overview of the dataset :

  • Accelerometer and Gyroscope readings are taken from 30 volunteers(referred to subjects) while performing the following 6 Activities.
  • Walking
  • WalkingUpstairs
  • WalkingDownstairs
  • Standing
  • Sitting
  • Lying.
  1. Readings are divided into a window of 2.56 seconds with 50% overlapping.
  2. Accelerometer readings are divided into gravity acceleration and body acceleration readings, which has x,y and z components each.
  3. Gyroscope readings are the measure of angular velocities which has x,y and z components.
  4. Jerk signals are calculated for BodyAcceleration readings.
  5. Fourier Transforms are made on the above time readings to obtain frequency readings.
  6. Now, on all the base signal readings., mean, max, mad, sma, arcoefficient, engerybands, entropy etc., are calculated for each window.
  7. We get a feature vector of 561 features and these features are given in the dataset.
  8. Each window of readings is a datapoint of 561 features.
import numpy as np
import pandas as pd
# get the features from the file features.txt
features = list()
with open(‘UCI_HAR_Dataset/features.txt’) as f:
features = [line.split()[1] for line in f.readlines()]
print(‘No of Features: {}’.format(len(features)))

Obtain the train data

# get the data from txt files to pandas dataffame
X_train = pd.read_csv('UCI_HAR_dataset/train/X_train.txt', delim_whitespace=True, header=None, names=features)
# add subject column to the dataframe
X_train['subject'] = pd.read_csv('UCI_HAR_dataset/train/subject_train.txt', header=None, squeeze=True)
y_train = pd.read_csv('UCI_HAR_dataset/train/y_train.txt', names=['Activity'], squeeze=True)
y_train_labels = y_train.map({1: 'WALKING', 2:'WALKING_UPSTAIRS',3:'WALKING_DOWNSTAIRS',\
4:'SITTING', 5:'STANDING',6:'LAYING'})
# put all columns in a single dataframe
train = X_train
train['Activity'] = y_train
train['ActivityName'] = y_train_labels
train.sample()

Obtain the test data

# get the data from txt files to pandas dataffame
X_test = pd.read_csv('UCI_HAR_dataset/test/X_test.txt', delim_whitespace=True, header=None, names=features)
# add subject column to the dataframe
X_test['subject'] = pd.read_csv('UCI_HAR_dataset/test/subject_test.txt', header=None, squeeze=True)
# get y labels from the txt file
y_test = pd.read_csv('UCI_HAR_dataset/test/y_test.txt', names=['Activity'], squeeze=True)
y_test_labels = y_test.map({1: 'WALKING', 2:'WALKING_UPSTAIRS',3:'WALKING_DOWNSTAIRS',\
4:'SITTING', 5:'STANDING',6:'LAYING'})
# put all columns in a single dataframe
test = X_test
test['Activity'] = y_test
test['ActivityName'] = y_test_labels
test.sample()

Data Cleaning

1. Check for Duplicates

print(‘No of duplicates in train: {}’.format(sum(train.duplicated())))
print(‘No of duplicates in test : {}’.format(sum(test.duplicated())))

2. Checking for NaN/null values

print(‘We have {} NaN/Null values in train’.format(train.isnull().values.sum()))
print(‘We have {} NaN/Null values in test’.format(test.isnull().values.sum()))

3. Check for data imbalance

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style(‘whitegrid’)
plt.rcParams[‘font.family’] = ‘Dejavu Sans’
plt.figure(figsize=(16,8))
plt.title(‘Data provided by each user’, fontsize=20)
sns.countplot(x=’subject’,hue=’ActivityName’, data = train)
plt.show()

We have got the almost same number of reading from all the subjects

plt.title(‘No of Datapoints per Activity’, fontsize=15)
sns.countplot(train.ActivityName)
plt.xticks(rotation=90)
plt.show()

4. Changing feature names

columns = train.columns# Removing ‘()’ from column names
columns = columns.str.replace(‘[()]’,’’)
columns = columns.str.replace(‘[-]’, ‘’)
columns = columns.str.replace(‘[,]’,’’)
train.columns = columns
test.columns = columns
test.columns

5. Save this data frame in a csv files

train.to_csv(‘UCI_HAR_Dataset/csv_files/train.csv’, index=False)
test.to_csv(‘UCI_HAR_Dataset/csv_files/test.csv’, index=False)

Exploratory Data Analysis

EDA is the most important part before training any kind of model, using EDA we can understand a lot about our data and it tells how to train a model. “Without domain knowledge, EDA has no meaning, without EDA a problem has no soul.

1. Featuring Engineering from Domain Knowledge

  • Static and Dynamic Activities
  • In static activities (sit, stand, lie down) motion information will not be very useful.
  • In the dynamic activities (Walking, WalkingUpstairs, WalkingDownstairs) motion info will be significant.

2. Stationary and Moving activities are completely different

sns.set_palette(“Set1”, desat=0.80)
facetgrid = sns.FacetGrid(train, hue=’ActivityName’, size=6,aspect=2)
facetgrid.map(sns.distplot,’tBodyAccMagmean’, hist=False)\
.add_legend()
plt.annotate(“Stationary Activities”, xy=(-0.956,17), xytext=(-0.9, 23), size=20,\
va=’center’, ha=’left’,\
arrowprops=dict(arrowstyle=”simple”,connectionstyle=”arc3,rad=0.1"))
plt.annotate(“Moving Activities”, xy=(0,3), xytext=(0.2, 9), size=20,\
va=’center’, ha=’left’,\
arrowprops=dict(arrowstyle=”simple”,connectionstyle=”arc3,rad=0.1"))
plt.show()
# for plotting purposes taking datapoints of each activity to a different dataframe
df1 = train[train[‘Activity’]==1]
df2 = train[train[‘Activity’]==2]
df3 = train[train[‘Activity’]==3]
df4 = train[train[‘Activity’]==4]
df5 = train[train[‘Activity’]==5]
df6 = train[train[‘Activity’]==6]
plt.figure(figsize=(14,7))
plt.subplot(2,2,1)
plt.title(‘Stationary Activities(Zoomed in)’)
sns.distplot(df4[‘tBodyAccMagmean’],color = ‘r’,hist = False, label = ‘Sitting’)
sns.distplot(df5[‘tBodyAccMagmean’],color = ‘m’,hist = False,label = ‘Standing’)
sns.distplot(df6[‘tBodyAccMagmean’],color = ‘c’,hist = False, label = ‘Laying’)
plt.axis([-1.01, -0.5, 0, 35])
plt.legend(loc=’center’)
plt.subplot(2,2,2)
plt.title(‘Moving Activities’)
sns.distplot(df1[‘tBodyAccMagmean’],color = ‘red’,hist = False, label = ‘Walking’)
sns.distplot(df2[‘tBodyAccMagmean’],color = ‘blue’,hist = False,label = ‘Walking Up’)
sns.distplot(df3[‘tBodyAccMagmean’],color = ‘green’,hist = False, label = ‘Walking down’)
plt.legend(loc=’center right’)
plt.tight_layout()
plt.show()

3. The magnitude of acceleration can separate it well

plt.figure(figsize=(7,7))
sns.boxplot(x=’ActivityName’, y=’tBodyAccMagmean’,data=train, showfliers=False, saturation=1)
plt.ylabel(‘Acceleration Magnitude mean’)
plt.axhline(y=-0.7, xmin=0.1, xmax=0.9,dashes=(5,5), c=’g’)
plt.axhline(y=-0.05, xmin=0.4, dashes=(5,5), c=’m’)
plt.xticks(rotation=90)
plt.show()

Observations:

  • If tAccMean is < -0.8 then the Activities are either Standing or Sitting or Laying.
  • If tAccMean is > -0.6 then the Activities are either Walking or WalkingDownstairs or WalkingUpstairs.
  • If tAccMean > 0.0 then the Activity is WalkingDownstairs.
  • We can classify 75% the Activity labels with some errors.

4. Position of GravityAccelerationComponants also matters

sns.boxplot(x=’ActivityName’, y=’angleXgravityMean’, data=train)
plt.axhline(y=0.08, xmin=0.1, xmax=0.9,c=’m’,dashes=(5,3))
plt.title(‘Angle between X-axis and Gravity_mean’, fontsize=15)
plt.xticks(rotation = 40)
plt.show()

Observations:

  • If angleX,gravityMean > 0 then Activity is Laying.
  • We can classify all data points belonging to Laying activity with just a single if else statement.
sns.boxplot(x=’ActivityName’, y=’angleYgravityMean’, data = train, showfliers=False)
plt.title(‘Angle between Y-axis and Gravity_mean’, fontsize=15)
plt.xticks(rotation = 40)
plt.axhline(y=-0.22, xmin=0.1, xmax=0.8, dashes=(5,3), c=’m’)
plt.show()

Apply t-sne on the data

import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import seaborn as sns
# performs t-sne with different perplexity values and their repective plots..def perform_tsne(X_data, y_data, perplexities, n_iter=1000, img_name_prefix='t-sne'):

for index,perplexity in enumerate(perplexities):
# perform t-sne
print('\nperforming tsne with perplexity {} and with {} iterations at max'.format(perplexity, n_iter))
X_reduced = TSNE(verbose=2, perplexity=perplexity).fit_transform(X_data)
print('Done..')

# prepare the data for seaborn
print('Creating plot for this t-sne visualization..')
df = pd.DataFrame({'x':X_reduced[:,0], 'y':X_reduced[:,1] ,'label':y_data})

# draw the plot in appropriate place in the grid
sns.lmplot(data=df, x='x', y='y', hue='label', fit_reg=False, size=8,\
palette="Set1",markers=['^','v','s','o', '1','2'])
plt.title("perplexity : {} and max_iter : {}".format(perplexity, n_iter))
img_name = img_name_prefix + '_perp_{}_iter_{}.png'.format(perplexity, n_iter)
print('saving this plot as image in present working directory...')
plt.savefig(img_name)
plt.show()
print('Done')
X_pre_tsne = train.drop(['subject', 'Activity','ActivityName'], axis=1)
y_pre_tsne = train['ActivityName']
perform_tsne(X_data = X_pre_tsne,y_data=y_pre_tsne, perplexities =[2,5,10,20,50])

Like this t-sne will be applied with perplexity=5,10,20,50 with 1000 iterations.

Here we are mapping 561 dim to 2dim, from t-sne plot we can observe that most of the activities are well separated except the blue and red points are overlapping, which means standing and sitting features are overlapping. Here our big challenge is to separate Standing and sitting points. By changing the perplexity all of our points are well clustered expect standing and sitting, the summary remained the same. This tells us that Even linear models will work fairly well. Let’s apply some models on this data.

Applying Machine Learning Models

# get X_train and y_train from csv filesX_train = train.drop(['subject', 'Activity', 'ActivityName'], axis=1)y_train = train.ActivityName# get X_test and y_test from test csv file
X_test = test.drop(['subject', 'Activity', 'ActivityName'], axis=1)
y_test = test.ActivityName
print('X_train and y_train : ({},{})'.format(X_train.shape, y_train.shape))
print('X_test and y_test : ({},{})'.format(X_test.shape, y_test.shape))

Let’s train models with our data

labels=['LAYING', 'SITTING','STANDING','WALKING','WALKING_DOWNSTAIRS','WALKING_UPSTAIRS']

Function to plot the confusion matrix

import itertools
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
plt.rcParams["font.family"] = 'DejaVu Sans'
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=90)
plt.yticks(tick_marks, classes)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')

Generic function to run any model specified

from datetime import datetime
def perform_model(model, X_train, y_train, X_test, y_test, class_labels, cm_normalize=True, \
print_cm=True, cm_cmap=plt.cm.Greens):


# to store results at various phases
results = dict()

# time at which model starts training
train_start_time = datetime.now()
print('training the model..')
model.fit(X_train, y_train)
print('Done \n \n')
train_end_time = datetime.now()
results['training_time'] = train_end_time - train_start_time
print('training_time(HH:MM:SS.ms) - {}\n\n'.format(results['training_time']))


# predict test data
print('Predicting test data')
test_start_time = datetime.now()
y_pred = model.predict(X_test)
test_end_time = datetime.now()
print('Done \n \n')
results['testing_time'] = test_end_time - test_start_time
print('testing time(HH:MM:SS:ms) - {}\n\n'.format(results['testing_time']))
results['predicted'] = y_pred
# calculate overall accuracty of the model
accuracy = metrics.accuracy_score(y_true=y_test, y_pred=y_pred)
# store accuracy in results
results['accuracy'] = accuracy
print('---------------------')
print('| Accuracy |')
print('---------------------')
print('\n {}\n\n'.format(accuracy))


# confusion matrix
cm = metrics.confusion_matrix(y_test, y_pred)
results['confusion_matrix'] = cm
if print_cm:
print('--------------------')
print('| Confusion Matrix |')
print('--------------------')
print('\n {}'.format(cm))

# plot confusin matrix
plt.figure(figsize=(8,8))
plt.grid(b=False)
plot_confusion_matrix(cm, classes=class_labels, normalize=True, title='Normalized confusion matrix', cmap = cm_cmap)
plt.show()

# get classification report
print('-------------------------')
print('| Classifiction Report |')
print('-------------------------')
classification_report = metrics.classification_report(y_test, y_pred)
# store report in results
results['classification_report'] = classification_report
print(classification_report)

# add the trained model to the results
results['model'] = model

return results

Method to print the Grid Search Attributes

def print_grid_search_attributes(model):
# Estimator that gave highest score among all the estimators formed in GridSearch
print('--------------------------')
print('| Best Estimator |')
print('--------------------------')
print('\n\t{}\n'.format(model.best_estimator_))
# parameters that gave best results while performing grid search
print('--------------------------')
print('| Best parameters |')
print('--------------------------')
print('\tParameters of best estimator : \n\n\t{}\n'.format(model.best_params_))
# number of cross validation splits
print('---------------------------------')
print('| No of CrossValidation sets |')
print('--------------------------------')
print('\n\tTotal numbre of cross validation sets: {}\n'.format(model.n_splits_))
# Average cross validated score of the best estimator, from the Grid Search
print('--------------------------')
print('| Best Score |')
print('--------------------------')
print('\n\tAverage Cross Validate scores of best estimator : \n\n\t{}\n'.format(model.best_score_))

1. Logistic Regression with Grid Search

from sklearn import linear_model
from sklearn import metrics
from sklearn.model_selection import GridSearchCV
# start Grid search
parameters = {'C':[0.01, 0.1, 1, 10, 20, 30], 'penalty':['l2','l1']}
log_reg = linear_model.LogisticRegression()
log_reg_grid = GridSearchCV(log_reg, param_grid=parameters, cv=3, verbose=1, n_jobs=-1)
log_reg_grid_results = perform_model(log_reg_grid, X_train, y_train, X_test, y_test, class_labels=labels)
plt.figure(figsize=(8,8))
plt.grid(b=False)
plot_confusion_matrix(log_reg_grid_results['confusion_matrix'], classes=labels, cmap=plt.cm.Greens, )
plt.show()
# observe the attributes of the model
print_grid_search_attributes(log_reg_grid_results['model'])

Like-wise we applied many Machine Learning Algorithms and comparison among all those algorithms is as follows:

print('\n                     Accuracy     Error')
print(' ---------- --------')
print('Logistic Regression : {:.04}% {:.04}%'.format(log_reg_grid_results['accuracy'] * 100,\100-(log_reg_grid_results['accuracy'] * 100)))
print('Linear SVC : {:.04}% {:.04}% '.format(lr_svc_grid_results['accuracy'] * 100,\100-(lr_svc_grid_results['accuracy'] * 100)))
print('rbf SVM classifier : {:.04}% {:.04}% '.format(rbf_svm_grid_results['accuracy'] * 100,\100-(rbf_svm_grid_results['accuracy'] * 100)))
print('DecisionTree : {:.04}% {:.04}% '.format(dt_grid_results['accuracy'] * 100,\100-(dt_grid_results['accuracy'] * 100)))
print('Random Forest : {:.04}% {:.04}% '.format(rfc_grid_results['accuracy'] * 100,\100-(rfc_grid_results['accuracy'] * 100)))
print('GradientBoosting DT : {:.04}% {:.04}% '.format(rfc_grid_results['accuracy'] * 100,\100-(rfc_grid_results['accuracy'] * 100)))

We can choose Logistic regression or Linear SVC or rbf SVM, since these 3 models can generate better results with high Accuracy and low Errors.

Modeling HAR using Deep Learning (RNN):

# importing librariesimport pandas as pd
import numpy as np
# Activities are the class labels
# It is a 6 class classification
ACTIVITIES = {
0: ‘WALKING’,
1: ‘WALKING_UPSTAIRS’,
2: ‘WALKING_DOWNSTAIRS’,
3: ‘SITTING’,
4: ‘STANDING’,
5: ‘LAYING’,
}
# Utility function to print the confusion matrix
def confusion_matrix(Y_true, Y_pred):
Y_true = pd.Series([ACTIVITIES[y] for y in np.argmax(Y_true, axis=1)])
Y_pred = pd.Series([ACTIVITIES[y] for y in np.argmax(Y_pred, axis=1)])
return pd.crosstab(Y_true, Y_pred, rownames=[‘True’], colnames=[‘Pred’])

Data

# Data directory DATADIR = ‘UCI_HAR_Dataset’

# Data directoryDATADIR = 'UCI_HAR_Dataset'# Raw data signals->Signals are from Accelerometer and Gyroscope
# The signals are in x,y,z directions
SIGNALS = [
“body_acc_x”,
“body_acc_y”,
“body_acc_z”,
“body_gyro_x”,
“body_gyro_y”,
“body_gyro_z”,
“total_acc_x”,
“total_acc_y”,
“total_acc_z”
]

Instead of 6 time-series data we have total of 9 time-series data:

3 from the Gyroscope

3 from the Accelerometer, corresponding to body and

3 from the Accelerometer, corresponding to total acceleration

# Utility function to read the data from csv file
def _read_csv(filename):
return pd.read_csv(filename, delim_whitespace=True, header=None)
# Utility function to load the load
def load_signals(subset):
signals_data = []
for signal in SIGNALS:
filename = f'UCI_HAR_Dataset/{subset}/Inertial Signals/{signal}_{subset}.txt'
signals_data.append(
_read_csv(filename).as_matrix()
)
# Transpose is used to change the dimensionality of the output,
# aggregating the signals by combination of sample/timestep.
# Resultant shape is (7352 train/2947 test samples, 128 timesteps, 9 signals)
return np.transpose(signals_data, (1, 2, 0))
def load_y(subset):
"""
The objective that we are trying to predict is a integer, from 1 to 6,that represents a human activity. We return a binary representation of every sample objective as a 6 bits vector using One Hot Encoding

"""
filename = f'UCI_HAR_Dataset/{subset}/y_{subset}.txt'
y = _read_csv(filename)[0]
return pd.get_dummies(y).as_matrix()def load_data():
"""
Obtain the dataset from multiple files.
Returns: X_train, X_test, y_train, y_test
"""
X_train, X_test = load_signals('train'), load_signals('test')
y_train, y_test = load_y('train'), load_y('test')
return X_train, X_test, y_train, y_test# Importing tensorflow
np.random.seed(42)
import tensorflow as tf
tf.set_random_seed(42)
# Configuring a session
session_conf = tf.ConfigProto(
intra_op_parallelism_threads=1,
inter_op_parallelism_threads=1
)
# Import Keras
from keras import backend as K
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
# Importing libraries
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers.core import Dense, Dropout
# Initializing parameters
epochs = 30
batch_size = 16
n_hidden = 32
# Utility function to count the number of classes
def _count_classes(y):
return len(set([tuple(category) for category in y]))
# Loading the train and test data
X_train, X_test, Y_train, Y_test = load_data()
timesteps = len(X_train[0])
input_dim = len(X_train[0][0])
n_classes = _count_classes(Y_train)
print(timesteps)
print(input_dim)
print(len(X_train))

Defining the Architecture of LSTM

# Initiliazing the sequential model
model = Sequential()
# Configuring the parameters
model.add(LSTM(n_hidden, input_shape=(timesteps, input_dim)))
# Adding a dropout layer
model.add(Dropout(0.5))
# Adding a dense output layer with sigmoid activation
model.add(Dense(n_classes, activation='sigmoid'))
model.summary()
# Compiling the model
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# Training the model
model.fit(X_train,
Y_train,
batch_size=batch_size,
validation_data=(X_test, Y_test),
epochs=epochs)
# Confusion Matrix
print(confusion_matrix(Y_test, model.predict(X_test)))

Observations:

  • Among all the points that actually belongs to laying class, 512 points are classified correctly as laying and only 3 datapoints got misclassified as sitting class
  • 87datapoints of sitting class are misclassified as standing and 75 datapoints of the standing class are misclassified as sitting class
  • We can observe more misclassification between sitting and standing classes only, all other classes datapoints got classified pretty well.
  • With a simple 2 layer architecture, we got 90.09% accuracy and a loss of 0.30
  • The major advantage of using Deep Learning models is we don’t to explicitly do the feature engineering. We can further improve the performance with Hyperparameter tuning

--

--