Emotion classification from face datasets​
​by Diya Elizabeth
In this project, we use deep learning to make an emotion recognition convolution neural network by customizing the EfficientNet model pretrained on the ImageNe dataset. We used the FER-2013 dataset available in the Wolfram repository. Seven classes of emotions are considered in the dataset: happy, sad, angry, surprise, disgust, fear, and neutral. We try out different methods to tackle class imbalance. This model can be applied in teaching autistic children, young children in general, and people blind to facial expressions. It can also be used to train robots to interact more efficiently with humans.

Data Exploration

The data set used here is FER-2013. It has 35887 greyscale images of faces with expressions categorized into one of the seven categories: happy, sad, angry, surprise, disgust, fear, neutral. It was made under all challenging conditions, such as varying lighting, different head movements, and variances in facial features due to ethnicity, age, gender, facial hair, and glasses. This is important to not create a bias in our model.

Obtaining the data

ro=ResourceObject["FER-2013"]​​data=ResourceData[ro];
Out[]=
ResourceObject
Name: FER-2013
»
Type: DataResource
Description: The Facial Expression Recognition 2013 (FER-2013) Dataset


Overview of the data

classes=DeleteDuplicates[Values[data]];​​dataPerClass=Map[Function[{class},Select[data,SameQ[Values@#,class]&]],classes];
In[]:=
Counts[Values[data]]​​BarChart[Counts[Values[data]],ChartLabels->Keys@Counts[Values[data]],ChartStyle->"DarkRainbow",PlotLabel->"Distribution of classes in the dataset",AxesLabel->{Automatic,"Number of images"}]
Out[]=

happiness
8989,
neutral
6198,
sadness
6077,
anger
4953,
surprise
4002,
disgust
547,
fear
5121
Out[]=

Data distribution of classes of train and test sets

We choose 4000 random images from each class for our sample dataset. 70% of this sample dataset is chosen randomly as train dataset and the other 30% as test dataset. The function RandomSample is used to ensure that the data was chosen randomly to ensure an accurate representation of the original dataset in the train and test sets.
sampleData=Flatten@Map[RandomSample[#,UpTo[4000]]&,dataPerClass];​​{train,test}=TakeDrop[RandomSample[sampleData],Floor[0.7*Length[sampleData]]];
In[]:=
dataPerClass=Map[Function[{class},Select[data,SameQ[Values@#,class]&]],classes];​​sampleData=Flatten@Map[RandomSample[#,UpTo[4000]]&,dataPerClass];​​{train,test}=TakeDrop[RandomSample[sampleData],Floor[0.7*Length[sampleData]]];
In[]:=
BarChart[Counts[Values[sampleData]],ChartLabels->Keys@Counts[Values[sampleData]],ChartStyle->"DarkRainbow",PlotLabel->"Distribution of classes in the sample data",AxesLabel->{Automatic,"Number of images"}]​​BarChart[Counts[Values[train]],ChartLabels->Keys@Counts[Values[train]],ChartStyle->"DarkRainbow",PlotLabel->"Distribution of classes in the train set",AxesLabel->{Automatic,"Number of images"}]​​BarChart[Counts[Values[test]],ChartLabels->Keys@Counts[Values[test]],ChartStyle->"DarkRainbow",PlotLabel->"Distribution of classes in the test set",AxesLabel->{Automatic,"Number of images"}]​​
Out[]=
Out[]=
Out[]=

Transfer Learning with EfficientNet

To create a neural network, rather than create a new network from scratch, which may take days or weeks to train, we can use a pretrained model as a starting point and customize it for our needs. EfficientNet trained over the dataset ‘ImageNet’ can be adapted to the ‘FER-2013’ dataset as shown below:

Creating the neural network

We start with calling EfficientNet model pretrained on the dataset ‘ImageNet’.
In[]:=
NetModel["EfficientNet Trained on ImageNet"]
Out[]=
NetChain
Input
image
array(size: 3×224×224)
stem_conv
ConvolutionLayer
array(size: 32×112×112)
stem_bn
BatchNormalizationLayer
array(size: 32×112×112)
stem_activation
LogisticSigmoid[x]x
array(size: 32×112×112)
block1a
NetChain (6 nodes)
array(size: 16×112×112)
block2a
NetChain (9 nodes)
array(size: 24×56×56)
block2b
NetGraph (11 nodes)
array(size: 24×56×56)
block3a
NetChain (9 nodes)
array(size: 40×28×28)
block3b
NetGraph (11 nodes)
array(size: 40×28×28)
block4a
NetChain (9 nodes)
array(size: 80×14×14)
block4b
NetGraph (11 nodes)
array(size: 80×14×14)
block4c
NetGraph (11 nodes)
array(size: 80×14×14)
block5a
NetChain (9 nodes)
array(size: 112×14×14)
block5b
NetGraph (11 nodes)
array(size: 112×14×14)
block5c
NetGraph (11 nodes)
array(size: 112×14×14)
block6a
NetChain (9 nodes)
array(size: 192×7×7)
block6b
NetGraph (11 nodes)
array(size: 192×7×7)
block6c
NetGraph (11 nodes)
array(size: 192×7×7)
block6d
NetGraph (11 nodes)
array(size: 192×7×7)
block7a
NetChain (9 nodes)
array(size: 320×7×7)
top_conv
ConvolutionLayer
array(size: 1280×7×7)
top_bn
BatchNormalizationLayer
array(size: 1280×7×7)
top_activation
LogisticSigmoid[x]x
array(size: 1280×7×7)
avg_pool
AggregationLayer
vector(size: 1280)
top_dropout
DropoutLayer
vector(size: 1280)
predictions
LinearLayer
vector(size: 1000)
predictions_activation
SoftmaxLayer
vector(size: 1000)
Output
class

In order to train a new model, we can use this architecture. We remove the last Linear and Softmax layers and add our own layers as required to customize the net to our dataset.
In[]:=
net=NetTake[NetModel["EfficientNet Trained on ImageNet"],{1,-3}]
Out[]=
NetChain
Inputport:
image
Outputport:
vector(size: 1280)


Customizing neural network

After the last 2 layers of the model EfficientNet are removed, we construct a customized neural network by adding new layers. This allows the model to learn new features form our dataset.
In[]:=
newNet=NetChain[<|"pretrainedNet"->net,"linear1"->LinearLayer[64],"dp"->DropoutLayer[0.2],"bn"->BatchNormalizationLayer[],"linear2"->LinearLayer[7],"softmax"->SoftmaxLayer[]|>,"Output"->NetDecoder[{"Class",classes}]]
Out[]=
NetChain
uniniti
aliz
ed
Inputport:
image
Outputport:
class

The layers contribute as follows:
◼
  • LinearLayer: Adds complexity to the neural network.
  • ◼
  • DropoutLayer: Prevents overfitting by randomly putting off the neurons while training.
  • ◼
  • BatchNormalizationLayer: Normalizes its input data by learning the data mean and variance.
  • ◼
  • SoftMaxLayer: Contributes the activation function layer for multiclass classification.
  • Handling data unbalance using different methodologies

    It is evident from the graphs that the emotion class ‘disgust’ has a significantly less amount of data compared to the other classes. Most machine learning algorithms are based on the assumption that data is equally distributed among all classes in the data set and hence, when training the learning develops a bias towards the majority classes. We will look at a few different ways in which we can resolve this issue.

    Undersampling

    In the Undersampling method, we remove excess number of samples from the majority classes so all classes end up with about the same amount of sample data. Here, the class ‘disgust’ only has 547 samples. By taking 500 samples from each class for our sample data, each of our classes end up with the same amount of data.

    Training the net

    The model trains with a BatchSize 24 and 2 training rounds.

    Net evaluation

    To compare how our different methods work, we shall compute the confusion matrices, accuracies, and F1 scores of each.
    1
    .
    Confusion matrix:
    2
    .
    F1 score:
    3
    .
    Accuracy:

    Weighted Class Training

    Customizing neural network

    Training the net

    Net Evaluation

    1
    .
    Confusion matrix:
    2
    .
    F1 score:
    3
    .
    Accuracy:

    Focal Loss Training

    Training the net

    Net Evaluation

    1
    .
    Confusion matrix:
    2
    .
    F1 score:
    3
    .
    Accuracy:

    Concluding remarks

    By comparing the results from the three methods we used to address the data imbalance in the dataset, the accuracies obtained are as follow: Undersampling gives us 0.494286 accuracy, using FocalLoss gives us 0.558316 and weighted sampling, 0.498982. We can see that using FocalLoss gave us the highest accuracy and F1 scores. The weighted class model performed the next best. The accuracies could be improved in the future with more training rounds and network layers.

    Keywords

    ◼
  • Undersampling
  • ◼
  • Weighted sampling
  • ◼
  • Focal Loss
  • Acknowledgment

    There are many people I would like to thank for their support. I would first like to thank Siria Sadeddin for being my mentor, her immense help and guidance allowed me to learn and use many new skills which I could use to complete this project. I would also like to express my sincere gratitude to Tuseeta Banerjee and Mads Bahrami for their time and consideration, the TAs for being available whenever I was in trouble, and Aravind Hanasoge and the entire Wolfram team for conducting this program.

    References

    ◼
  • Sadeddin, Siria. “Face mask detection: classifying image data.” Wolfram Community. 2021. https://community.wolfram.com/groups/-/m/t/2139499.
  • ◼
  • Sadeddin, Siria. “Loss Focal: Una solución para el desbalance de datos.” AI en Español. June 12, 2020.
    ​https://siriasadeddin.wixsite.com/siriaai/post/loss-focal-una-soluci % C3 % B3n-para-el-desbalance-de-datos.
  • ◼
  • Chandler, Seth. “Machine learning with weighted data.” Wolfram Community. 2018. https://community.wolfram.com/groups/-/m/t/1223968.
  • ◼
  • Shrivastava, Ishan. “Handling Class Imbalance by Introducing Sample Weighting in the Loss Function.” GumGum Tech Blog. December 17, 2020. https://medium.com/gumgum-tech/handling-class-imbalance-by-introducing-sample-weighting-in-the-loss-function-3bdebd8203b4.
  • ◼
  • Lin, Tsung-Yi., Goyal, Priya., Girshick, Ross., He, Kaiming., Dollár, Piotr. “Focal Loss for Dense Object Detection.” arXiv. February 7, 2018. https://arxiv.org/pdf/1708.02002.pdf.
  • ◼
  • Saxena, Shipra. “Introduction to Softmax for Neural Network.” Analytics Vidhya. April 5, 2021.
    https://www.analyticsvidhya.com/blog/2021/04/introduction-to-softmax-for-neural-network/.
  • ◼
  • Singh, Kamaldeep. “How to Improve Class Imbalance using Class Weights in Machine Learning.” Analytics Vidhya, October 6, 2020. https://www.analyticsvidhya.com/blog/2020/10/improve-class-imbalance-class-weights/.
  • ◼
  • Godoy, Daniel. “Understanding binary cross-entropy/log loss: a visual explanation.” November 21, 2018.
    ​https://towardsdatascience.com/understanding-binary-cross-entropy-log-loss-a-visual-explanation-a3ac6025181a.
  • ◼
  • Hoeltgen, Laurent. “Designing Neural Networks in Mathematica.” Laurent Hoeltgen. May 5, 2015. https://laurenthoeltgen.name/post/ml-nn-mathematica/
  • ◼
  • Singh, Gaganjot. “Facial Emotion Classification using Deep Learning.” December 18, 2019.
    ​https://medium.com/analytics-vidhya/facial-emotion-classification-using-deep-learning-d08dd02a2d38.
  • ◼
  • Chowdhry, Arsh. “Emotion Recognition With Deep Learning On Google Colab.” April 5, 2021.
    ​https://blog.clairvoyantsoft.com/emotion-recognition-with-deep-learning-on-google-colab-24ceb015e5.