STEP 1: Import ALL the things!

The packages

In [35]:
DATASET = 'animals'
TEST_IMAGE = 'images/panda.jpg'

# DATASET = 'jcrew'
# TEST_IMAGE = 'images/jc_test.jpeg'
time: 1.18 ms
In [37]:
# !pip install ipython-autotime
%load_ext autotime
The autotime extension is already loaded. To reload it, use:
  %reload_ext autotime
time: 3.45 ms
In [38]:
import matplotlib
matplotlib.use("Agg")
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from keras.models import Sequential
from keras.layers.core import Dense
from keras.optimizers import SGD
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os
time: 9.22 ms

The data

In [39]:
## mount your Google Drive folder
from google.colab import drive
drive.mount('/content/drive')
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
time: 2.7 ms
In [41]:
## change into the directory where your data is 
## **** ONLY NEED TO DO THIS ONCE PER RUNTIME ****

# os.chdir("drive/My Drive/data")
time: 851 µs

STEP 2: Process the data

  1. Get image paths. Shuffle them.
  2. Loop over the paths and and load the images

Inside the loop (for each image)

  • resize the image
  • flatten the image
  • store the (newly flattened & resized) image in 'data' array
  • store the label in 'labels' array
In [42]:
print("[INFO] loading images...")
data = []
labels = []

# imagePaths = sorted(list(paths.list_images('animals')))
imagePaths = sorted(list(paths.list_images(DATASET)))
random.seed(42)
random.shuffle(imagePaths)

for imagePath in imagePaths:
	image = cv2.imread(imagePath)
	image = cv2.resize(image, (32, 32)).flatten()
	data.append(image)
	label = imagePath.split(os.path.sep)[-2]
	labels.append(label)
[INFO] loading images...
time: 18.6 s
In [43]:
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
time: 55.2 ms
In [44]:
(trainX, testX, trainY, testY) = train_test_split(data,
	labels, test_size=0.25, random_state=42)
time: 32.8 ms

Convert the labels from integers to vectors

NOTE: for 2-class, binary classification you should use Keras' to_categorical function instead as the scikit-learn's LabelBinarizer will not return a vector

In [45]:
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
time: 7.36 ms

STEP 3: MODEL

In [46]:
model = Sequential()
model.add(Dense(1024, input_shape=(3072,), activation="sigmoid"))
model.add(Dense(512, activation="sigmoid"))
model.add(Dense(len(lb.classes_), activation="softmax"))
time: 45.9 ms
  1. Initialize learning rate and # of epochs
  2. Compile the model using:
  • OPTIMIZER: SGD
  • LOSS: categorical cross-entropy loss

NOTE: use binary_crossentropy for 2-class classification

In [47]:
INIT_LR = 0.01
EPOCHS = 75

print("[INFO] training network...")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
	metrics=["accuracy"])
[INFO] training network...
time: 45.8 ms

STEP 4: Train the neural network

In [48]:
H = model.fit(trainX, trainY, validation_data=(testX, testY),
	epochs=EPOCHS, batch_size=32)
Train on 2263 samples, validate on 755 samples
Epoch 1/75
2263/2263 [==============================] - 3s 1ms/step - loss: 1.0965 - acc: 0.3880 - val_loss: 1.0748 - val_acc: 0.4768
Epoch 2/75
2263/2263 [==============================] - 3s 1ms/step - loss: 1.0789 - acc: 0.4034 - val_loss: 1.0870 - val_acc: 0.3298
Epoch 3/75
2263/2263 [==============================] - 3s 1ms/step - loss: 1.0552 - acc: 0.4547 - val_loss: 1.0589 - val_acc: 0.4013
Epoch 4/75
2263/2263 [==============================] - 3s 1ms/step - loss: 1.0383 - acc: 0.4560 - val_loss: 1.0419 - val_acc: 0.4808
Epoch 5/75
2263/2263 [==============================] - 3s 1ms/step - loss: 1.0173 - acc: 0.4954 - val_loss: 1.0222 - val_acc: 0.4927
Epoch 6/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9992 - acc: 0.5179 - val_loss: 1.0165 - val_acc: 0.4530
Epoch 7/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9865 - acc: 0.5055 - val_loss: 0.9918 - val_acc: 0.5258
Epoch 8/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9674 - acc: 0.5263 - val_loss: 1.0201 - val_acc: 0.4848
Epoch 9/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9568 - acc: 0.5157 - val_loss: 0.9978 - val_acc: 0.4980
Epoch 10/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9436 - acc: 0.5219 - val_loss: 0.9683 - val_acc: 0.4980
Epoch 11/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9302 - acc: 0.5356 - val_loss: 0.9511 - val_acc: 0.5285
Epoch 12/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9187 - acc: 0.5422 - val_loss: 0.9657 - val_acc: 0.4861
Epoch 13/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.9054 - acc: 0.5493 - val_loss: 0.9547 - val_acc: 0.4940
Epoch 14/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8979 - acc: 0.5409 - val_loss: 0.9436 - val_acc: 0.4887
Epoch 15/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8901 - acc: 0.5506 - val_loss: 0.9311 - val_acc: 0.5152
Epoch 16/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8824 - acc: 0.5404 - val_loss: 0.9232 - val_acc: 0.5298
Epoch 17/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8759 - acc: 0.5479 - val_loss: 0.9150 - val_acc: 0.5656
Epoch 18/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8692 - acc: 0.5586 - val_loss: 0.9191 - val_acc: 0.5470
Epoch 19/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8638 - acc: 0.5546 - val_loss: 0.9147 - val_acc: 0.5311
Epoch 20/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8600 - acc: 0.5683 - val_loss: 0.9464 - val_acc: 0.5205
Epoch 21/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8530 - acc: 0.5811 - val_loss: 0.9095 - val_acc: 0.5338
Epoch 22/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8509 - acc: 0.5625 - val_loss: 0.9044 - val_acc: 0.5656
Epoch 23/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8439 - acc: 0.5802 - val_loss: 0.9030 - val_acc: 0.5166
Epoch 24/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8438 - acc: 0.5656 - val_loss: 0.8902 - val_acc: 0.5629
Epoch 25/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8411 - acc: 0.5669 - val_loss: 0.8925 - val_acc: 0.5311
Epoch 26/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8384 - acc: 0.5700 - val_loss: 0.8885 - val_acc: 0.5430
Epoch 27/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8343 - acc: 0.5643 - val_loss: 0.8836 - val_acc: 0.5589
Epoch 28/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8313 - acc: 0.5762 - val_loss: 0.9028 - val_acc: 0.5139
Epoch 29/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8298 - acc: 0.5714 - val_loss: 0.8873 - val_acc: 0.5510
Epoch 30/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8261 - acc: 0.5700 - val_loss: 0.9187 - val_acc: 0.5325
Epoch 31/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8222 - acc: 0.5873 - val_loss: 0.8812 - val_acc: 0.5642
Epoch 32/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8210 - acc: 0.5771 - val_loss: 0.8823 - val_acc: 0.5510
Epoch 33/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8204 - acc: 0.5890 - val_loss: 0.8753 - val_acc: 0.5576
Epoch 34/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8164 - acc: 0.5793 - val_loss: 0.8955 - val_acc: 0.5338
Epoch 35/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8148 - acc: 0.5851 - val_loss: 0.8790 - val_acc: 0.5510
Epoch 36/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8154 - acc: 0.5815 - val_loss: 0.8803 - val_acc: 0.5298
Epoch 37/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8139 - acc: 0.5806 - val_loss: 0.8731 - val_acc: 0.5656
Epoch 38/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8127 - acc: 0.5758 - val_loss: 0.8894 - val_acc: 0.5404
Epoch 39/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8074 - acc: 0.5846 - val_loss: 0.8696 - val_acc: 0.5722
Epoch 40/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8069 - acc: 0.5829 - val_loss: 0.8753 - val_acc: 0.5616
Epoch 41/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8032 - acc: 0.5829 - val_loss: 0.8709 - val_acc: 0.5497
Epoch 42/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7993 - acc: 0.6085 - val_loss: 0.8828 - val_acc: 0.5815
Epoch 43/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8053 - acc: 0.5939 - val_loss: 0.8757 - val_acc: 0.5642
Epoch 44/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.8049 - acc: 0.5855 - val_loss: 0.8632 - val_acc: 0.5748
Epoch 45/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7998 - acc: 0.6027 - val_loss: 0.8823 - val_acc: 0.5576
Epoch 46/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7997 - acc: 0.6001 - val_loss: 0.8808 - val_acc: 0.5510
Epoch 47/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7973 - acc: 0.5890 - val_loss: 0.8812 - val_acc: 0.5298
Epoch 48/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7970 - acc: 0.5908 - val_loss: 0.8711 - val_acc: 0.5642
Epoch 49/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7962 - acc: 0.5921 - val_loss: 0.8733 - val_acc: 0.5709
Epoch 50/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7956 - acc: 0.5943 - val_loss: 0.8601 - val_acc: 0.5748
Epoch 51/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7914 - acc: 0.5948 - val_loss: 0.8761 - val_acc: 0.5589
Epoch 52/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7906 - acc: 0.5992 - val_loss: 0.8773 - val_acc: 0.5510
Epoch 53/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7886 - acc: 0.6058 - val_loss: 0.8664 - val_acc: 0.5828
Epoch 54/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7857 - acc: 0.6014 - val_loss: 0.8627 - val_acc: 0.5775
Epoch 55/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7867 - acc: 0.6032 - val_loss: 0.8625 - val_acc: 0.5735
Epoch 56/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7830 - acc: 0.6067 - val_loss: 0.8591 - val_acc: 0.5629
Epoch 57/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7826 - acc: 0.6063 - val_loss: 0.8763 - val_acc: 0.5417
Epoch 58/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7818 - acc: 0.6036 - val_loss: 0.8584 - val_acc: 0.5629
Epoch 59/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7816 - acc: 0.6014 - val_loss: 0.8783 - val_acc: 0.5391
Epoch 60/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7812 - acc: 0.6120 - val_loss: 0.8834 - val_acc: 0.5483
Epoch 61/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7795 - acc: 0.6041 - val_loss: 0.8585 - val_acc: 0.5775
Epoch 62/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7753 - acc: 0.6072 - val_loss: 0.8568 - val_acc: 0.5868
Epoch 63/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7775 - acc: 0.6036 - val_loss: 0.8582 - val_acc: 0.5669
Epoch 64/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7727 - acc: 0.6209 - val_loss: 0.8536 - val_acc: 0.5828
Epoch 65/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7705 - acc: 0.6116 - val_loss: 0.8916 - val_acc: 0.5550
Epoch 66/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7707 - acc: 0.6182 - val_loss: 0.8563 - val_acc: 0.5907
Epoch 67/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7719 - acc: 0.6186 - val_loss: 0.8570 - val_acc: 0.5775
Epoch 68/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7706 - acc: 0.6186 - val_loss: 0.8863 - val_acc: 0.5417
Epoch 69/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7663 - acc: 0.6240 - val_loss: 0.8635 - val_acc: 0.5722
Epoch 70/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7685 - acc: 0.6098 - val_loss: 0.8580 - val_acc: 0.5921
Epoch 71/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7655 - acc: 0.6195 - val_loss: 0.8543 - val_acc: 0.5868
Epoch 72/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7648 - acc: 0.6138 - val_loss: 0.8965 - val_acc: 0.5351
Epoch 73/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7612 - acc: 0.6213 - val_loss: 0.8767 - val_acc: 0.5510
Epoch 74/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7616 - acc: 0.6244 - val_loss: 0.8944 - val_acc: 0.5483
Epoch 75/75
2263/2263 [==============================] - 3s 1ms/step - loss: 0.7594 - acc: 0.6222 - val_loss: 0.8740 - val_acc: 0.5523
time: 3min 39s

STEP 5: Evaluate the trained network

In [49]:
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
	predictions.argmax(axis=1), target_names=lb.classes_))

N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["acc"], label="train_acc")
plt.plot(N, H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig('results.png')
[INFO] evaluating network...
              precision    recall  f1-score   support

        cats       0.47      0.75      0.58       249
        dogs       0.48      0.23      0.31       257
       panda       0.74      0.68      0.71       249

    accuracy                           0.55       755
   macro avg       0.56      0.56      0.53       755
weighted avg       0.56      0.55      0.53       755

time: 411 ms

STEP 6: Test the model on new data

In [50]:
image = cv2.imread(TEST_IMAGE)
output = image.copy()

## doing the same pre-processing we did above
image = cv2.resize(image, (32, 32))
image = image.astype("float") / 255.0
image = image.flatten()
image = image.reshape((1, image.shape[0]))
time: 265 ms
In [51]:
preds = model.predict(image)

## take the label with the highest probability
i = preds.argmax(axis=1)[0]
label = lb.classes_[i]
print(label, preds[0][i])
panda 0.99365956
time: 7.1 ms
In [0]: