rede neural convolucional em tensorflow/keras · a função custo é calculada nos exemplos de...

18
[Início da aula 3] Rede neural convolucional em Tensorflow/Keras [Relembrando] Em PSI3471, na apostila classif-ead, classificamos o banco de imagens MNIST usando algoritmos de aprendizagem clássicos, obtendo 2,5% de erro com “vizinho mais próximo”. Depois, na apostila densakeras-ead, obtivemos 2% de erro usando “rede neural densa”. Nesta apos- tila, usando “rede convolucional profunda”, vamos atingir erro de 0,37%. Vamos começar PSI3472 revendo esta apostila sobre “rede convolucional profunda” com mais detalhes, apesar de a termos visto rapidamente em PSI3471. 1 Introdução O aluno pode ficar com a falsa impressão de que aprendizagem profunda resolve qualquer proble - ma e bastando fornecer os exemplos de treinamento. Isto não é verdade. Para poder dizer se um problema pode ser resolvido usando (a) técnicas convencionais de processamento de imagens, (b) aprendizagem de máquina convencional, (c) aprendizagem profunda e (d) não pode ser resolvido nem usando aprendizagem profunda, é necessário ter conhecimento de cada uma das técnicas. Se um problema pode ser resolvido, por exemplo, usando técnica de processamento de imagens con - vencional, não vale a pena usar a aprendizagem profunda. Pois, a técnica convencional é normal - mente mais fácil de desenvolver e mais rápido para executar. Mesmo quando se chega à conclusão de que aprendizagem profunda é a solução mais adequada, a solução precisa ser projetada cuidado - samente. Nesta aula, vou procurar dar uma visão intuitiva de como funciona a aprendizagem pro - funda, para que o aluno possa dizer quando é apropriado usá-la e quando não é. Nas aulas passadas, usando rede neural densa, chegamos a taxa de erro 2% ao classificar os 10000 dígitos de MNIST. Como diminuir ainda mais o erro? Parece que, usando rede neural densa, não há como obter uma taxa de erro substancialmente menor que 2%. Lembre-se do que fizemos na aula “classif-ead” para detectar faces. Era impossível classificar uma janela em face / não-face usando aprendizagem de máquina convencional. Para resolver este pro - blema, escolhemos um conjunto de filtros lineares e alimentamos o algoritmo de aprendizagem com as saídas desses fitros. A figura 1a mostra duas convoluções (entre muitas) usadas para detectar faces humanas. O primeiro filtro utiliza o fato de que a região dos olhos é mais escura do que a região das bochechas. Esse fil - tro vai dar um pico de correlação na região dos olhos. O segundo filtro utiliza o fato de que a região dos olhos é mais escura do que a região entre os olhos. Este filtro também dará um outro pico de correlação na região dos olhos. Executando muitos filtros diferentes e concatenando as saídas, é possível dizer se numa janela tem (ou não) face humana. Como vocês devem se lembrar, convolução (ou filtro linear) calcula média aritmética ponderada usando janela móvel. A figura 1b mostra a detecção de região clara entre duas regiões escuras. A saída do filtro dá um pico de correlação na região com estas características. 1

Upload: others

Post on 26-Aug-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

[Início da aula 3]

Rede neural convolucional em Tensorflow/Keras

[Relembrando] Em PSI3471, na apostila classif-ead, classificamos o banco de imagens MNISTusando algoritmos de aprendizagem clássicos, obtendo 2,5% de erro com “vizinho mais próximo”.Depois, na apostila densakeras-ead, obtivemos 2% de erro usando “rede neural densa”. Nesta apos-tila, usando “rede convolucional profunda”, vamos atingir erro de 0,37%. Vamos começar PSI3472revendo esta apostila sobre “rede convolucional profunda” com mais detalhes, apesar de a termosvisto rapidamente em PSI3471.

1 Introdução

O aluno pode ficar com a falsa impressão de que aprendizagem profunda resolve qualquer proble-ma e bastando fornecer os exemplos de treinamento. Isto não é verdade. Para poder dizer se umproblema pode ser resolvido usando (a) técnicas convencionais de processamento de imagens, (b)aprendizagem de máquina convencional, (c) aprendizagem profunda e (d) não pode ser resolvidonem usando aprendizagem profunda, é necessário ter conhecimento de cada uma das técnicas. Seum problema pode ser resolvido, por exemplo, usando técnica de processamento de imagens con-vencional, não vale a pena usar a aprendizagem profunda. Pois, a técnica convencional é normal-mente mais fácil de desenvolver e mais rápido para executar. Mesmo quando se chega à conclusãode que aprendizagem profunda é a solução mais adequada, a solução precisa ser projetada cuidado-samente. Nesta aula, vou procurar dar uma visão intuitiva de como funciona a aprendizagem pro-funda, para que o aluno possa dizer quando é apropriado usá-la e quando não é.

Nas aulas passadas, usando rede neural densa, chegamos a taxa de erro 2% ao classificar os 10000dígitos de MNIST. Como diminuir ainda mais o erro? Parece que, usando rede neural densa, não hácomo obter uma taxa de erro substancialmente menor que 2%.

Lembre-se do que fizemos na aula “classif-ead” para detectar faces. Era impossível classificar umajanela em face / não-face usando aprendizagem de máquina convencional. Para resolver este pro-blema, escolhemos um conjunto de filtros lineares e alimentamos o algoritmo de aprendizagem comas saídas desses fitros.

A figura 1a mostra duas convoluções (entre muitas) usadas para detectar faces humanas. O primeirofiltro utiliza o fato de que a região dos olhos é mais escura do que a região das bochechas. Esse fil-tro vai dar um pico de correlação na região dos olhos. O segundo filtro utiliza o fato de que a regiãodos olhos é mais escura do que a região entre os olhos. Este filtro também dará um outro pico decorrelação na região dos olhos. Executando muitos filtros diferentes e concatenando as saídas, épossível dizer se numa janela tem (ou não) face humana.

Como vocês devem se lembrar, convolução (ou filtro linear) calcula média aritmética ponderadausando janela móvel. A figura 1b mostra a detecção de região clara entre duas regiões escuras. Asaída do filtro dá um pico de correlação na região com estas características.

1

Page 2: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

Figura 1a: Duas (entre muitas) convoluções necessárias para detectar face.

Figura 1b: Convolução que detecta “região clara entre duas regiões escuras”.

Sabendo que na detecção de faces essencialmente usamos filtros lineares como pré-processamentopara extrair as características, seria possível usar filtros lineares (ou casamentos de modelos ou con-volução) para melhorar a classificação de MNIST? Talvez detectar pontas de retas, linhas verticaise horizontais (como na figura 2) e alimentar a aprendizagem de máquina com as saídas desses fil-tros?

Para identificar dígito “3”, talvez usar convoluções para detectar as pontas de retas, linhas verticaise horizontais (figura 2)? Depois, duas pontas de retas, uma linha vertical e duas linhas horizontaiscaracterizariam a forma “ↄ” (contém) que poderia ser detectada fazendo uma outra convolução.Duas formas “ↄ” caracterizariam o dígito “3” que seria detectada por uma ainda outra convolução.Rede convolucional profunda utiliza esta ideia de fazer convoluções em cascata. É convolucionalporque usa convoluções. É profunda porque existem muitas camadas de convoluções.

2

255

A B

255

255

0

0

0

0

0

0

0 0

0

-1

-1

-1

-1

-1

-1

22

2

21/6 x

255 -127

0

0

0

0

matriz de pesos

Page 3: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

imagem a classificar Pontas voltadas paraesquerda

Linhas verticais Linhas horizontais Duas formas “ↄ” ca-racterizam “3”

Figura 2: Seria possível usar convoluções para melhorar a classificação de MNIST?

A abordagem descrita acima deve funcionar, mas é muito difícil escolher manualmente os filtrosmais adequados. Usando rede neural convolucional (CNN), ela escolhe para nós, automaticamente,os filtros lineares adequados a serem usados para extrair as características [LeCun1989]. Aliás, redeneural convolucional recebe esse nome porque usa convoluções. As primeiras camadas de CNNconsistem de convoluções que extraem automaticamente as características úteis.

[Numa rede neural convencional, todas as camadas são densas (ou “fully connected”). Isto é, todosos neurônios de uma camada estão ligados com todos os neurônios da camada seguinte (figura 3).Rede neural densa trabalha sem levar em consideração a configuração 2D dos pixels dentro de umaimagem. Lembre-se de que, nos programas com rede neural densa da aula passada (densakeras-ead), a primeira camada da rede foi “Flatten”, que converte uma imagem 2D num vetor 1D. Isto é,para rede densa, não interessa a disposição espacial dos pixels. Evidentemente, tem algo de erradocom esta abordagem, pois para reconhecer qualquer dígito interessa a configuração 2D dos pixels.

Intuitivamente, como funciona a nossa visão? Primeiro, detectamos as características primitivas,como cantos, arestas, regiões de cor uniforme, linhas, curvas, etc. Depois, integramos essas caracte-rísticas para detectar formas mais complexas. Depois juntamos essas “formas mais complexas” parareconhecer objetos. Uma CNN consegue captar esta intuição.

Figura 3: Numa rede neural convencional, todos os neurônios de uma camada estão ligados com to-dos os neurônios da cama seguinte. Figura extraída de [Nielsen].]

As primeiras camadas de CNN são filtros lineares. Podemos imaginar que CNN aplica vários “casa-mentos de modelos” na imagem, procurando locais onde aparecem algumas formas simples (pontade reta, linha horizontal, linha vertical, etc). A figura 4 mostra a aplicação de um filtro linear 5x5na imagem 28x28 de um dígito MNIST. Durante o treino, CNN procura os 25 pesos e 1 viés queajudam a classificar a imagem de entrada em dígitos 0, ..., 9. Depois de treinado, os mesmos 25 pe-

3

Page 4: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

sos e 1 viés serão aplicados para todos os pixels, varrendo imagem, como no “template matching” eirá gerar uma imagem de saída. As saídas dos filtros lineares passam por uma função de ativaçãonão-linear, por exemplo, relu ou sigmoide.

Figura 4: CNN possui filtro linear nas primeiras camadas. De [Nielsen].

[Vários filtros lineares diferentes serão projetados automaticamente pelo algoritmo de retro-propa-gação. A figura 5 mostra o projeto e a aplicação de 3 filtros diferentes que produzem 3 imagens desaídas. Assim como a função matchTemplate do OpenCV (ou filtro linear funcionando no modo“valid”), a saída (24x24) é menor do que a entrada (28x28).]

Como CNN consegue projetar os filtros adequados? Ela primeiro inicializa aleatoriamente os pesose os vieses dos filtros. Depois, efetua repetidamente retro-propagação, onde cada peso e cada viés émodificado um pouco de cada vez para que a função custo diminua (diferença entre a saída deseja-da e a obtida). Repare que quem escolhe o número de camadas, a quantidade e os tamanhos dos fil-tros é o programador.

Figura 5: CNN projeta e aplica vários fltros lineares diferentes na imagem de entrada. Extraí-do de [Nielsen].

As saídas dos filtros, depois de passar pela função de ativação, normalmente alimentam camadastipo “pooling” (figura 6). Estas camadas reduzem a dimensionalidade da imagem. Para isso, CNNdivide a imagem em blocos e calcula o máximo (max-pool) ou a média (average-pool) dentro decada bloco. Já vimos que os classificadores funcionam melhor quando o número de características é

4

Page 5: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

pequena. A intuição ao fazer max-pooling é que se (por exemplo) uma ponta de reta do dígito “3”mover um pouco dentro do bloco, a figura vai continuar representando dígito 3.

Figura 6: Max-pooling divide imagem em blocos (por exemplo 2x2) e calcula o maior elemento emcada bloco. Extraído de [Nielsen].

As saídas das camadas de agrupamento (pooling) entram em outros filtros lineares. Esta segundacamada convolucional combina as ativações de vários filtros da primeira camada convolucional,procurando descobrir padrões mais complexos. Por exemplo, na figura 2, a segunda camada pode-ria buscar o conjunto formado por duas pontas de reta, duas linhas horizontais e uma linha vertical,formando o símbolo “contém” (“ↄ”). Duas formas “ↄ” numa disposição espacial correta caracteri-zam um dígito “3”. Isto que escrevo é somente uma explicação intuitiva de como CNN funciona.Na realidade, ela não procura “ↄ” para reconhecer dígito “3”.

As camadas convolucionais e “max-pooling” extraem as características a serem usadas pelo classifi-cador final, tipicamente uma rede neural com camadas densas (“fully-connected” ou “inner-pro-duct”). Essas características poderiam ser utilizadas até por outros tipos de classificadores que já vi-mos, como vizinho mais próximo, árvore de decisão, boosting, etc.

Figura 7: Modelo LeNet para reconhecer dígitos MNIST. Filtros convolucionais são 5x5, aplicadosem passo (stride) 1. Subamostragem (max_pooling) são 2x2, aplicados em passo 2.

5

Extração de características classificação

Page 6: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

2 Classificação de MNIST por CNN

O programa 1 (cnn1.py) classifica os dígitos MNIST usando uma rede neural convolucional em Ke-ras. O modelo de rede, chamado de LeNet, está nas figuras 7 e 8.

Nas linhas 12-21 utilizamos o mesmo código dos programas da aula “classif-ead” para fazer a leitu-ra do MNIST. As linhas 23 e 24 convertem os tensores AX e QX de dimensões (60000, 28, 28) e(10000, 28, 28) em tensores de dimensões (60000, 28, 28, 1) e (10000, 28, 28, 1). Isto é necessáriopois a camada Conv2D espera receber tensores neste formato, com a última dimensão indicandonúmero de bandas de cor. Se a imagem de entrada fosse colorida, a última dimensão teria tamanho3.

A primeira camada convolucional recebe uma image 28×28 e aplica 20 convoluções 5×5, gerando20 imagens 24×24 (linha 27). A camada maxpooling com bloco 2×2 reduz a resolução das 20 ima-gens para 12×12 (linha 28). A segunda camada convolucional recebe 20 imagens 12×12 e aplica 40convoluções 20×5×5, gerando 40 imagens 8×8 (linha 29). As dimensões das imagens são reduzidaspara 4×4 por max-pooling 2×2 (linha 30). Neste ponto, CNN extraiu 40×4×4=640 característicasque julgou serem úteis para classificar os dígitos. Essas características passam por camada “Flatten”que converte o tensor num vetor com 640 elementos. Estas 640 características irão alimentar umarede neural densa com duas camadas com 1000 e 10 neurônios.

As linhas 26-33 especificam o modelo da rede. As linhas 35-36 imprimem o modelo de rede comofigura 8. Linhas 38-41 “compilam” a rede especificada. As linhas 43-46 fazem o treinamento. As li-nhas 49-51 aplicam a rede treinada nos dados de teste. A linha 53 grava a rede resultante num ar-quivo tipo .h5.

6

Page 7: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

123456789

10111213141516171819202122232425262728293031323334353637383940414243444546474849505152

#cnn1.py - grad2020#Testado em TF2 em Colabimport tensorflow.keras as kerasfrom keras.datasets import mnistfrom keras.models import Sequentialfrom keras.layers import Dropout, Conv2D, MaxPooling2D, Dense, Flattenfrom keras import optimizersimport numpy as npimport sysimport os

(AX, AY), (QX, QY) = mnist.load_data() # AX [60000,28,28] AY [60000,]AX=255-AX; QX=255-QX

nclasses = 10AY2 = keras.utils.to_categorical(AY, nclasses) # 3 -> 0001000000QY2 = keras.utils.to_categorical(QY, nclasses)

nl, nc = AX.shape[1], AX.shape[2] #28, 28AX = AX.astype('float32') / 255.0 # 0 a 1QX = QX.astype('float32') / 255.0 # 0 a 1AX = np.expand_dims(AX,axis=3) # AX [60000,28,28,1]QX = np.expand_dims(QX,axis=3)

model = Sequential() # 28x28model.add(Conv2D(20, kernel_size=(5,5), activation='relu', input_shape=(nl, nc, 1) )) #20x24x24model.add(MaxPooling2D(pool_size=(2,2))) #20x12x12model.add(Conv2D(40, kernel_size=(5,5), activation='relu')) #40x8x8model.add(MaxPooling2D(pool_size=(2,2))) #40x4x4model.add(Flatten()) #640model.add(Dense(1000, activation='relu')) #1000model.add(Dense(nclasses, activation='softmax')) #10

from keras.utils import plot_modelplot_model(model, to_file='cnn1.png', show_shapes=True); model.summary()

opt=optimizers.Adam()model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])

model.fit(AX, AY2, batch_size=500, epochs=30, verbose=2)

score = model.evaluate(QX, QY2, verbose=False)print('Test loss:', score[0])print('Test accuracy:', score[1])

model.save('cnn1.h5')

Programa 1: Classificação de MNIST usando rede neural convolucional.

Programa 1 também está em:https://colab.research.google.com/drive/1qjky49jl8ChqVSvlvRykMhlnKcvhv0dL?usp=sharing

Exercício: Execute programa 1 (cnn1.py) para obter a rede cnn1.h5. Anote a acuracidade obtida.

7

Page 8: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

_________________________________________________________________Layer (type) Output Shape Param # =================================================================conv2d_1 (Conv2D) (None, 24, 24, 20) 520 _________________________________________________________________max_pooling2d_1 (MaxPooling2 (None, 12, 12, 20) 0 _________________________________________________________________conv2d_2 (Conv2D) (None, 8, 8, 40) 20040 _________________________________________________________________max_pooling2d_2 (MaxPooling2 (None, 4, 4, 40) 0 _________________________________________________________________flatten_1 (Flatten) (None, 640) 0 _________________________________________________________________dense_1 (Dense) (None, 1000) 641000 _________________________________________________________________dense_2 (Dense) (None, 10) 10010 =================================================================Total params: 671,570Trainable params: 671,570Non-trainable params: 0

Figura 8: Modelo de rede do programa cnn1.py (programa 1). Esquerda: TF2. Direita: TF1.

A saída obtida, rodando este programa, é:

Epoch 1/30 - 5s 76us/step - loss: 0.4239 - acc: 0.8846Epoch 2/30 - 3s 47us/step - loss: 0.0878 - acc: 0.9736Epoch 3/30 - 3s 46us/step - loss: 0.0577 - acc: 0.9826(...)Epoch 27/30 - 3s 47us/step - loss: 0.0023 - acc: 0.9993Epoch 28/30 - 3s 47us/step - loss: 0.0014 - acc: 0.9997Epoch 29/30 - 3s 46us/step - loss: 0.0014 - acc: 0.9997Epoch 30/30 - 3s 47us/step - loss: 0.0036 - acc: 0.9990Test loss: 0.0329350275504491Test accuracy: 0.9928

Obtivemos taxa de erro de teste 0,72%, a menor taxa que conseguimos até agora. Esta taxa estábastante abaixo de 2% que conseguimos obter usando rede convencional. Por outro lado, podemosver que o custo e erro de treino (0,0036 e 0,1%) são muito melhores que o custo e erro de teste(0,0329 e 0,72%), indicando que há “overfitting”. Cada vez que rodamos este programa, obtemosuma taxa de erro um pouco diferente, pois os pesos e vieses são inicializados aleatoriamente. Tipi-camente, os erros obtidos estão entre 0,68% e 0,84%.

8

Page 9: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

Exercício: Faça diferentes alterações no programa 1 para atingir taxa de erro menor que 0,72%,sem fazer “data augmentation”. Isto não é difícil, pois já consegui taxas de erros menores usandoparâmetros um pouco diferentes. Algumas alterações possíveis são: (a) Mudar a estrutura da rede.(b) Mudar número e tamanho dos filtros. (c) Mudar função de ativação. (d) Mudar o otimizadore/ou os seus parâmetros. (e) Mudar o tamanho do batch. (f) Mudar o número de épocas. Descreva(como comentários dentro do seu programa .cpp ou .py) a taxa de erro que obteve, o tempo de pro-cessamento, as alterações feitas e os testes que fez para chegar ao seu programa com baixa taxa deerro.

Exercício: Modifique programa 1 para que a rede extraia as características das imagens (os valoresentre a parte vermelha e azul da figura 7). Utilize as características das imagens de treinamento paratreinar algum algoritmo de aprendizagem de máquina clássica (como Boost, decision-tree, etc). Ve-rifique a taxa de acerto classificando as imagens de teste.

[Lição de casa #1 aula 3] O programa 1 utiliza 60000 imagens de treinamento. Modifique-o paraque utilize apenas 6000 primeiras imagens de treino, isto é 10% dos dados de treino iniciais. Nãotem problema se alguns dígitos possuem um pouco mais exemplos de treinamento do que outros.Ajuste o programa para obter a menor taxa de erro possível quando o programa classifica as 10000imagens de teste. Qual foi a taxa de erro obtida? O seu vídeo deve mostrar claramente que está uti -lizando apenas 6000 imagens de treino, imprimindo AX.shape[0] e AY.shape[0]. Também devedeixar claro no vídeo a taxa de erro obtida.

9

Page 10: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

[Lição de casa #2, aula 3] Fashion_MNIST é um BD muito semelhante à MNIST. Consiste de60000 imagens de treino e 10000 imagens de teste 28x28, em níveis de cinza, com as categorias: 0T-shirt/top; 1 Trouser; 2 Pullover; 3 Dress; 4 Coat; 5 Sandal; 6 Shirt; 7 Sneaker; 8 Bag; 9 Ankleboot.

Esse BD pode ser carregada com os comandos:

from keras.datasets import fashion_mnist(AX, AY), (QX, QY) = fashion_mnist.load_data()

Modifique o programa 1 para que classifique fashion_mnist. Ajuste o programa para obter a menortaxa de erro possível. Qual foi a taxa de erro obtida? Deixe claro no vídeo a taxa de erro obtida.Mostre as 4 primeiras imagens do BD na tela e no vídeo, para ter certeza de que está classificando oBD correto.

Mostrar 3 imagens em níveis de cinza lado a lado:

from matplotlib import pyplot as pltf = plt.figure()f.add_subplot(1,3,1)plt.imshow(img1,cmap="gray")f.add_subplot(1,3,2)plt.imshow(img2,cmap="gray")f.add_subplot(1,3,3)plt.imshow(img3,cmap="gray")plt.show(block=True)

[Fim da aula 3]

10

Page 11: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

[Início da aula 4]

3 Visualização dos filtros

A figura 9 mostra os aspectos dos 20 filtros 5×5 da primeira camada da rede (estou processando arede cnn1.h5 com taxa de erro 0,68% que deixei disponível no site). De um modo geral, CNN pro-jetou filtros com características visuais pouco intuitivas. Porém, algumas delas possuem interpreta-ções intuitivas. Por exemplo, o filtro azul detecta (aproximadamente) as bordas esquerdas das retasverticais. As imagens filtradas por esse filtro na figura 11b mostram que, de fato, ele detecta as bor-das esquerdas das retas verticais. Outro exemplo, o filtro vermelho detecta (aproximadamente) asbordas inferiores das retas horizontais, o que pode ser confirmado olhando as saídas respectivas nafigura 11b. As saídas desses 20 filtros resultam em 20 imagens 24×24, que serão reduzidos para 20imagens 12×12 por max-pooling com blocos 2×2.

Figura 10 mostra 40 filtros 20×5×5 da segunda camada. Note que cada um desses 40 filtros seráaplicado às 20 imagens 12×12 da primeira camada, resultando em 40 imagens 8×8. Estas imagensserão reduzidas para 40 imagens 4×4 pelo max-pooling 2×2. Os valores dos 40×4×4=640 saídas ali-mentarão uma rede neural densa que fará a classificação final nos 10 dígitos.

Figura 9: Os pesos das 20 convoluções 5x5 da primeira camada. Os filtros marcados em vermelho eazul detectam respectivamente retas horizontais e verticais.

11

Page 12: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

Figura 10: 40 filtros 20x5x5 da segunda camada. Cada coluna é um filtro.

Para acessar os pesos dos filtros e dos vieses da primeira camada (“conv2d_1” ou “conv2d” depen-dendo da versão de TF, figura 8), o seguinte trecho de programa pode ser usado:

model=keras.models.load_model("cnn1.h5")(filters, biases) = model.get_layer("conv2d_1").get_weights()#Nome da primeira camada convolucional é conv2d_1 (TF1) ou conv2d (TF2)

O tensor “filters” obtido como acima deve ter shape 5x5x1x20. Para imprimi-lo, é melhor que te-nha shape 20x5x5. O seguinte trecho de programa faz essa conversão.

filters=np.squeeze( filters )filters2=np.empty( (filters.shape[2], filters.shape[0], filters.shape[1]) )for i in range(20): filters2[i,:,:]=filters[:,:,i]

[Lição de casa 1 da aula 4] Escreva um programa que permite visualizar os 20 filtros da primeiracamada convolucional da rede cnn1.h5, como na figura 9. Mostre esses filtros na tela e grave no ví-deo. Se você usar cnn1.h5 que deixei no site, deve visualizar exatamente os filtros da figura 9 - sevocê usar cnn1.h5 gerado pelo seu programa, os filtros visualizados serão outros.

Nota: Aparentemente, TF1 e TF2 estão dando nomes diferentes às camadas. A primeira camadaconvolucional chama-se conv2d_1 no TF1 mas chama-se conv2d no TF2. No TF2, conv2d_1 é asegunda camada convolucional.

Exercício: Explique por que a segunda camada convolucional possui 40x20x5x5 pesos.

12

Page 13: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

4 Visualizar ativação

É possível visualizar a ativação dos neurônios de uma camada intermediária durante a prediçãousando o seguinte código:

model=models.load_model("cnn1.h5") layer_name = 'conv2d_1' #ou conv2d dependendo da versão do TF intermediate_layer_model = Model(inputs=model.input, outputs=model.get_layer(layer_name).output) y = intermediate_layer_model.predict(x)

onde x é a imagem de um dígito no formato “(1, 28, 28, 1) float32” e y é a matriz de ativação.

A figura 11 mostra nas 3 colunas:

(a) As imagens de entrada de dígitos “1” e “3”.

(b) As ativações da primeira camada convolucional (conv2d_1), isto é, as saídas dos 20 primeirasconvoluções.

(c) As ativações da segunda camada max_pooling (max_pooling2d_2), ou seja, as 40×4×4=640 ca-racterísticas extraídas automaticamente pela CNN e que serão usadas pelas camadas densas paraclassificar os dígitos. Olhando essas características, é muito simples separar os dígitos “1” de “3”.Basta olhar, por exemplo, para os dois primeiros blocos. Eles são completamente pretos para dígi-tos “1” mas está com bastante ativação para dígitos “3”.

[Lição de casa 2 da aula 4] Escreva um programa que lê as imagens dos dígitos da figura 11 e geraas imagens das ativações (como na figura 11). Essas 4 imagens estão no site. Mostre essas imagensna tela e grave no vídeo.

Exercício: Explique por que nas ativações da figura 11 não pode haver valores negativos.

Nota: Para fazer os exercícios acima, pode ser interessante saber as características de um tensornumpy. Programa abaixo imprime o tipo de variável a, o tipo de cada elemento do tensor a, númerode dimensões de a e o forma de a:

import numpy as npa=np.full((100,100,3),(255,0,0),dtype="uint8")print(type(a),a.dtype,a.ndim,a.shape)

<class 'numpy.ndarray'> uint8 3 (100, 100, 3)

13

Page 14: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

(a) imagem (b) 20 saídas dos filtro da primeira camada (c) características escolhidas

at_1_002_dig.png

at_1_005_dig.png

at_3_018_dig.png

at_3_032_dig.png

Figura 11: (a) Dígito a classificar. (b) Ativações da primeira camada (preto=0, branco=1). (c) Ascaracterísticas extraídas automaticamente pela rede convolucional (preto=0, branco=1).

14

Page 15: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

5 Classificação de MNIST por CNN com “data augmentation”

Para diminuir ainda mais a taxa de erro, é possível usar vários “truques”.

O primeiro deles é aumentar artificialmente os dados de treinamento, chamado “data augmentati-on”. A ideia é pegar cada imagem de treino (AX) e deslocar um pixel em cada direção (norte, sul,leste, oeste), obtendo 5 imagens de treino (a original mais as quatro deslocadas, linhas 37-48). Comisso, obtemos dado de treino 5 vezes maior do que o original. Keras possui rotinas de “data aug-mentation” prontas. Porém, aqui vamos fazer manualmente “data augmentation” para que a ideia fi-que mais clara.

Nota: Em Python, sempre que possível deve-se escrever programa sem usar “loops”, pois “loops”são muito lentos em Python. As linhas 13-15 mostram como deslocar a imagem para esquerdausando “loops” (é o que faria em C/C++). A linha 12 faz o mesmo sem usar “loops”. Veja, porexemplo, https://numpy.org/doc/stable/reference/arrays.indexing.html para mais detalhes.

O segundo são as camadas “Dropout” (linhas 66, 69 e 71, marcadas em amarelo). Estas camadasdesativam aleatoriamente uma certa porcentagem dos neurônios de uma camada da rede durante otreino. Isto parece diminuir “overfitting”, pois obriga que a CNN funcione mesmo com vários neu-rônios desativados.

O terceiro é diminuir learning rate toda vez que a rede para de melhorar, através de uma função“callback” (linhas 80-81).

O quarto e último é fazer com que os valores dos pixels da imagem de entrada estejam no intervalo-0,5 a +0,5 (em vez de 0 a 1 como fizemos até agora, linhas 55-56). Sinceramente, é um mistériopor que isto melhora a acuracidade - teria que pensar mais a respeito. Se algum de vocês conseguiruma explicação plausível, favor avise-me.

O programa obtido com essas alterações está em programa 2. Rodando este programa, obtemos: Test loss: 0.018444421054241572Test accuracy: 0.9963

A taxa de erro obtida é 0,37%. O resultado é comparável ao estado da arte:http://rodrigob.github.io/are_we_there_yet/build/classifcation_datasets_results.html

Os 37 dígitos classificados incorretamente estão mostrados na figura 12. Repare que mesmo nós,seres humanos, temos dificuldade para classificar corretamente muitos deles. Esta taxa de erro(0,37%) já é menor do que a taxa de erro típico de um ser humano ao classificar os 10000 dígitosde teste de MNIST (2%).

Exercício: Modifique o programa 2 para obter taxa de erro menor que 0,37%.

Exercício: Escreva um programa que imprime os dígitos classificados incorretamente, como na fi-gura 12.

15

Page 16: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

Figura 12: Os 37 dígitos classificados incorretamente. Número à esquerda é a classificação correta.Número à direita é a classificação dada pelo algoritmo.

16

Page 17: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

12123456789

101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293

#cnn2.py - grad2020 - Testado em TF2 em Colabimport tensorflow.keras as kerasfrom keras.datasets import mnistfrom keras.models import Sequentialfrom keras.layers import Dropout, Conv2D, MaxPooling2D, Dense, Flattenfrom keras import optimizersfrom keras.callbacks import ReduceLROnPlateauimport numpy as npimport sysimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'

def deslocaEsquerda(a): d=a.copy() d[:,0:-1]=a[:,1:] # for c in range(a.shape[1]-1): # for l in range(a.shape[0]): # d[l,c]=a[l,c+1]; return d

def deslocaDireita(a): d=a.copy() d[:,1:]=a[:,0:-1] return d

def deslocaCima(a): d=a.copy() d[0:-1,:]=a[1:,:] return d

def deslocaBaixo(a): d=a.copy() d[1:,:]=a[0:-1,:] return d

print("Lendo MNIST")(AX, AY), (QX, QY) = mnist.load_data()AX=255-AX; QX=255-QX

print("Fazendo manualmente data augmentation")AX.resize((5*60000,28,28))AY.resize((5*60000,1))for s in range(60000): AX[s+60000]=deslocaEsquerda(AX[s]) AX[s+2*60000]=deslocaDireita(AX[s]) AX[s+3*60000]=deslocaCima(AX[s]) AX[s+4*60000]=deslocaBaixo(AX[s]) AY[s+60000]=AY[s] AY[s+2*60000]=AY[s] AY[s+3*60000]=AY[s] AY[s+4*60000]=AY[s]

print("Convertendo para categorico e float")nclasses = 10AY2 = keras.utils.to_categorical(AY, nclasses)QY2 = keras.utils.to_categorical(QY, nclasses)nl, nc = AX.shape[1], AX.shape[2] #28, 28AX = AX.astype('float32') / 255.0 - 0.5 # -0.5 a +0.5QX = QX.astype('float32') / 255.0 - 0.5 # -0.5 a +0.5AX = AX.reshape(AX.shape[0], nl, nc, 1)QX = QX.reshape(QX.shape[0], nl, nc, 1)

print("Construindo modelo")model = Sequential()model.add(Conv2D(20, kernel_size=(5,5), activation='relu', input_shape=(nl,nc,1)))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(40, kernel_size=(5,5), activation='relu'))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Dropout(0.25))model.add(Flatten())model.add(Dense(1000, activation='relu'))model.add(Dropout(0.5))model.add(Dense(200, activation='relu'))model.add(Dropout(0.5))model.add(Dense(nclasses, activation='softmax'))

print("Treinando modelo")opt=optimizers.Adam(lr=0.001)model.compile(optimizer=opt, loss="categorical_crossentropy", metrics=["accuracy"])

reduce_lr = ReduceLROnPlateau(monitor='accuracy', factor=0.9, patience=2, min_lr=0.0001, verbose=True)model.fit(AX, AY2, batch_size=1000, epochs=100, verbose=2, validation_data=(QX, QY2), callbacks=[reduce_lr])

score = model.evaluate(QX, QY2, verbose=False)print("Test loss:", score[0])print("Test accuracy:", score[1])

model.save("cnn2.h5")

Programa 2: Classificação de MNIST usando CNN com “data augmentation manual”.https://colab.research.google.com/drive/1qjky49jl8ChqVSvlvRykMhlnKcvhv0dL?usp=sharing

17

Page 18: Rede neural convolucional em Tensorflow/Keras · A função custo é calculada nos exemplos de treinamento organizados em mini-batches. O nosso programa possui apenas dois exemplos

6 Treino, validação e teste

Em aprendizagem de máquina, os dados de teste não podem ser usados durante o treino de jeito ne-nhum para ajudar a melhorar a rede. Por exemplo, é errado gravar a rede quando a taxa de erro, me-dido nos dados de teste, é a menor possível. Fazendo isto, a rede obtida estará adaptada para classi-ficar bem os dados de teste mas quase certamente funcionará pior quando processar novos dados.Para assegurar que os dados de teste não serão usados para nada durante o treino, os dados costu-mam ser dividido em 3 subconjuntos (treino, validação e teste) e não em 2 conjuntos (treino e teste)como fizemos até agora. Durante o treino, o conjunto de treino deve ser usado para ajustar os pesose vieses da rede. Durante o treino, o conjunto de validação pode ser usado para estimar a taxa deerro da rede (para dados que não estão no conjunto de treino). Somente quando a rede estiver com-pletamente treinada, o conjunto de teste deve ser usado para estimar a taxa de erro da rede.

Referências:

[Nielsen] http://neuralnetworksanddeeplearning.com/

[LeCun1989] LeCun, Y.; Boser, B.; Denker, J. S.; Henderson, D.; Howard, R. E.; Hubbard, W.;Jackel, L. D. (1989). "Backpropagation Applied to Handwritten Zip Code Recognition" NeuralComputation. MIT Press - Journals. 1 (4): 541–551.

[Fim da aula 4]

18