Problem description

Our task was to predict a person’s age from their facial features (denoted by “Young”, “Middle” and “Old”). We trained a data set of 19,906 + photos and the corresponding age of each picture (all of ah3’s heads…). , the test set contained 6,636 pictures. First, we loaded the data set, and then we built, compiled and trained the model through the deep learning framework Keras to predict the ages of 6,636 head pictures

Import the required modules

import os
import random
import pandas as pd
import numpy as np
from PIL import Image
Copy the code

Load data set

root_dir=os.path.abspath('E:/data/age')
train=pd.read_csv(os.path.join(root_dir,'train.csv'))
test=pd.read_csv(os.path.join(root_dir,'test.csv'))

print(train.head())
print(test.head())
Copy the code
          ID   Class
0    377.jpg  MIDDLE
1  17814.jpg   YOUNG
2  21283.jpg  MIDDLE
3  16496.jpg   YOUNG
4   4487.jpg  MIDDLE
          ID
0  25321.jpg
1    989.jpg
2  19277.jpg
3  13093.jpg
4   5367.jpg
Copy the code

☺ (☺)

i=random.choice(train.index)
img_name=train.ID[i]
print(img_name)
img=Image.open(os.path.join(root_dir,'Train',img_name))
img.show()
print(train.Class[i])
Copy the code
20188.jpg
MIDDLE
Copy the code

The difficulties in

When we open a few pictures randomly, we can find that the differences between the pictures are quite large. Everyone feel:

  1. Good quality pictures:

    • Middle:

      **Middle**
    • Young:

      **Young**
    • Old:

      **Old**
  2. 2. Of poor quality:

    • Middle:

      **Middle**

Here are the questions we need to face:

  1. Image size difference: One image is 66×46 and another is 102×87
  2. Different faces and angles:
    • Side face:

    • Positive face:

  3. Image quality varies (directly above) :




    illustrations

  4. The difference between brightness and contrast




    brightness



    contrast

    For now, let’s just focus on image sizing and reset each image to 32×32

Format image sizes and convert images into NUMpy arrays

temp=[] for img_name in train.ID: Img_path = OS. Path. Join (root_dir, 'Train' img_name) img = Image. Open (img_path) img = img. Resize (aiaa (32)) array = np. Array (img) temp.append(array.astype('float32')) train_x=np.stack(temp) print(train_x.shape) print(train_x.ndim)Copy the code
(19906, 32, 32, 3)
4
Copy the code
temp=[] for img_name in test.ID: Img_path = OS. Path. Join (root_dir, 'Test' img_name) img = Image. Open (img_path) img = img. Resize (aiaa (32)) array = np. Array (img) temp.append(array.astype('float32')) test_x=np.stack(temp) print(test_x.shape)Copy the code
(6636, 32, 32, 3)
Copy the code

In addition, we will normalize the image, which will make the model training faster


train_x = train_x / 255.
test_x = test_x / 255.
Copy the code

Let’s take a look at the picture

train.Class.value_counts(normalize=True)
Copy the code
MIDDLE    0.542751
YOUNG     0.336883
OLD       0.120366
Name: Class, dtype: float64
Copy the code
test['Class'] = 'MIDDLE'
test.to_csv('sub01.csv', index=False)
Copy the code

Treating the target variable as a virtual column makes it more acceptable for the model to recognize it

import keras
from sklearn.preprocessing import LabelEncoder
lb=LabelEncoder()
train_y=lb.fit_transform(train.Class)
print(train_y)
train_y=keras.utils.np_utils.to_categorical(train_y)
print(train_y)
print(train_y.shape)
Copy the code
2 0... [0, 0, 0, 0] [[1. 0. 0.] [0. 0. 1.] [1. 0. 0.]... [1. 0. 0.] [1. 0. 0.] [1. 0. 0.]] (19906, 3)Copy the code

Create the model

Input_num_units =(32,32,3) hidden_num_units=500 output_num_units=3 epochs=5 batch_size=128Copy the code
from keras.models import Sequential from keras.layers import Dense,Flatten,InputLayer model=Sequential({ InputLayer(input_shape=input_num_units), Flatten(), Dense(units=hidden_num_units,activation='relu'), Dense (input_shape = (32,32,3), units = output_num_units, activation = 'softmax')}) model. The summary ()Copy the code
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_23 (InputLayer) (None, 32, 32, 3) 0 _________________________________________________________________ flatten_23 (Flatten) (None, 3072) 0 _________________________________________________________________ dense_45 (Dense) (None, 500) 1536500 _________________________________________________________________ dense_46 (Dense) (None, 3) 1503 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Total params: 1538003 Trainable params: 1538003 Non - trainable params: 0 _________________________________________________________________Copy the code

Compilation model

# model.compile(optimizer='sgd',loss='categorical_crossentropy',metrics=['accuracy'])
model.compile(optimizer='sgd',loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(train_x,train_y,batch_size=batch_size,epochs=epochs,verbose=1)
Copy the code
Epoch 1/5 19906/19906 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 4 s - loss: 0.8878 acc: 0.5809 Epoch 2/5 19906/19906 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 4 s - loss: 0.8420 acc: 0.6077 Epoch 3/5 19906/19906 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 4 s - loss: 0.8210 acc: 0.6214 Epoch 4/5 19906/19906 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 4 s - loss: 0.8149 acc: 0.6194 Epoch 5/5 19906/19906 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 4 s - loss: 0.8042 acc: 0.6305 < keras. Callbacks. History at 0 x1d3803e6278 >Copy the code
The model fit (train_x train_y, batch_size = batch_size, epochs = epochs, verbose = 1, validation_split = 0.2)Copy the code
Train on 15924 samples, validate on 3982 samples Epoch 1/5 15924/15924 [==============================] - 3s - loss: 0.7970-ACC: 0.6375 - val_loss: 0.7854 - val_ACC: 0.6396 Epoch 2/5 15924/15924 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 3 s - loss: 0.7919 acc: 0.6378 - val_loss: 0.7767 - val_acc: 0.6519 Epoch 3/5 15924/15924 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 3 s - loss: 0.7870 acc: 0.6404 - val_loss: 0.7754 - val_acc: 0.6534 Epoch 4/5 15924/15924 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 3 s - loss: 0.7806 - ACC: 0.6439 - val_loss: 0.7715 - val_ACC: 0.6524 Epoch 5/5 15924/15924 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 3 s - loss: 0.7755 acc: 0.6519 - val_loss: 0.7970 - val_acc: 0.6346 <keras.callbacks.History at 0x1D3800a4eb8 >Copy the code

To optimize the

We used the most basic model to process the age prediction, and the final prediction was 0.6375. Next, try to optimize from the following angles:

  1. Use better neural network models
  2. Increase training sessions
  3. Grayscale the image (because image color is not a particularly important feature for this problem).

Optimize1 uses convolutional neural networks

After the convolution layer was added, the prediction accuracy increased from 6.3 to 6.7. At the beginning, the number of epoCHS rounds is 5, and the number of training rounds is increased to 10. At this time, the accuracy rate is 6.87. The number of training rounds was then increased to 20, with no change.

Conv2D layer

keras.layers.convolutional.Conv2D(filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)

  • Filters: Dimensions of the output
  • Strides: Strides for the convolution

For more information about Conv2D see the Conv2D layer of the Keras documentation

Filtersize =(5,5) epochs =10 batchsize=128 input_shape=(32,32,3)Copy the code
from keras.models import Sequential model = Sequential() model.add(keras.layers.InputLayer(input_shape=input_shape)) model.add(keras.layers.convolutional.Conv2D(filters, filtersize, strides=(1, 1), padding='valid', data_format="channels_last", activation='relu')) model.add(keras.layers.MaxPooling2D(pool_size=(2, 2))) model.add(keras.layers.Flatten()) model.add(keras.layers.Dense(units=3, input_dim=50,activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(train_x, train_y, epochs=epochs, Batch_size = batchsize, validation_split = 0.3) model. The summary ()Copy the code
Train on 13934 samples, validate on 5972 samples Epoch 1/10 13934/13934 [==============================] - 9s - loss: 0.8986-ACC: 0.5884 - val_loss: 0.8352-val_ACC: 0.6271 Epoch 2/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.8141 acc: 0.6281 - val_loss: 0.7886 - val_acc: 0.6474 Epoch 3/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7788 acc: 0.6504 - val_loss: 0.7706 - val_acc: 0.6551 Epoch 4/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7638 - ACC: 0.6577 - val_loss: 0.7559 - val_ACC: 0.6626 Epoch 5/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7484 acc: 0.6679 - val_loss: 0.7457 - val_acc: 0.6710 Epoch 6/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7346 acc: 0.6723 - val_loss: 0.7490 - val_acc: 0.6780 Epoch 7/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7217-ACC: 0.6804 - val_loss: 0.7298-val_acc: 0.6795 Epoch 8/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7162 acc: 0.6826 - val_loss: 0.7248 - val_acc: 0.6792 Epoch 9/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7082 acc: 0.6892 - val_loss: 0.7202 - val_acc: 0.6890 Epoch 10/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 9 s - loss: 0.7001 - ACC: 0.6940 - val_loss: 0.7226 - val_ACC: 0.6885 _________________________________________________________________ Layer (type) the Output Shape Param # ================================================================= input_6 (InputLayer) (None, 32, 32, 3) 0 _________________________________________________________________ conv2d_6 (Conv2D) (None, 28, 28, 10) 760 _________________________________________________________________ max_pooling2d_6 (MaxPooling2 (None, 14, 14, 10) 0 _________________________________________________________________ flatten_6 (Flatten) (None, 1960) 0 _________________________________________________________________ dense_6 (Dense) (None, 3) 5883 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Total params: 6643 Trainable params: 6643 Non - trainable params: 0 _________________________________________________________________Copy the code

Optimize2 increases the number of layers of the neural network

We added several more layers to the model and improved the output dimension of several layers of volume, and the result was significantly improved: 0.750904

Filters1 =50 filters2=100 filters3=100 filtersize=(5,5) epochs =10 batchsize=128 input_shape=(32,32,3)Copy the code
from keras.models import Sequential model = Sequential() model.add(keras.layers.InputLayer(input_shape=input_shape)) model.add(keras.layers.convolutional.Conv2D(filters1, filtersize, strides=(1, 1), padding='valid', data_format="channels_last", activation='relu')) model.add(keras.layers.MaxPooling2D(pool_size=(2, 2))) model.add(keras.layers.convolutional.Conv2D(filters2, filtersize, strides=(1, 1), padding='valid', data_format="channels_last", activation='relu')) model.add(keras.layers.MaxPooling2D(pool_size=(2, 2))) model.add(keras.layers.convolutional.Conv2D(filters3, filtersize, strides=(1, 1), padding='valid', data_format="channels_last", activation='relu')) model.add(keras.layers.Flatten()) model.add(keras.layers.Dense(units=3, input_dim=50,activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(train_x, train_y, epochs=epochs, Batch_size = batchsize, validation_split = 0.3) model. The summary ()Copy the code
Train on 13934 samples, validate on 5972 samples Epoch 1/10 13934/13934 [==============================] - 44s - loss: 0.8613-ACC: 0.5985 - val_loss: 0.7778 - val_ACC: 0.6586 Epoch 2/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 44 s - loss: 0.7493 acc: 0.6697 - val_loss: 0.7545 - val_acc: 0.6808 Epoch 3/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - s - 43 loss: 0.7079 acc: 0.6877 - val_loss: 0.7150 - val_acc: 0.6947 Epoch 4/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - s - 43 loss: 0.6694 - ACC: 0.7061 - val_loss: 0.6496 - val_ACC: 0.7261 Epoch 5/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] 43 - s - loss: 0.6274 acc: 0.7295 - val_loss: 0.6683 - val_acc: 0.7125 Epoch 6/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - s - 43 loss: 0.5950 acc: 0.7462 - val_loss: 0.6194 - val_acc: 0.7400 Epoch 7/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - s - 43 loss: 0.5562 - ACC: 0.7655 - val_loss: 0.5981 - val_ACC: 0.7465 Epoch 8/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] 43 - s - loss: 0.5165 acc: 0.7852 - val_loss: 0.6458 - val_acc: 0.7354 Epoch 9/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 46 s - loss: 0.4826 acc: 0.7986 - val_loss: 0.6206 - val_acc: 0.7467 Epoch 10/10 13934/13934 [= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] - 45 s - loss: 0.4530-ACC: 0.8130 - val_loss: 0.5984 - val_ACC: 0.7569 _________________________________________________________________ Layer (type) the Output Shape Param # ================================================================= input_15 (InputLayer) (None, 32, 32, 3) 0 _________________________________________________________________ conv2d_31 (Conv2D) (None, 28, 28, 50) 3800 _________________________________________________________________ max_pooling2d_23 (MaxPooling (None, 14, 14, 50) 0 _________________________________________________________________ conv2d_32 (Conv2D) (None, 10, 10, 100) 125100 _________________________________________________________________ max_pooling2d_24 (MaxPooling (None, 5, 5, 100) 0 _________________________________________________________________ conv2d_33 (Conv2D) (None, 1, 1, 100) 250100 _________________________________________________________________ flatten_15 (Flatten) (None, 100) 0 _________________________________________________________________ dense_7 (Dense) (None, 3) 303 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Total params: 379303 Trainable params: 379303 Non - trainable params: 0 _________________________________________________________________Copy the code

The output

pred=model.predict_classes(test_x)
pred=lb.inverse_transform(pred)
print(pred)
test['Class']=pred
test.to_csv('sub02.csv',index=False)
Copy the code
6636/6636 [==============================] - 7s     
['MIDDLE' 'YOUNG' 'MIDDLE' ..., 'MIDDLE' 'MIDDLE' 'YOUNG']
Copy the code
i = random.choice(train.index) img_name = train.ID[i] img=Image.open(os.path.join(root_dir,'Train',img_name)) img.show()  pred = model.predict_classes(train_x) print('Original:', train.Class[i], 'Predicted:', lb.inverse_transform(pred[i]))Copy the code
19872/19906 [============================>.] - ETA: 0sOriginal: MIDDLE Predicted: MIDDLE
Copy the code

The results of





image.png

You can optimize it. Let’s go on