ruk·si

Keras
Annotated Multiclass Example

Updated at 2018-06-22 14:37

Fully annotated example of a Keras multi-class softmax classification model training, evaluation and prediction usage.

import keras
import numpy as np
from keras.layers import Dense, Dropout
from keras.losses import categorical_crossentropy
from keras.models import Sequential
from keras.optimizers import SGD

# we seed the random number generators for the sake of this example
np.random.seed(0)

# training inputs x and labels y
# labels are turned to "one-hot labels" with keras.utils.to_categorical
x_train = np.random.random((1000, 20))
labels_train = np.random.randint(10, size=(1000, 1))  # 1000 rows of numbers 0-9
y_train = keras.utils.to_categorical(labels_train, num_classes=10)

# test inputs x and labels y
x_test = np.random.random((100, 20))
labels_test = np.random.randint(10, size=(100, 1))  # 100 rows of numbers 0-9
y_test = keras.utils.to_categorical(labels_test, num_classes=10)

# training inputs are in a 1000 x 20 numpy array, "1000 rows of 20 items"
assert x_train.shape == (1000, 20)
assert type(x_train) == np.ndarray

# each input row has 20 numbers between 0 and 1,
# values are deterministic because we set np.random.seed(0) above
expected_first_train_x = np.array([
	0.5488135, 0.71518937, 0.60276338, 0.54488318, 0.4236548,
	0.64589411, 0.43758721, 0.891773, 0.96366276, 0.38344152,
	0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606,
	0.0871293, 0.0202184, 0.83261985, 0.77815675, 0.87001215,
])
assert np.allclose(x_train[0], expected_first_train_x)

# training labels are in a 1000 x 10 numpy array, "1000 rows of 10 items"
assert y_train.shape == (1000, 10)
expected_first_train_y = np.array([0, 0, 0, 0, 0, 1, 0, 0, 0, 0])
assert np.array_equal(y_train[0], expected_first_train_y)

# the inputs are 20-dimensional vectors from input_dim=20
model = Sequential()
model.add(Dense(64, activation='relu', input_dim=20))
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

# the above creates a neural network with 5 layers
assert len(model.layers) == 5

# we focus to minimize "categorical_crossentropy"
# by using stochastic gradient descent optimizer
sgd = SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss=categorical_crossentropy, optimizer=sgd)

# goes through the datasets 20 times from epochs=20
# will use 128 rows per gradient update from batch_size=128
history = model.fit(x_train, y_train, epochs=20, batch_size=128)

# training will print something like this for each epoch:
# Epoch 20/20
# 1000/1000 [==============================] - 0s - loss: 2.2863
#  100/100  [==============================] - 0s

# model.fit returns a history object with info how the training went
# in this case, it's loss for each epoch, this can be used to
# plot the training
assert type(history) == keras.callbacks.History
assert list(history.history.keys()) == ['loss']
assert len(history.history['loss']) == 20

# we test the trained model with data it hasn't seen
# model.evaluate returns loss + all metrics, but we have not defined
# any metrics so it will just be the loss
loss = model.evaluate(x_test, y_test, batch_size=128)
assert np.isclose(loss, 2.29517817497)

# let's use the trained model to give a prediction
single_sample = np.ndarray(buffer=expected_first_train_x, shape=(1, 20))
probabilities = model.predict(single_sample)

# each row of probabilities sums to 1.0 because of output layer softmax
assert sum(probabilities[0]) == 1.0

assert np.allclose(probabilities[0], [
	0.08671631, 0.10148139, 0.08006778, 0.10181929, 0.1092971,
	0.10233453, 0.11037925, 0.10788239, 0.10635556, 0.0936664,
])
# so our trained model would think train_x[0] is most likely 6
# (that is wrong, it is 5)=