Model Building

To start with creating the model, we first expand the new pixels column to make a dataframe. Using that dataframe and necessary target values (age and gender), we will split our dataset into training and Validation Dataset.

Python3




# create the X (predictor) variables
X_new = pd.DataFrame(df['new_pixels'].tolist())
  
# Assign Predictor Variables and Target variables
X = X_new
y_age = df['age'].values
y_gender = df['gender'].values
  
# split the Variables into Train and Validation sets
y_reg_train, y_reg_val, y_clf_train, y_clf_val, X_train, X_val = train_test_split(y_age,
                                                                                  y_gender,
                                                                                  X,
                                                                                  test_size=0.2,
                                                                                  stratify = y_gender,
                                                                                  random_state=42)
# Check the shape
y_reg_train.shape, y_reg_val.shape, y_clf_train.shape, y_clf_val.shape, X_train.shape, X_val.shape


Output:

((18964,), (4741,), (18964,), (4741,), (18964, 2304), (4741, 2304))

Normalizations

Before we proceed forward, a necessary step in Data preparation for training is to normalize the pixel data. This ensures that the pixels are in a similar data distribution which will help in faster model convergence in training.

Python3




# normalising the Pixel data for training dataset and then reshaping it to (48,48,1) 
Xmin = 0
Xmax = 255
X_train = X_train.values
X_train = X_train - Xmin/(Xmax-Xmin)
X_train = X_train.reshape(-1,48,48,1)
  
# similar step is taken for Validation set
X_val = X_val.values
X_val = X_val - Xmin/(Xmax-Xmin)
X_val = X_val.reshape(-1,48,48,1)


Creating The CNN model Architecture

The model architecture is made using functional API of keras. This method is helpful in joining two types of output (in this case regression and classification) as a single output to be fed to the model.

The Model takes 3 parts:

  1. Input: This layer takes in the input data with shape (48,48,1)
  2. Middle architecture: All the Deep Learning Networks are cascaded over Input layer, i.e., the input layer is joined with subsequent layers in the deep learning model. In this case the architecture consists of:
    • a single Conv2D layer with 16 node
    • a single Conv2D layer with 32 nodes followed by Maxpooling2D layer
    • two conv2D layer with 64 nodes each
    • a flatten layer
    • two dense layer of 128 and 32 nodes respectively
  3. Output: The output of the model consist of two dense layers which corresponds to the necessary task they will perform which are:
    • a dense layer with 1 node and sigmoid activation which will perform the gender classification
    • a dense layer with 1 node and linear activation which will perform the age regression prediction

For all the other layers, necessary activations were provided. To understand the underlying layers and the parameters involved in the model architecture created above, we will plot the model

Python3




input_layer = keras.Input(shape=(48, 48, 1), name="Input image")
x = layers.Conv2D(16, 3, activation="relu")(input_layer)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(64, 3, activation="relu")(x)
x = layers.Conv2D(64, 3, activation="relu")(x)
x = layers.Flatten()(x)
x = layers.Dense(128, activation='relu')(x)
x = layers.Dense(32, activation='relu')(x)
  
  
  
out_a = keras.layers.Dense(1, activation='sigmoid', name='g_clf')(x)
out_b = keras.layers.Dense(1, activation='linear', name='a_reg')(x)
  
model = keras.Model( inputs = input_layer, outputs = [out_a, out_b], name="age_gender_model")


Output:

Model Training

We compile the model with necessary loss, metrics and optimizers (remember to do so for each layer as you will see in the code below) and fitted the model for 200 epochs with an earlystopping of patience 25.

Python3




# compile the model
model.compile(
    loss = {
        "g_clf": 'binary_crossentropy',
        "a_reg": 'mse'
    },
  
    metrics = {
        "g_clf": 'accuracy',
        "a_reg": 'mse'
    },
  
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.003)
)
  
# create an EarlyStopping instance which will stop if the val_loss doesn't change much in 25 epochs
callback = EarlyStopping(monitor='val_loss',
                         patience=25,
                         verbose=0)
  
# train the model 
history = model.fit(X_train, 
                    [y_clf_train, y_reg_train],
                    batch_size = 256
                    validation_data= (X_val, [y_clf_val, y_reg_val]), 
                    epochs=200, callbacks = [callback])


Output:

Epoch 1/200
75/75 [==============================] - 79s 662ms/step - loss: 2402.7998 - g_clf_loss: 2.7341 - a_reg_loss: 2400.0664 - g_clf_accuracy: 0.4776 - a_reg_mse: 2400.0664 - val_loss: 423.1724 - val_g_clf_loss: 1.0336 - val_a_reg_loss: 422.1387 - val_g_clf_accuracy: 0.4200 - val_a_reg_mse: 422.1387
Epoch 2/200
75/75 [==============================] - 52s 693ms/step - loss: 357.2810 - g_clf_loss: 1.4903 - a_reg_loss: 355.7906 - g_clf_accuracy: 0.4606 - a_reg_mse: 355.7906 - val_loss: 449.3816 - val_g_clf_loss: 1.4558 - val_a_reg_loss: 447.9258 - val_g_clf_accuracy: 0.5916 - val_a_reg_mse: 447.9258
Epoch 3/200
75/75 [==============================] - 51s 683ms/step - loss: 290.7226 - g_clf_loss: 0.9503 - a_reg_loss: 289.7724 - g_clf_accuracy: 0.6046 - a_reg_mse: 289.7724 - val_loss: 231.5632 - val_g_clf_loss: 0.6586 - val_a_reg_loss: 230.9046 - val_g_clf_accuracy: 0.6748 - val_a_reg_mse: 230.9046
Epoch 4/200
...
Epoch 58/200
75/75 [==============================] - 49s 653ms/step - loss: 19.4069 - g_clf_loss: 0.3974 - a_reg_loss: 19.0095 - g_clf_accuracy: 0.8104 - a_reg_mse: 19.0095 - val_loss: 114.9000 - val_g_clf_loss: 0.4197 - val_a_reg_loss: 114.4803 - val_g_clf_accuracy: 0.8019 - val_a_reg_mse: 114.4803

Plotting the Losses and Accuracy for Regression and Classification Respectively

To visualize the losses, we will use history of our model training and plot the necessary metrices.

Python3




# plotting for Gender Classification Accuracy
plt.plot(history.history['g_clf_accuracy'], label = 'training accuracy')
plt.plot(history.history['val_g_clf_accuracy'], label = 'validation accuracy')
plt.title('Gender classification model Accuracy')
plt.xlabel('epoch')
plt.ylabel('Accuracy for gender classification')
plt.legend()
plt.show()


Output:

Python3




# plotting the mse loss for age regression 
plt.plot(history.history['a_reg_mse'], label = 'training loss')
plt.plot(history.history['val_a_reg_mse'], label = 'validation loss')
plt.title('Age Estimation model loss')
plt.xlabel('epoch')
plt.ylabel('loss for age estimation')
plt.legend()
  
plt.show()


Output:

Model Evaluations

Python3




model.evaluate(X_val, [y_clf_val, y_reg_val])


Output:

149/149 [==============================] - 3s 18ms/step - loss: 114.9000 - g_clf_loss: 0.4197 - a_reg_loss: 114.4803 - g_clf_accuracy: 0.8019 - a_reg_mse: 114.4803

[114.89997100830078,
0.4196634590625763,
114.48027801513672,
0.8019405007362366,
114.48027801513672]

Predictn Age & Gender from the model

We created a subplot of 3×3 with random indices and predicted the age and gender for the given input image

Python3




fig, ax = plt.subplots(3,3, figsize = (10,15))
  
ax = ax.ravel()
  
res = random.sample(range(0, X_val.shape[0]), 9)
  
for i,id in enumerate(res):
    ax[i].imshow(X_val[id])
    ax[i].set_title(f'Age-group: {y_reg_val[id]}, Gender: {gender_dict[str(y_clf_val[id])]}')
      
    pred_Gender, pred_age = model.predict(tf.expand_dims(X_val[id], 0), verbose = 0)
    y_value = np.where(pred_Gender > 0.5, 1,0)
    ax[i].set_xlabel(f'gender: {gender_dict[str(y_value[0][0])]} , age: {int(np.round(pred_age,0))}')
      
plt.savefig('prediction_subplot.png')


Output:

In the above subplot, the title at the top signifies actual age and gender whereas the title below signifies predicted age and gender. As you can see the predictions are quite good.

Age and Gender Prediction using CNN

In this article, we will create an Age and Gender Prediction model using Keras Functional API, which will perform both Regression to predict the Age of the person and Classification to predict the Gender from face of the person.

Similar Reads

Age and Gender Prediction

Keras Functional API offers a more flexible and creative way to make models of higher complexity. One such Complexity arises when making a model that does more than one type of supervised prediction (Regression and Classification predictions). We will unravel a similar scenario to create a model that can perform Regression and Classification as well....

Model Building

...

Conclusion

...

Contact Us