read

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.

Training Images

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:

  1. 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.
  2. We need to use the (BinaryCrossentropy)[https://www.tensorflow.org/api_docs/python/tf/keras/losses/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)

Trained

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.

Blog Logo

Chris Greening


Published

Image

Chris Greening

Blogging about random stuff

View All Posts