
A rede neural siamesa é um dos algoritmos de aprendizado único mais simples e mais populares. Métodos em que para cada aula é realizado apenas um estudo de caso. Assim, a rede siamesa é geralmente usada em aplicativos onde não há muitas unidades de dados em cada classe.
Suponha que precisamos criar um modelo de reconhecimento facial para uma organização que emprega cerca de 500 pessoas. Se você criar um modelo desse tipo com base na rede neural convolucional (CNN), para treiná-lo e obter uma boa precisão de reconhecimento, precisaremos de muitas imagens de cada uma dessas 500 pessoas. Mas é óbvio que não podemos compilar esse conjunto de dados, portanto, você não deve criar um modelo baseado na CNN ou em qualquer outro algoritmo de
aprendizado profundo se não tivermos dados suficientes. Nesses casos, você pode usar o algoritmo complexo de aprendizado único, como a rede siamesa, que pode ser treinada com menos dados.
De fato, as redes siamesas consistem em duas redes neurais simétricas, com os mesmos pesos e arquitetura, que no final combinam e usam a função de energia - E.
Vejamos a rede siamesa, criando um modelo de reconhecimento de rosto baseado nela. Vamos ensiná-la a determinar quando duas faces são iguais e quando não são. E, para começar, usaremos o conjunto de dados AT&T Database of Faces, que pode ser baixado do site do
laboratório de computação da Universidade de Cambridge .
Baixe, descompacte e veja as pastas de s1 a s40:

Cada pasta contém 10 fotografias diferentes de uma única pessoa, tiradas de diferentes ângulos. Aqui está o conteúdo da pasta s1:

E aqui está o que está na pasta s13:

As redes siamesas precisam inserir valores emparelhados com marcações, então vamos criar esses conjuntos. Tire duas fotos aleatórias da mesma pasta e marque-as como um par “genuíno”. Depois, tiramos duas fotos de pastas diferentes e as marcamos como um par "falso" (imposição):

Depois de distribuir todas as fotos em pares marcados, estudaremos a rede. De cada par, transferiremos uma foto para a rede A e a segunda para a rede B. Ambas as redes extraem apenas vetores de propriedades. Para isso, usamos duas camadas convolucionais com a ativação da unidade linear retificada (ReLU). Tendo estudado as propriedades, transferimos os vetores gerados pelas duas redes para uma função energética que estima a similaridade. Usamos a distância euclidiana como uma função.
Agora considere todas essas etapas com mais detalhes.
Primeiro, importe as bibliotecas necessárias:
import re import numpy as np from PIL import Image from sklearn.model_selection import train_test_split from keras import backend as K from keras.layers import Activation from keras.layers import Input, Lambda, Dense, Dropout, Convolution2D, MaxPooling2D, Flatten from keras.models import Sequential, Model from keras.optimizers import RMSprop
Agora, definimos uma função para ler imagens de entrada. A função
read_image
tira uma foto e retorna uma matriz NumPy:
def read_image(filename, byteorder='>'):
Por exemplo, abra esta foto:
Image.open("data/orl_faces/s1/1.pgm")

Passamos para a função
read_image
e obtemos uma matriz NumPy:
img = read_image('data/orl_faces/s1/1.pgm') img.shape (112, 92)
Agora, definimos a função
get_data
que irá gerar os dados. Deixe-me lembrá-lo de que as redes siamesas precisam enviar pares de dados (genuínos e imponentes) com marcação binária.
Primeiro, leia as imagens (
img1
,
img2
) em um diretório, salve-as na matriz
x_genuine_pair,
defina
y_genuine
como
1
. Em seguida, lemos as imagens (
img1
,
img2
) de diretórios diferentes, salve-as no par
x_imposite,
e defina
y_imposite
como
0
.
Concatene
x_genuine_pair
e
x_imposite
em
X
e
y_genuine
e
y_imposite
em
Y
:
size = 2 total_sample_size = 10000 def get_data(size, total_sample_size):
Agora vamos gerar os dados e verificar seu tamanho. Temos 20.000 fotos, das quais 10.000 pares genuínos e 10.000 falsos foram coletados:
X, Y = get_data(size, total_sample_size) X.shape (20000, 2, 1, 56, 46) Y.shape (20000, 1)
Compartilharemos toda a gama de informações: 75% dos pares serão treinados e 25% - para testes:
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=.25)
Agora crie uma rede siamesa. Primeiro, definimos a rede principal - será uma rede neural convolucional para extrair propriedades. Crie duas camadas convolucionais usando ativações ReLU e uma camada com pool máximo após uma camada plana:
def build_base_network(input_shape): seq = Sequential() nb_filter = [6, 12] kernel_size = 3
Em seguida, transferiremos um par de imagens da rede principal, que retornará representações vetoriais, ou seja, vetores de propriedades:
input_dim = x_train.shape[2:] img_a = Input(shape=input_dim) img_b = Input(shape=input_dim) base_network = build_base_network(input_dim) feat_vecs_a = base_network(img_a) feat_vecs_b = base_network(img_b)
feat_vecs_a
e
feat_vecs_b
são vetores de propriedades de um par de imagens. Vamos passar suas funções de energia para calcular a distância entre eles. E em função da energia, usamos a distância euclidiana:
def euclidean_distance(vects): x, y = vects return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True)) def eucl_dist_output_shape(shapes): shape1, shape2 = shapes return (shape1[0], 1) distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([feat_vecs_a, feat_vecs_b])
Definimos o número de épocas como 13, aplicamos a propriedade RMS para otimização e declaramos o modelo:
epochs = 13 rms = RMSprop() model = Model(input=[input_a, input_b], output=distance)
Agora, definimos a função de perda
contrastive_loss
e compilamos o modelo:
def contrastive_loss(y_true, y_pred): margin = 1 return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0))) model.compile(loss=contrastive_loss, optimizer=rms)
Vamos estudar o modelo:
img_1 = x_train[:, 0] img_2 = x_train[:, 1] model.fit([img_1, img_2], y_train, validation_split=.25, batch_size=128, verbose=2, nb_epoch=epochs)
Você vê como as perdas diminuem à medida que as eras passam:
Train on 11250 samples, validate on 3750 samples Epoch 1/13 - 60s - loss: 0.2179 - val_loss: 0.2156 Epoch 2/13 - 53s - loss: 0.1520 - val_loss: 0.2102 Epoch 3/13 - 53s - loss: 0.1190 - val_loss: 0.1545 Epoch 4/13 - 55s - loss: 0.0959 - val_loss: 0.1705 Epoch 5/13 - 52s - loss: 0.0801 - val_loss: 0.1181 Epoch 6/13 - 52s - loss: 0.0684 - val_loss: 0.0821 Epoch 7/13 - 52s - loss: 0.0591 - val_loss: 0.0762 Epoch 8/13 - 52s - loss: 0.0526 - val_loss: 0.0655 Epoch 9/13 - 52s - loss: 0.0475 - val_loss: 0.0662 Epoch 10/13 - 52s - loss: 0.0444 - val_loss: 0.0469 Epoch 11/13 - 52s - loss: 0.0408 - val_loss: 0.0478 Epoch 12/13 - 52s - loss: 0.0381 - val_loss: 0.0498 Epoch 13/13 - 54s - loss: 0.0356 - val_loss: 0.0363
E agora vamos testar o modelo nos dados de teste:
pred = model.predict([x_test[:, 0], x_test[:, 1]])
Defina uma função para calcular a precisão:
def compute_accuracy(predictions, labels): return labels[predictions.ravel()
Calculamos a precisão:
compute_accuracy(pred, y_test) 0.9779092702169625
Conclusões
Neste guia, aprendemos como criar modelos de reconhecimento de rosto baseados em redes siamesas. A arquitetura de tais redes consiste em duas redes neurais idênticas com o mesmo peso e estrutura, e os resultados de seu trabalho são transferidos para uma função de energia - isso determina a identidade dos dados de entrada. Para obter mais informações sobre meta-aprendizado usando
Python, consulte
Meta-Learning prático com Python.Meu comentário
Atualmente, o conhecimento de redes siamesas é necessário ao trabalhar com imagens. Existem muitas abordagens para o treinamento de redes em pequenas amostras, nova geração de dados, métodos de aumento. Este método permite que relativamente "barato" alcance bons resultados, eis um exemplo mais clássico da rede siamesa no "Hello world" para redes neurais - conjunto de dados MNIST
keras.io/examples/mnist_siamese