Utilizando TransferLearning para detectar o correto uso de máscaras

Este artigo contém a implementação das técinicas de feature extraction e fine tuning utilizando o Tensorflow.

1. Introdução

A intuição por trás do aprendizado de transferência para classificação de imagens é que se um modelo for treinado em um conjunto de dados grande e geral o suficiente, esse modelo servirá efetivamente como um modelo genérico do mundo visual. Você pode então tirar proveito desses mapas de recursos aprendidos sem ter que começar do zero, treinando um grande modelo em um grande conjunto de dados.
https://www.tensorflow.org/tutorials/images/transfer_learning

Esta técnica pode ser utilizada para usufruir do conhecimento e de informações aprendidas por modelos conhecidos e treinados em milhões de dados. Estes dados não precisam fazer parte do mesmo problema que estamos resolvendo. No exemplo a seguir, vamos classificar o uso de máscaras através da estrutura de uma rede(ResNet) treinada para classificar animais e que utilizou como base de dados o ImageNet.

2. Base de dados

  • with_mask
  • without_mask
  • wearing_mask_incorrectly

A base foi obtida no Kaggle através do seguinte link: https://www.kaggle.com/vijaykumar1799/face-mask-detection.

3. Construção dos modelos

3.1 Feature Extraction

Primeriamente precisamos importar um modelo pré-treinado. Utilizaremos a arquitetura VGG16 com o dataset ImageNet:

from tensorflow.keras.applications import VGG16
model = VGG16(weights="imagenet", include_top=False)

O parametro include_top=False é importante pois ele remove as camadas de classificação da VGG16 mantendo somente as camadas responsáveis pela extração de características.

Com o modelo carregado podemos realizar as extrações. Para isso, basta passar as imagens para o modelo.

features = model.predict(batchImages, batch_size=bs)# redimensiona o output para que tenha apenas 1 dimensão
features = features.reshape((features.shape[0], 512 * 7 * 7))

Por fim, basta treinar um classificador com as features geradas:

from sklearn.neural_network  import MLPClassifieri = int(labels.shape[0] * 0.75)model = MLPClassifier(solver="adam",a lpha=1e-5,hidden_layer_sizes=(250, 100, ))model.fit(features[:i], labels[:i])

Como resultado obtivemos 99% de acurácia com apenas alguns passos simples:

3.2 Fine Tuning

Para este exemplo vamos utilizar o modelo ResNet50 treinado na base imagenet.

from tensorflow.keras.applications import ResNet50# mais uma vez passamos include_top=False
baseModel = ResNet50(weights="imagenet", include_top=False,input_tensor=Input(shape=(224, 224, 3)))

Agora precisamos modificar o modelo importado adicionando as camadas de classificação no topo:

# import the necessary packages
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
# a fully connect network
class FCHeadNet:
@staticmethod
def build(baseModel, classes, D):

# initialize the head model that will be placed on top of
# the base, then add a FC layer
headModel = baseModel.output
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(D, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)

# add a softmax layer
headModel = Dense(classes, activation="softmax")(headModel)
return headModel

Criando o modelo final:

from tensorflow.keras.models import ModelheadModel = FCHeadNet.build(baseModel, num_classes, 256)model = Model(inputs=baseModel.input, outputs=headModel)

Antes de iniciar o treino precisamos congelar algumas camadas do modelo base

# congela todas a camadas
for layer in baseModel.layers:
layer.trainable = False
# descongelar apenas algumas camadas
for layer in baseModel.layers[165:]:
if (layer.__class__.__name__ != 'BatchNormalization'):
layer.trainable = True

Segundo a documentação do prórpio TensorFlow é recomendado não descongelar as camadas de BatchNormalization:

Quando você descongelar um modelo que contém camadas BatchNormalization, a fim de fazer o ajuste fino, você deve manter as camadas BatchNormalization no modo de inferência passando training = False ao chamar o modelo base. Caso contrário, as atualizações aplicadas aos pesos não treináveis ​​destruirão o que o modelo aprendeu.

Por fim, basta compitar o modelo e configurar o treino:

from tensorflow.keras.optimizers import SGDopt = SGD(learning_rate=0.001)model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])history = model.fit(features, labels, steps_per_epoch=44, validation_data=(val_features, val_labels), validation_steps=44, epochs=5, max_queue_size=10, verbose=1)

Como resultado obtivemos um modelo com 98% de acurácia

4. Conclusões

Os códigos acima apresentam apenas os passos relacionados ao carregamento e à manipulação dos modelos. No entando, existem alguns passos importantes que foram omitidos. Estes passos são relacionados ao carregamento e à conversão das imagens para hdf5 e à utilização de processos de data augmentation.

Os códigos completos estão dispostos no seguinte repositório:

5. Referências