Tensorflow Project

Let's wrap up this Deep Learning by taking a a quick look at the effectiveness of Neural Nets!

We'll use the Bank Authentication Data Set from the UCI repository.

The data consists of 5 columns:

  • variance of Wavelet Transformed image (continuous)
  • skewness of Wavelet Transformed image (continuous)
  • curtosis of Wavelet Transformed image (continuous)
  • entropy of image (continuous)
  • class (integer)

Where class indicates whether or not a Bank Note was authentic.

This sort of task is perfectly suited for Neural Networks and Deep Learning! Just follow the instructions below to get started!

Get the Data

Use pandas to read in the bank_note_data.csv file

In [1]:
import numpy as np
import pandas as pd
In [2]:
df = pd.read_csv('bank_note_data.csv')

Check the head of the Data

In [3]:
df.head()
Out[3]:
Image.Var Image.Skew Image.Curt Entropy Class
0 3.62160 8.6661 -2.8073 -0.44699 0
1 4.54590 8.1674 -2.4586 -1.46210 0
2 3.86600 -2.6383 1.9242 0.10645 0
3 3.45660 9.5228 -4.0112 -3.59440 0
4 0.32924 -4.4552 4.5718 -0.98880 0

EDA

We'll just do a few quick plots of the data.

Import seaborn and set matplolib inline for viewing

In [4]:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')
%matplotlib inline

Create a Countplot of the Classes (Authentic 1 vs Fake 0)

In [5]:
sns.countplot(x = 'Class', data = df, palette = 'viridis')
Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x111d70cf8>

Create a PairPlot of the Data with Seaborn, set Hue to Class

In [6]:
sns.pairplot(data = df, hue = 'Class', palette = 'viridis')
Out[6]:
<seaborn.axisgrid.PairGrid at 0x111d701d0>

Data Preparation

When using Neural Network and Deep Learning based systems, it is usually a good idea to Standardize your data, this step isn't actually necessary for our particular data set, but let's run through it for practice!

Standard Scaling

Import StandardScaler() from SciKit Learn

In [7]:
from sklearn.preprocessing import StandardScaler

Create a StandardScaler() object called scaler.

In [8]:
sc = StandardScaler()

Fit scaler to the features.

In [9]:
sc.fit(X = df.drop('Class', axis = 1))
Out[9]:
StandardScaler(copy=True, with_mean=True, with_std=True)

Use the .transform() method to transform the features to a scaled version.

In [10]:
scaled_data = sc.transform(X = df.drop('Class', axis = 1))

Convert the scaled features to a dataframe and check the head of this dataframe to make sure the scaling worked.

In [11]:
df_scaled = pd.DataFrame(data = scaled_data, columns = df.columns[:-1] ) 
In [12]:
df_scaled.head()
Out[12]:
Image.Var Image.Skew Image.Curt Entropy
0 1.121806 1.149455 -0.975970 0.354561
1 1.447066 1.064453 -0.895036 -0.128767
2 1.207810 -0.777352 0.122218 0.618073
3 1.063742 1.295478 -1.255397 -1.144029
4 -0.036772 -1.087038 0.736730 0.096587

Train Test Split

Create two objects X and y which are the scaled feature values and labels respectively.

In [13]:
X = df_scaled
y = df['Class']

Use the .as_matrix() method on X and Y and reset them equal to this result. We need to do this in order for TensorFlow to accept the data in Numpy array form instead of a pandas series.

Note from Serhan Mete 14/7/2018 : .as_martix() is now obselete and should be replaced w/ .values

In [14]:
X = X.values
y = y.values

Use SciKit Learn to create training and testing sets of the data as we've done in previous lectures:

In [15]:
from sklearn.model_selection import train_test_split
In [16]:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 101)
y_test  = (y_test==1).astype(np.int32)
y_train = (y_train==1).astype(np.int32)

Keras

Note from Serhan Mete 14/7/2018 : Contrib.learn is now ~depricated. Instead of directly interacting w/ Tensorflow, we'll use Keras instead which provides a high level API that makes life quite a bit easier.

We're going to build a sequential model w/ three hidden layers w/ [10,20,10] structure, binary output class, and train it with 30 epochs w/ a batch size of 20.

In [17]:
from keras.models import Sequential
from keras.layers import Dense
Using TensorFlow backend.
In [18]:
# A sequential model where we stack layers on top of each other
model = Sequential()
In [19]:
# Stack 3 hidden layers and 1 output layer
model.add(Dense(units = 10, activation='relu', input_dim=4))
model.add(Dense(units = 20, activation='relu'))
model.add(Dense(units = 10, activation='relu'))
model.add(Dense(units = 1, activation='sigmoid'))
In [20]:
# Now compile the method.
model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
In [21]:
# Now fit the model
model.fit(X_train, y_train, epochs = 30, batch_size = 20)
Epoch 1/30
960/960 [==============================] - 0s 512us/step - loss: 0.6659 - acc: 0.5219
Epoch 2/30
960/960 [==============================] - 0s 84us/step - loss: 0.5484 - acc: 0.8771
Epoch 3/30
960/960 [==============================] - 0s 80us/step - loss: 0.3716 - acc: 0.9406
Epoch 4/30
960/960 [==============================] - 0s 80us/step - loss: 0.2004 - acc: 0.9625
Epoch 5/30
960/960 [==============================] - 0s 81us/step - loss: 0.1127 - acc: 0.9698
Epoch 6/30
960/960 [==============================] - 0s 81us/step - loss: 0.0745 - acc: 0.9833
Epoch 7/30
960/960 [==============================] - 0s 82us/step - loss: 0.0555 - acc: 0.9802
Epoch 8/30
960/960 [==============================] - 0s 80us/step - loss: 0.0453 - acc: 0.9875
Epoch 9/30
960/960 [==============================] - 0s 80us/step - loss: 0.0369 - acc: 0.9896
Epoch 10/30
960/960 [==============================] - 0s 78us/step - loss: 0.0305 - acc: 0.9927
Epoch 11/30
960/960 [==============================] - 0s 76us/step - loss: 0.0259 - acc: 0.9948
Epoch 12/30
960/960 [==============================] - 0s 81us/step - loss: 0.0212 - acc: 0.9969
Epoch 13/30
960/960 [==============================] - 0s 93us/step - loss: 0.0176 - acc: 0.9979
Epoch 14/30
960/960 [==============================] - 0s 81us/step - loss: 0.0146 - acc: 1.0000
Epoch 15/30
960/960 [==============================] - 0s 81us/step - loss: 0.0122 - acc: 1.0000
Epoch 16/30
960/960 [==============================] - 0s 80us/step - loss: 0.0099 - acc: 1.0000
Epoch 17/30
960/960 [==============================] - 0s 97us/step - loss: 0.0083 - acc: 1.0000
Epoch 18/30
960/960 [==============================] - 0s 79us/step - loss: 0.0070 - acc: 1.0000
Epoch 19/30
960/960 [==============================] - 0s 78us/step - loss: 0.0058 - acc: 1.0000
Epoch 20/30
960/960 [==============================] - 0s 75us/step - loss: 0.0047 - acc: 1.0000
Epoch 21/30
960/960 [==============================] - 0s 77us/step - loss: 0.0039 - acc: 1.0000
Epoch 22/30
960/960 [==============================] - 0s 77us/step - loss: 0.0031 - acc: 1.0000
Epoch 23/30
960/960 [==============================] - 0s 84us/step - loss: 0.0026 - acc: 1.0000
Epoch 24/30
960/960 [==============================] - 0s 78us/step - loss: 0.0021 - acc: 1.0000
Epoch 25/30
960/960 [==============================] - 0s 78us/step - loss: 0.0018 - acc: 1.0000
Epoch 26/30
960/960 [==============================] - 0s 82us/step - loss: 0.0015 - acc: 1.0000
Epoch 27/30
960/960 [==============================] - 0s 89us/step - loss: 0.0012 - acc: 1.0000
Epoch 28/30
960/960 [==============================] - 0s 80us/step - loss: 0.0011 - acc: 1.0000
Epoch 29/30
960/960 [==============================] - 0s 82us/step - loss: 9.2280e-04 - acc: 1.0000
Epoch 30/30
960/960 [==============================] - 0s 82us/step - loss: 8.1070e-04 - acc: 1.0000
Out[21]:
<keras.callbacks.History at 0x120698048>

Model Evaluation

Use the predict method from the classifier model to create predictions from X_test

Now create a classification report and a Confusion Matrix. Does anything stand out to you?

In [22]:
y_predict = model.predict_classes(X_test)
In [23]:
from sklearn.metrics import confusion_matrix, classification_report
In [24]:
print(confusion_matrix(y_test,y_predict))
[[238   0]
 [  0 174]]
In [25]:
print(classification_report(y_test,y_predict))
             precision    recall  f1-score   support

          0       1.00      1.00      1.00       238
          1       1.00      1.00      1.00       174

avg / total       1.00      1.00      1.00       412

In [26]:
# Let's also look at the scores - obvious but still...
score = model.evaluate(X_test, y_test, verbose=0)
print('Test score: %.3f'%(score[0]))
print('Test accuracy: %.3f'%(score[1]))
Test score: 0.000
Test accuracy: 1.000

Optional Comparison

You should have noticed extremely accurate results from the DNN model. Let's compare this to a Random Forest Classifier for a reality check!

Use SciKit Learn to Create a Random Forest Classifier and compare the confusion matrix and classification report to the DNN model

In [27]:
from sklearn.ensemble import RandomForestClassifier
In [28]:
rc = RandomForestClassifier()
In [29]:
rc.fit(X_train, y_train)
Out[29]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=None, verbose=0,
            warm_start=False)
In [30]:
y_predict = rc.predict(X_test)
In [31]:
print(confusion_matrix(y_test,y_predict))
[[234   4]
 [  0 174]]
In [32]:
print(classification_report(y_test,y_predict))
             precision    recall  f1-score   support

          0       1.00      0.98      0.99       238
          1       0.98      1.00      0.99       174

avg / total       0.99      0.99      0.99       412

It should have also done very well, but not quite as good as the DNN model. Hopefully you have seen the power of DNN!

Great Job!