<jupyter_start><jupyter_text>COVID-19: Face Mask Recognition  Submitted by: <NAME> 961152147 <NAME> 318471208  Link to the github: https://github.com/Stayermax/Face_Mask_Recognition<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math
from  copy import deepcopy
from collections import OrderedDict
import os

import matplotlib.image as mpimg
import pickle<jupyter_output><empty_output><jupyter_text>Exploratory Data Analysis  Visualization<jupyter_code>train_files = os.listdir('train/')
test_files = os.listdir('test/')

print(f"Train-set Size: {len(train_files)}")
print(f"Test-set Size: {len(test_files)}")<jupyter_output>Train-set Size: 18259
Test-set Size: 6086<jupyter_text>Sample from the train data:<jupyter_code>images_num = 16
fig, axs = plt.subplots(4, 4)
for i in range(images_num):
    image = mpimg.imread(f"train/{train_files[i]}")
    axs[int(i/4), i%4].imshow(image)
    plt.xlabel(f"{train_files[i]}")
    axs[int(i / 4), i % 4].title.set_text(f"{train_files[i]}")
    axs[int(i / 4), i % 4].axes.get_xaxis().set_visible(False)
    axs[int(i / 4), i % 4].axes.get_yaxis().set_visible(False)
plt.subplots_adjust(left=None, bottom=None, right=None, top=1.5, wspace=None, hspace=None)
plt.show()<jupyter_output><empty_output><jupyter_text>Sample from the test data:<jupyter_code>images_num = 16
fig, axs = plt.subplots(4, 4)
for i in range(images_num):
    image = mpimg.imread(f"test/{test_files[i]}")
    axs[int(i/4), i%4].imshow(image)
    plt.xlabel(f"{train_files[i]}")
    axs[int(i / 4), i % 4].title.set_text(f"{train_files[i]}")
    axs[int(i / 4), i % 4].axes.get_xaxis().set_visible(False)
    axs[int(i / 4), i % 4].axes.get_yaxis().set_visible(False)
plt.subplots_adjust(left=None, bottom=None, right=None, top=1.5, wspace=None, hspace=None)
plt.show()<jupyter_output><empty_output><jupyter_text>Insights We can compare a number of masked and unmasked people in the dataset.<jupyter_code>train_masked_num = 0
train_unmasked_num = 0
for image_name in train_files:
    if("_1." in image_name):
        train_masked_num +=1
    elif("_0." in image_name):
        train_unmasked_num +=1
    else:
        image = mpimg.imread(f"train/{image_name}")
        plt.imshow(image)
plt.show()

print(f"The number of people that wear the mask properly in the train dataset is: {train_masked_num}")
print(f"The number of people that wear the mask improperly in the train dataset is: {train_unmasked_num}")
height = [train_masked_num, train_unmasked_num]
bars = ('Masked', 'Unmasked')
y_pos = np.arange(len(bars))
plt.bar(y_pos, height)
plt.xticks(y_pos, bars)
plt.ylabel("No. of pictures") 
plt.title("Train data") 
plt.show()
test_masked_num = 0
test_unmasked_num = 0
for image_name in test_files:
    if("_1.jpg" in image_name):
        test_masked_num +=1
    elif("_0.jpg" in image_name):
        test_unmasked_num +=1
    else:
        image = mpimg.imread(f"train/{image_name}")
        plt.imshow(image)
plt.show()
    
print(f"The number of people that wear the mask properly in the test dataset is: {test_masked_num}")
print(f"The number of people that wear the mask improperly in the test dataset is: {test_unmasked_num}")
height = [test_masked_num, test_unmasked_num]
bars = ('Masked', 'Unmasked')
y_pos = np.arange(len(bars))
plt.bar(y_pos, height)
plt.xticks(y_pos, bars)
plt.ylabel("No. of pictures") 
plt.title("Test data") 
plt.show()<jupyter_output><empty_output><jupyter_text>We can see that the size of the classes in both datasets is relatively equal as well as proportioned between the classes. Hence we can assume that the train dataset can be a representative sample of the population.  Experiments  Model 1: CNN modelTo define our model, we subclass the LightningModule of PyTorch Lightning. The model consists of 4 convolution layers followed by 2 linear layers. We used ReLU as the activation function, and the MaxPool2d as the pooling layer. We then initialize the weights of these layers with xavier_uniform as this makes the network train better.   Model architecture<jupyter_code>from report_copy import print_summary
print_summary()<jupyter_output>/home/vitaly/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint8 = np.dtype([("qint8", np.int8, 1)])
/home/vitaly/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_quint8 = np.dtype([("quint8", np.uint8, 1)])
/home/vitaly/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint16 = np.dtype([("qint16", np.int16, 1)])
/home/vitaly/.local/lib/python3.6/site-packages/tensorboard/compat/ten[...]<jupyter_text>Parameters number: 2,193,474  Data preprocessing classFor the first model we transformed all the images into 100 by 100 pixels squared images.<jupyter_code>import cv2
from torch import long, tensor
from torch.utils.data.dataset import Dataset
from torchvision.transforms import Compose, Resize, ToPILImage, ToTensor

class MaskDataset(Dataset):
    """ Masked faces dataset
        0 = 'not correct mask wearing'
        1 = 'correct mask wearing'
    """

    def __init__(self, dataFrame):
        self.dataFrame = dataFrame

        self.transformations = Compose([
            ToPILImage(),
            Resize((100, 100)),
            ToTensor(),  # [0, 1]
        ])

    def __getitem__(self, key):
        if isinstance(key, slice):
            raise NotImplementedError('slicing is not supported')

        row = self.dataFrame.iloc[key]
        return {
            'name': row['image'],
            'image': self.transformations(cv2.imread(row['image'])),
            'mask': tensor([row['mask']], dtype=long),  
        }

    def __len__(self):
        return len(self.dataFrame.index)<jupyter_output><empty_output><jupyter_text>Loss FuntionWe used Cross Entropy function from pytorch library. OptimizerWe tried a few options (for example, SGD from torch.optim), but eventually ended up using the Adam optimizer from the pytorch library. We also tried several learning rates and settled on 0.00001 which yielded the best results. RegularizationWe tried using the batch normalization only to discover we obtained better results without applying it, thus we opted not to use regularization.  Graphs for the first model:<jupyter_code># Training and testing results were saved into csv files by epochs.
def results_graphs():
    train_df = pd.read_csv('graph_data/train_results.csv')
    test_df = pd.read_csv('graph_data/test_results.csv')
    # LOSS:
    sns.set_style("darkgrid", {"axes.facecolor": ".9"})
    train_loss = sns.lineplot(x=range(len(train_df)), y='loss', data=train_df, label="Train")
    test_loss = sns.lineplot(x=range(len(test_df)), y='loss', data=test_df, label="Test")
    plt.show()
    # AUC:
    train_auc = sns.lineplot(x=range(len(train_df)), y='ROC_AUC', data=train_df, label="Train")
    test_auc = sns.lineplot(x=range(len(test_df)), y='ROC_AUC', data=test_df, label="Test")
    plt.show()
    # F1-score:
    train_auc = sns.lineplot(x=range(len(train_df)), y='f1_score', data=train_df, label="Train")
    test_auc = sns.lineplot(x=range(len(test_df)), y='f1_score', data=test_df, label="Test")
    plt.show()
results_graphs()<jupyter_output><empty_output><jupyter_text>Model 1 results: Best F1-score acheived for the first model is 95.80 on the test set.  Model 2: mobilenet_v2 We used default model from pytorch library, which shows good results on such tasks as image processing.This model is well know and described. Full model description can be found via the link (https://arxiv.org/pdf/1801.04381v4.pdf)  Model architecture<jupyter_code>from report_copy import print_summary2
print_summary2()<jupyter_output># ================================================================
            Conv2d-1         [-1, 32, 112, 112]             864
       BatchNorm2d-2         [-1, 32, 112, 112]              64
             ReLU6-3         [-1, 32, 112, 112]               0
            Conv2d-4         [-1, 32, 112, 112]             288
       BatchNorm2d-5         [-1, 32, 112, 112]              64
             ReLU6-6         [-1, 32, 112, 112]               0
            Conv2d-7         [-1, 16, 112, 112]             512
       BatchNorm2d-8         [-1, 16, 112, 112]              32
  InvertedResidual-9         [-1, 16, 112, 112]               0
           Conv2d-10         [-1, 96, 112, 112]           1,536
      BatchNorm2d-11         [-1, 96, 112, 112]             192
            ReLU6-12         [-1, 96, 112, 112]               0
           Conv2d-13           [-1, 96, 56, 56]             864
      BatchNorm2d-14           [-1, 96, 56, 56]             192
            ReLU6-15           [-1, 9[...]<jupyter_text>Parameters number: 2,226,434  Data preprocessing We decided to work with bigger image sizes in the second model. To do so, we transformed every image into a 224x224 pixels squared image. We didn't create a separate preprocessing class for the second model, since we used the ImageFolder function from torchvision.datasets library and sorted negative and postitive training objects into two different folders.  Loss FuntionWe used the negative log likelihood loss. function from pytorch library. OptimizerWe used Adam optimizer from pytorch library. We also tried several learning rates and settled on 0.003 which yielded the best results. RegularizationWe tried using the batch normalization for the seconf model as well and again, obtained better results without applying it, thus we opted not to use regularization.  Graphs for the second model:<jupyter_code>def results_graphs_m2():
    train_df = pd.read_csv('graph_data_m2/train_results.csv')
    test_df = pd.read_csv('graph_data_m2/test_results.csv')
    # LOSS:
    sns.set_style("darkgrid", {"axes.facecolor": ".9"})
    train_loss = sns.lineplot(x=range(len(train_df)), y='loss', data=train_df, label="Train")
    test_loss = sns.lineplot(x=range(len(test_df)), y='loss', data=test_df, label="Test")
    plt.show()
    # AUC:
    train_auc = sns.lineplot(x=range(len(train_df)), y='ROC_AUC', data=train_df, label="Train")
    test_auc = sns.lineplot(x=range(len(test_df)), y='ROC_AUC', data=test_df, label="Test")
    plt.show()
    # F1-score:
    train_auc = sns.lineplot(x=range(len(train_df)), y='f1_score', data=train_df, label="Train")
    test_auc = sns.lineplot(x=range(len(test_df)), y='f1_score', data=test_df, label="Test")
    plt.show()
results_graphs_m2()<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup