DEV Community

Dexter
Dexter

Posted on

Building a Deep Face Detection Model with Python and TensorFlow (Part 4)

Welcome back to our tutorial on building a deep face detection model using Python and TensorFlow. In this part, we'll cover steps 9 through 11, including defining losses, optimizers, training the model, and making predictions.

Check out Part 1

Check out Part 2

Check out Part 3

9. Define Losses and Optimizers

9.1 Define Optimizer and Learning Rate

batches_per_epoch = len(train)
lr_decay = (1. / 0.75 - 1) / batches_per_epoch
opt = tf.keras.optimizers.Adam(learning_rate=0.0001, decay=lr_decay)
Enter fullscreen mode Exit fullscreen mode

9.2 Create Localization Loss and Classification Loss

def localization_loss(y_true, yhat):            
    delta_coord = tf.reduce_sum(tf.square(y_true[:, :2] - yhat[:, :2]))

    h_true = y_true[:, 3] - y_true[:, 1] 
    w_true = y_true[:, 2] - y_true[:, 0] 

    h_pred = yhat[:, 3] - yhat[:, 1] 
    w_pred = yhat[:, 2] - yhat[:, 0] 

    delta_size = tf.reduce_sum(tf.square(w_true - w_pred) + tf.square(h_true - h_pred))

    return delta_coord + delta_size

classloss = tf.keras.losses.BinaryCrossentropy()
regressloss = localization_loss
Enter fullscreen mode Exit fullscreen mode

9.3 Test out Loss Metrics

localization_loss(y[1], coords)
classloss(y[0], classes)
regressloss(y[1], coords)
Enter fullscreen mode Exit fullscreen mode

10. Train Neural Network

10.1 Create Custom Model Class

class FaceTracker(Model): 
    def __init__(self, eyetracker,  **kwargs): 
        super().__init__(**kwargs)
        self.model = eyetracker

    def compile(self, opt, classloss, localizationloss, **kwargs):
        super().compile(**kwargs)
        self.closs = classloss
        self.lloss = localizationloss
        self.opt = opt

    def train_step(self, batch, **kwargs): 

        X, y = batch

        with tf.GradientTape() as tape: 
            classes, coords = self.model(X, training=True)

            batch_classloss = self.closs(y[0], classes)
            batch_localizationloss = self.lloss(tf.cast(y[1], tf.float32), coords)

            total_loss = batch_localizationloss + 0.5 * batch_classloss

            grad = tape.gradient(total_loss, self.model.trainable_variables)

        opt.apply_gradients(zip(grad, self.model.trainable_variables))

        return {"total_loss": total_loss, "class_loss": batch_classloss, "regress_loss": batch_localizationloss}

    def test_step(self, batch, **kwargs): 
        X, y = batch

        classes, coords = self.model(X, training=False)

        batch_classloss = self.closs(y[0], classes)
        batch_localizationloss = self.lloss(tf.cast(y[1], tf.float32), coords)
        total_loss = batch_localizationloss + 0.5 * batch_classloss

        return {"total_loss": total_loss, "class_loss": batch_classloss, "regress_loss": batch_localizationloss}

    def call(self, X, **kwargs): 
        return self.model(X, **kwargs)
Enter fullscreen mode Exit fullscreen mode
model = FaceTracker(facetracker)
model.compile(opt, classloss, regressloss)
Enter fullscreen mode Exit fullscreen mode

10.2 Train

logdir = 'logs'
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=logdir)
hist = model.fit(train, epochs=10, validation_data=val, callbacks=[tensorboard_callback])
Enter fullscreen mode Exit fullscreen mode

10.3 Plot Performance

hist.history

fig, ax = plt.subplots(ncols=3, figsize=(20, 5))

ax[0].plot(hist.history['total_loss'], color='teal', label='loss')
ax[0].plot(hist.history['val_total_loss'], color='orange', label='val loss')
ax[0].title.set_text('Loss')
ax[0].legend()

ax[1].plot(hist.history['class_loss'], color='teal', label='class loss')
ax[1].plot(hist.history['val_class_loss'], color='orange', label='val class loss')
ax[1].title.set_text('Classification Loss')
ax[1].legend()

ax[2].plot(hist.history['regress_loss'], color='teal', label='regress loss')
ax[2].plot(hist.history['val_regress_loss'], color='orange', label='val regress loss')
ax[2].title.set_text('Regression Loss')
ax[2].legend()

plt.show()
Enter fullscreen mode Exit fullscreen mode

11. Make Predictions

11.1 Make Predictions on Test Set

test_data = test.as_numpy_iterator()
test_sample = test_data.next()
yhat = facetracker.predict(test_sample[0])

fig, ax = plt.subplots(ncols=4, figsize=(20, 20))
for idx in range(4): 
    sample_image = test_sample[0][idx]
    sample_coords = yhat[1][idx]

    if yhat[0][idx] > 0.9:
        cv2.rectangle(sample_image, 
                      tuple(np.multiply(sample_coords[:2], [120, 120]).astype(int)),
                      tuple(np.multiply(sample_coords[2:], [120, 120]).astype(int)), 
                      (255, 0, 0), 2)

    ax[idx].imshow(sample_image)
Enter fullscreen mode Exit fullscreen mode

11.2 Save the Model

from tensorflow.keras.models import load_model

facetracker.save('facetracker.h5')
facetracker = load_model('facetracker.h5')
Enter fullscreen mode Exit fullscreen mode

11.3 Real-Time Detection

cap = cv2.VideoCapture(1)
while cap.isOpened():
    _ , frame = cap.read()
    frame = frame[50:500, 50:500, :]

    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    resized = tf.image.resize(rgb, (120, 120))

    yhat = facetracker.predict(np.expand_dims(resized/255, 0))
    sample_coords = yhat[1][0]

    if yhat[0] > 0.5: 
        # Controls the main rectangle
        cv2.rectangle(frame, 
                      tuple(np.multiply(sample_coords[:2], [450, 450]).astype(int)),
                      tuple(np.multiply(sample_coords[2:], [450, 450]).astype(int)), 
                      (255, 0, 0), 2)
        # Controls the label rectangle
        cv2.rectangle(frame, 
                      tuple(np.add(np.multiply(sample_coords[:2], [450, 450]).astype(int), [0, -30])),
                      tuple(np.add(np.multiply(sample_coords[:2], [450, 450]).astype(int), [80, 0])), 
                      (255, 0, 0), -1)

        # Controls the text rendered
        cv2.putText(frame, 'face', 
                    tuple(np.add(np.multiply(sample_coords[:2], [450, 450]).astype(int), [0, -5])),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

    cv2.imshow('Face Detection', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
Enter fullscreen mode Exit fullscreen mode

This wraps up part 4 of our tutorial. In the next part, we'll discuss how to evaluate the model's performance and fine-tune it for better results.

Stay tuned for the upcoming installment!

Top comments (0)