Building a Deep Face Detection Model with Python and TensorFlow (Part 4)
Tags: ai, deeplearning, machinelearning, python
Published: 2024-04-04 05:18:27

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](https://dev.to/dexterxt/building-a-deep-face-detection-model-with-python-and-tensorflow-3ofg)**

**Check out [Part 2](https://dev.to/dexterxt/building-a-deep-face-detection-model-with-python-and-tensorflow-part-2-59en)**

**Check out [Part 3](https://dev.to/dexterxt/building-a-deep-face-detection-model-with-python-and-tensorflow-part-3-515n)**

## 9. Define Losses and Optimizers

**9.1 Define Optimizer and Learning Rate**

```python
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**

```python
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**

```python
localization_loss(y[1], coords)
classloss(y[0], classes)
regressloss(y[1], coords)
```

## 10. Train Neural Network

**10.1 Create Custom Model Class**

```python
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)
```

```python
model = FaceTracker(facetracker)
model.compile(opt, classloss, regressloss)
```

**10.2 Train**

```python
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**

```python
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**

```python
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**

```python
from tensorflow.keras.models import load_model

facetracker.save('facetracker.h5')
facetracker = load_model('facetracker.h5')
```

**11.3 Real-Time Detection**

```python
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!