Binary classification is used where you have data that falls into two possible classes - a classic example would be “hotdog” or “not hotdog” ((if you don’t get the hot dog reference then watch this).
If you’re looking to categorise your input into more than 2 categories then checkout TensorFlow Categorical Classification
You can find the example notebook(s) for this post in the tensorflow-tutorial GitHub repo.
For this small tutorial, I’ve created a python generator that creates images with either a square or a circle.
def data_generator(): i = 0 while(True): if i >= 1000: i = 0 # our output value will be 0 or 1 Y = i % 2 X = np.zeros((image_width, image_height, 1)) # size of our shape radius = int(np.random.uniform(10,20)) # position of our shape center_x = int(np.random.uniform(radius, image_width - radius)) center_y = int(np.random.uniform(radius, image_height - radius)) if Y == 0: # generate a square X[center_y - radius:center_y + radius, center_x - radius:center_x + radius] = 1 else: # generate a circle for y in range(-radius, radius): for x in range(-radius, radius): if x*x + y*y <= radius*radius: X[y+center_y, x+center_x] = 1 yield X, [Y] i = i + 1
Our simple generator will generate an infinite number of samples, alternating between a random square and random circle.
To get binary classification working we need to take note of a couple of things:
- We need to have one output neuron with a sigmoid activation function. The sigmoid activation function will return a value between 0 and 1 - we’ll use this to determine how confident the network is that input falls the true class.
- We need to use the BinaryCrossentropy loss function during our training.
Our simple model looks like this:
model = Sequential([ Conv2D(8, 3, padding='same', activation='relu', input_shape=(image_width, image_height, 1), name='conv_layer'), MaxPooling2D(name='max_pooling'), Flatten(), Dense( 10, activation='relu', name='hidden_layer' ), Dense(1, activation='sigmoid', name='output') ])
And when we compile it we specify the loss function that we want to optimise:
model.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy(), metrics=['accuracy'])
Given our simple problem (is it a square or a triangle) you should be able to get close to 100% accuracy with just a few training epochs.
You can test the model pretty easily by feeding in some more random samples from the training set:
# get a batch of samples from the dataset X, Y = next(iter(train_dataset)) # ask the model to predict the output for our samples predicted_Y = model.predict(X.numpy()) # show the images along with the predicted value plot_images(X, predicted_Y)
As you can see it is pretty good at classifying the images, mostly producing 0 or 1 for each image.
Checkout the full code in the GitHub repo.