Building a Deep Face Detection Model with Python and TensorFlow (Part 4)
EvolveDev
Posted on April 4, 2024
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)
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
9.3 Test out Loss Metrics
localization_loss(y[1], coords)
classloss(y[0], classes)
regressloss(y[1], coords)
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)
model = FaceTracker(facetracker)
model.compile(opt, classloss, regressloss)
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])
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()
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)
11.2 Save the Model
from tensorflow.keras.models import load_model
facetracker.save('facetracker.h5')
facetracker = load_model('facetracker.h5')
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()
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!
Posted on April 4, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.