Aula 15 – Scikit-Learn – Reconhecimento facial – Código
Aula 15 – Scikit-Learn – Reconhecimento facial – Código
Voltar para página principal do blog
Todas as aulas desse curso
Aula 14 Aula 16
Script dessa aula:
Download do script da aula
Documentação oficial do Sklearn:
https://scikit-learn.org/stable/
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Essa aula é baseada no trabalho apresentado no:
Labeled Faces in the Wild: A Database for Studying Face Recognition in Unconstrained Environments Gary B. Huang,Manu Ramesh, Tamara Berg, and Erik Learned-Miller
Para o download da base LFW é só clicar nesse link abaixo:
https://scikit-learn.org/stable/auto_examples/applications/plot_face_recognition.html
Ou da fonte original
http://vis-www.cs.umass.edu/lfw/
Código completo
Esse código é praticamente o mesmo do scikit, as mudanças foram:
Os comentários mais detalhados e em português
Foi adicionado um docstring
Nos prints foi utilizada a formatação mais atual do python 3, o novo mecanismo de formatação de sequência de caracteres conhecido como Literal String Interpolation ou mais comumente como sequências de caracteres F (devido ao caractere f que precede a string). A ideia por trás das strings f é simplificar a interpolação de strings.
"""
================================
Faces recognition example using eigenfaces and SVMs
================================
An example showing how the scikit-learn can be used to faces recognition with eigenfaces and SVMs
================================
================================
================================
Exemplo de reconhecimento de faces usando autofaces e SVMs
================================
Exemplo mostrando como o scikit-learn pode ser usado para reconhecimento de faces com autofaces e SVMs
"""
from time import time
import logging
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC
print(__doc__)
# O logging exibe o progresso da execução no stdout
# adicionando as informações de data e hora
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
# #############################################################################
# Download dos dados, se ainda não estiver em disco e carregue-a como uma matriz numpy
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
# Inspeciona as matrizes de imagens para encontrar os formatos das imagens( para plotagem )
n_samples, h, w = lfw_people.images.shape
# para aprendizado de máquina, usamos 2 dados diretamente( esse modelo ignora
# informações relativas a posição do pixel )
X = lfw_people.data
n_features = X.shape[1]
# A rótulo( label ) a prever é o ID da pessoa
y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]
print("Total dataset size:")
print(f"n_samples: {n_samples}")
print(f"n_features: {n_features}")
print(f"n_classes: {n_classes}")
# #############################################################################
# Divide a base em um conjunto de treinamento e um conjunto de teste usando k fold
# 25% da base para o conjunto de teste os 75% restantes para o treino
# random_state é para inicializar o gerador interno de números aleatórios
# Definir random_state com um valor fixo garantirá que a mesma sequência de números
# aleatórios seja gerada cada vez que você executar o código
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42)
# #############################################################################
# Computa o principal component analysis - PCA (eigenfaces) na base de faces
# ( tratado como dataset não rotulado ): extração não supervisionada / redução de dimensionalidade
n_components = 150
print(f"Extracting the top {n_components} eigenfaces from {X_train.shape[0]} faces")
# t0 guarda o tempo zero, para cálculo do tempo de execução do PCA
# O cálculo é feito no time() - t0 do print da linha 81
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized',
whiten=True).fit(X_train)
print("done in {0:.3f}s".format(time() - t0))
eigenfaces = pca.components_.reshape((n_components, h, w))
print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in {0:.3f}s".format(time() - t0))
# #############################################################################
# Treinando um modelo de classificação SVM
print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
clf = clf.fit(X_train_pca, y_train)
print("done in {0:.3f}s".format(time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)
# #############################################################################
# Avaliação quantitativa da qualidade do modelo sobre o conjunto de testes
print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in {0:.3f}s".format(time() - t0))
print(classification_report(y_test, y_pred, target_names=target_names))
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))
# #############################################################################
# Avaliação qualitativa das previsões usando matplotlib
def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())
# Plota o resultado da previsão em uma parte do conjunto de testes
def title(y_pred, y_test, target_names, i):
pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
return f'predicted: {pred_name}\ntrue: {true_name}'
prediction_titles = [title(y_pred, y_test, target_names, i)
for i in range(y_pred.shape[0])]
plot_gallery(X_test, prediction_titles, h, w)
# plota a galeria das autofaces mais significativas
eigenface_titles = [f"eigenface {i}" for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
Visão geral do código.
Qualquer função, classe ou módulo que comece com uma string literal tem um __doc__ não vazio.
Ela é a string de documentação da função, classe ou módulo.
Se estiver vazia será definido como None.
Ao fazer o download do exemplo de um script Scikit, em geral, você verá que ele começa com uma string do tipo:
"""
================================
Faces recognition example using eigenfaces and SVMs
================================
An example showing how the scikit-learn can be used to faces recognition with eigenfaces and SVM
================================
================================
Exemplo de reconhecimento de faces usando autofaces e SVMs
================================
Exemplo mostrando como o scikit-learn pode ser usado para reconhecimento de faces com autofaces e SVMs
"""
O print (__ doc__) simplesmente reutiliza essa string de documentação para mostrar no seu terminal, toda vez que você executar o script.
Logging
O Logging é uma ferramenta muito útil.
Ele ajuda a desenvolver uma melhor compreensão do fluxo de um programa e descobrir cenários nos quais você nem imaginou durante o desenvolvimento.
Os logs fornecem aos desenvolvedores um conjunto extra de olhos que estão constantemente observando o fluxo pelo qual um aplicativo passa.
Podem armazenar informações, como qual usuário ou IP acessou o aplicativo.
Se ocorrer um erro, pode fornecer mais informações do que um rastreamento de pilha, informando qual era o estado do programa antes de chegar à linha de código em que ocorreu o erro.
Enfim, essencial.
A linha logging.basicConfig(level=logging.INFO, format=’%(asctime)s %(message)s’) exibe o progresso da execução em logs no stdout.
Carga dos dados
Quando os dados são carregados, em lfw_people ele só pega pessoas que tem mais de 69 imagens diferentes (min_faces_per_person) na base, e com o resize é informada a proporção de 0.4 usada para redimensionar a imagem de cada rosto.
Depois com lfw_people.images.shape pegamos a largura(w), altura(h) e quantidade de samples(n_samples).
Com: X = lfw_people.data a parte dos dados é atribuído ao X.
Em n_features = X.shape[1] pegamos o número de características de cada imagem, que será reduzida logo mais na frente, no PCA.
No y = lfw_people.target a parte target, ou seja, as classificações, são atribuidas a y.
Já em target_names = lfw_people.target_names pegamos as pessoas mais representadas no LFW.
Resultados esperados para as 7 pessoas mais representadas no conjunto de dados:
[‘Ariel Sharon’, ‘Colin Powell’, ‘Donald Rumsfeld’, ‘George W Bush’,’Gerhard Schroeder’, ‘Hugo Chavez’, ‘Tony Blair’]
Divisão da base para treino e teste
A base é dividida em um conjunto de treinamento e um conjunto de teste usando k fold.
25% da base para o conjunto de teste os 75% restantes para o treino.
O random_state é para inicializar o gerador interno de números aleatórios.
Definir random_state com um valor fixo garantirá que a mesma sequência de números aleatórios seja gerada cada vez que você executar o código.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
Hiper-parâmetros são parâmetros que não são aprendidos diretamente nos estimadores.
No scikit-learn, eles são passados como argumentos para o construtor das classes dos estimadores.
Exemplos típicos incluem C, kernel e gama para o Support Vector Classifier, alfa para Lasso, etc.
É possível e recomendado procurar no espaço de hiper-parâmetros a melhor pontuação da validação cruzada.
Qualquer parâmetro fornecido ao construir um estimador pode ser otimizado dessa forma.
Especificamente, para encontrar os nomes e os valores atuais de todos os parâmetros para um determinado estimador, use:
estimator.get_params()
Redução de dimensionalidade
Computa o principal component analysis – PCA (eigenfaces) na base de faces, tratado como dataset não rotulado, a extração é não supervisionada nessa redução de dimensionalidade
A redução de dimensionalidade linear usa a Decomposição de Valor Singular dos dados para projetá-los em um espaço dimensional inferior.
Os dados de entrada são centralizados, mas não redimensionados para cada feature antes de aplicar o SVD (Singular Value Decomposition).
Ele usa a implementação LAPACK (LAPACK Linear Algebra PACKage) do SVD completo ou de um SVD truncado randomizado pelo método de Halko et al. 2009, dependendo da forma dos dados de entrada e do número de componentes a serem extraídos.
Cálculo de tempo
Em cada etapa, na redução de dimensionalidade, na fase de treinamento, etc. é utilizado o módulo time para calcular o tempo gasto nessas etapas.
#Tempo inicial
t0 = time()
...
processo que se quer medir o tempo
...
#imprime o tempo gasto
print("done in {0:.3f}s".format(time() - t0))
O processo de redução de dimensionalidade PCA, tenta ao mesmo tempo, preservar a maior parte da variação nas imagens.
A classe PCA usada com o parâmetro opcional svd_solver=’randomized’ é muito útil nesse caso: como vamos eliminar a maioria dos vetores singulares, é muito mais eficiente limitar o cálculo a uma estimativa aproximada dos vetores singulares que manteremos para realmente executar a transformação.
Whitening é uma importante etapa de pré-processamento para muitos algoritmos.
Ele remove ainda mais a correlação linear entre os recursos com ‘whiten = True‘.
O whiten = True escala os componentes principais pelos valores próprios equivalentes, de modo que as variações tenham a mesma unidade.
Às vezes, isso é usado na análise de imagens para aprimorar as bordas de uma imagem em relação a outros recursos.
Em termos de distância euclidiana, esperamos que o clareamento(whitening) torne as imagens da mesma classe e, portanto, compartilhe um conjunto de arestas semelhantes mais próximas umas das outras, devido ao fato de ignorar algumas diferenças como brilho por exemplo.
A linha: eigenfaces = pca.components_.reshape((n_components, h, w)), projeta os dados de entrada na base ortonormal de autofaces.
As linhas:
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in {0:.3f}s".format(time() - t0))
Atribui a X_train_pca a base de treino já com as dimensões reduzidas pelo processo do PCA do passo anterior.
A mesma coisa para a base de teste e o print em seguida, mostra o tempo gasto nesse processo.