42
Rede neural densa em Tensorflow/Keras ou PyTorch 1. Tensorflow, Keras, PyTorch e Google Colab 1.1 Tensorflow, Keras e PyTorch A partir desta aula, vamos trabalhar com aprendizagem profunda, usando redes neurais convolucio- nais. Trabalharemos em linguagem Python, usando bibliotecas OpenCV, Tensorflow e Keras. Al- guns programas correspondentes em PyTorch estão no anexo. Estou supondo que vocês já estudaram rede neural. Quem nunca tiver estudado rede neural, muitos dos conceitos envolvidos será explicada neste curso. Porém pode ser necessário complementar o co- nhecimento consultando alguma outra fonte. A minha apostila “redeneural” dá um pouco mais de explicação sobre rede neural, principalmente sobre retro-propagação. Conhecidamente, C++ é entre 10 a 100 vezes mais rápido do que Python: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/gpp-python3.html Porém, as bibliotecas mais populares para deep learning (em 2020) são TensorFlow/Keras e PyTor- ch. Ambas possuem interface principal em Python. Assim, passaremos a usar Python. TensorFlow é uma biblioteca de código aberto para aprendizagem de máquina profunda. Foi desen- volvida pela equipe Google Brain e é usada tanto para a pesquisa quanto produção na Google. Es- crever aplicações de aprendizagem de máquina diretamente em TensorFlow costuma ser uma tarefa árdua. Nota: O que é um tensor (de TensorFlow)? Em aprendizagem de máquina, tensor é generalização do conceito de vetor e matriz. É um arranjo multi-dimensional ou uma matriz de mais de duas di- mensões. Em matemática, tensor possui outra definição. Porém, para nós, um tensor é simplesmente uma matriz multi-dimensional. Keras é uma biblioteca de código aberto escrita em Python, projetada para ser amigável e de “alto nível”. Permite escrever os programas de forma simples e rápida, porém é difícil escrever um pro- grama “diferente”, que “foge do padrão”, em Keras. Roda em cima de outras bibliotecas de aprendi- zagem de máquina de “baixo nível”, por exemplo TensorFlow, Theano ou Microsoft Cognitive To- olkit. Neste curso, vamos usar Keras (com backend TensorFlow) para implementar as redes neurais profundas. PyTorch é uma biblioteca de aprendizagem de máquina de código aberta e foi desenvolvida pelo grupo de pesquisa em IA da Facebook. Esta biblioteca é de “baixo nível” que necessita escrever mais código para fazer a mesma tarefa que Keras. Por outro lado, permite debugar melhor o progra- ma pois é possível visualizar os passos intermediários do processamento e permite desenvolver pro- gramas de aprendizagem de máquina que fogem do padrão. Alguns programas deste curso estarão traduzidas para PyTorch e apresentados no anexo. Instruções para instalar esses programas (Keras/Tensorflow/PyTorch) encontram-se em muitos sites diferentes. A forma específica de instalar depende do hardware do seu computador e da opção de instalação escolhida (se vai usar ou não GPU; do modelo do GPU; se vai instalar em ambiente vir- tual ou não; etc). Instale como você achar melhor. Se quiser, siga as instruções que deixei no site abaixo (pode estar um pouco desatualizada): http://www.lps.usp.br/hae/software/instalacao_tensorflow.pdf 1

Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Rede neural densa em Tensorflow/Keras ou PyTorch

1. Tensorflow, Keras, PyTorch e Google Colab

1.1 Tensorflow, Keras e PyTorch

A partir desta aula, vamos trabalhar com aprendizagem profunda, usando redes neurais convolucio-nais. Trabalharemos em linguagem Python, usando bibliotecas OpenCV, Tensorflow e Keras. Al-guns programas correspondentes em PyTorch estão no anexo.

Estou supondo que vocês já estudaram rede neural. Quem nunca tiver estudado rede neural, muitosdos conceitos envolvidos será explicada neste curso. Porém pode ser necessário complementar o co-nhecimento consultando alguma outra fonte. A minha apostila “redeneural” dá um pouco mais deexplicação sobre rede neural, principalmente sobre retro-propagação.

Conhecidamente, C++ é entre 10 a 100 vezes mais rápido do que Python:https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/gpp-python3.html

Porém, as bibliotecas mais populares para deep learning (em 2020) são TensorFlow/Keras e PyTor-ch. Ambas possuem interface principal em Python. Assim, passaremos a usar Python.

TensorFlow é uma biblioteca de código aberto para aprendizagem de máquina profunda. Foi desen-volvida pela equipe Google Brain e é usada tanto para a pesquisa quanto produção na Google. Es-crever aplicações de aprendizagem de máquina diretamente em TensorFlow costuma ser uma tarefaárdua.

Nota: O que é um tensor (de TensorFlow)? Em aprendizagem de máquina, tensor é generalizaçãodo conceito de vetor e matriz. É um arranjo multi-dimensional ou uma matriz de mais de duas di-mensões. Em matemática, tensor possui outra definição. Porém, para nós, um tensor é simplesmenteuma matriz multi-dimensional.

Keras é uma biblioteca de código aberto escrita em Python, projetada para ser amigável e de “altonível”. Permite escrever os programas de forma simples e rápida, porém é difícil escrever um pro-grama “diferente”, que “foge do padrão”, em Keras. Roda em cima de outras bibliotecas de aprendi-zagem de máquina de “baixo nível”, por exemplo TensorFlow, Theano ou Microsoft Cognitive To-olkit. Neste curso, vamos usar Keras (com backend TensorFlow) para implementar as redes neuraisprofundas.

PyTorch é uma biblioteca de aprendizagem de máquina de código aberta e foi desenvolvida pelogrupo de pesquisa em IA da Facebook. Esta biblioteca é de “baixo nível” que necessita escrevermais código para fazer a mesma tarefa que Keras. Por outro lado, permite debugar melhor o progra-ma pois é possível visualizar os passos intermediários do processamento e permite desenvolver pro-gramas de aprendizagem de máquina que fogem do padrão. Alguns programas deste curso estarãotraduzidas para PyTorch e apresentados no anexo.

Instruções para instalar esses programas (Keras/Tensorflow/PyTorch) encontram-se em muitos sitesdiferentes. A forma específica de instalar depende do hardware do seu computador e da opção deinstalação escolhida (se vai usar ou não GPU; do modelo do GPU; se vai instalar em ambiente vir-tual ou não; etc). Instale como você achar melhor. Se quiser, siga as instruções que deixei no siteabaixo (pode estar um pouco desatualizada):

http://www.lps.usp.br/hae/software/instalacao_tensorflow.pdf

1

Page 2: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

TensorFlow/Keras/PyTorch rodam consideravelmente mais rápido em GPU do que CPU (algocomo 3-10 vezes mais rápido). Por outro lado, dá bem mais trabalho instalá-los para usar GPU doque CPU.

Em primeiro lugar, só funcionam com GPU da NVidia (parece que há forma de fazer funcioná-loscom alguns GPUs da AMD, mas é experimental). Mesmo que o seu computador tenha GPU daNVidia, precisa instalar primeiro uma série de bibliotecas (NVidia GPU driver, Cuda e cuDNN)para trabalhar usando GPU. Cada versão de TensorFlow/Keras/PyTorch só funciona com uma ver-são específica destas bibliotecas. Muitas vezes, não dá certo instalar a versão mais atual de todos osprogramas. Se mudar a versão de algumas dessas bibliotecas (ou quando atualiza esses programas),programas que antes estavam funcionando podem parar de funcionar.

2

Page 3: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

1.2 Google Colab

a) Outra forma de usar Tensorflow/Keras/PyTorch com GPU é pelo Google Colab. Você pode en-trar no Google Colab via browser (Chrome, Firefox, Safari, etc.) com sua conta Google, dar copy-paste dos programas desta apostila e tudo roda. Inclusive, dá para usar GPUs bons só editando asconfigurações em “notebook settings”. Outra grande vantagem de Google Colab é que você nãoprecisa instalar nada – já está tudo instalado e funcionando.

Os programas desta apostila foram testados em Google Colab (Python 3.6.9, tensorflow 2.2.0-rc4,tensorflow-keras 2.3.0-tf e OpenCV 4.1.2) e/ou localmente usando Python3. Dependendo das ver-sões das bibliotecas no seu computador, pode ser necessário modificar um pouco os exemplos paraque eles funcionem.

Após instalar Tensorflow/Keras (ou em Google Colab), rode o programa abaixo:

#versao2.py#Imprime versao de Tensorflow, Keras e Keras dentro do Tensorflow#Tambem imprime se GPU esta funcionando, versao de SO, CPU e RAMimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflow as tfimport kerasphysical_devices = tf.config.list_physical_devices('GPU') tf.config.experimental.set_memory_growth(physical_devices[0], True)import sys; import cv2

print(sys.version)print("Versao de tensorflow:",tf.__version__)print("Versao de Keras independente:",keras.__version__)print("Versao de Keras dentro de tensorflow:",tf.keras.__version__)print("Versao cv2:",cv2.__version__)os.system("nvcc --version | grep release")print()

gpu=tf.test.gpu_device_name()if gpu=="": print("Computador sem GPU.")else: print("Computador com GPU:",tf.test.gpu_device_name()) from tensorflow.python.client import device_lib devices=device_lib.list_local_devices() print("Dispositivos:",[x.physical_device_desc for x in devices if x.physical_device_desc!=""]) #os.system('cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2') os.system('cat /usr/include/cudnn.h | grep "define CUDNN_MAJOR" -A 2') #os.system('nvidia-smi')print()

os.system('lsb_release -a | grep "Description"') #imprime qual é o sistema operacionalos.system('cat /proc/cpuinfo | grep -E "model name"') #especificações de CPUos.system('cat /proc/meminfo | grep "Mem"') #especificações de RAMprint()

import torch;print("Versao pytorch: ",torch.__version__);print("GPU disponivel em pytorch: ",torch.cuda.is_available());

Com o comando:Linux$ python3 versao.py Windows> python versao.py

3

Page 4: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Ou em Google Colab:

O programa deve informar as versões das bibliotecas e imprimir se GPU está disponível (ou não)junto com TensorFlow. Rodando esse mesmo programa no Google Colab, a saída obtida é:

4

Aperte aqui para rodar

Page 5: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0]Versao de tensorflow: 2.4.1Versao de Keras independente: 2.4.3Versao de Keras dentro de tensorflow: 2.4.0Versao cv2: 4.2.0Cuda compilation tools, release 11.0, V11.0.194

Computador com GPU: /device:GPU:0Dispositivos: ['device: 0, name: GeForce RTX 2060, pci bus id: 0000:01:00.0, compute capability: 7.5']#define CUDNN_MAJOR 7#define CUDNN_MINOR 6#define CUDNN_PATCHLEVEL 5

Description: Linux Mint 20.1model name : Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz(...)MemTotal: 16325708 kBMemFree: 8195920 kBMemAvailable: 13158356 kB

Versao pytorch: 1.7.1GPU disponivel em pytorch: True

Note que há duas Keras instaladas: Uma Keras independente do TensorFlow (versão 2.4.3) e umaoutra Keras que vem incluído dentro do TensorFlow (versão 2.4.0).

b) Associado à sua conta Google, você tem acesso a Google Drive e Google Colab. Os “notebooks”que você cria em Colab são salvos normalmente no diretório “Colab Notebooks” do seu Drive e nãodesaparecem. O grande problema do Google Colab é que todos os arquivos que você deixar no Co-lab (exceto os “notebooks” que ficam armazenados no diretório “Colab Notebooks” do seu Drive)desaparecem quando você fecha a seção. Explicarei mais adiante como contornar isto.

c) Para usar GPU ou TPU dentro de Google Colab, você deve editar “editar → configurações de no-tebook”.

d) Quando você entra no computador virtual do Google Colab, o seu diretório atual é “/content”,você é o usuário “root” e o seu diretório $HOME é /root.

e) Os comandos de bash (terminal de Linux) podem ser executados em “subshell” prefixando o co-mando com “!”. Por exemplo, escrevendo “!ls” no seu programa Python, irá obter o conteúdo do di-retório atual. Se escrever “!pwd”, obterá o seu diretório default.

!ls #lista conteúdo do diretório atual (inicialmente “sample_data”)!pwd #imprime qual é o diretório atual (normalmente “/content”)

É também possível usar o comando os.system(“...”) de Python em vez de “!”. O problema é que asaída no terminal deste comando fica invisível. Porém, se redirecionar a saída para algum arquivotexto usando “>” ou “>>”, é possível constatar que esse comando funciona:

import osos.system("ls > saida.txt")os.system("pwd >> saida.txt")

O arquivo saida.txt conterá as saídas dos dois comandos.

f) Para mudar o diretório atual, “!cd” não funciona pois esse comando é executado em subshell. Amudança de diretório é desfeita quando termina subshell. Para mudar o diretório permanentemente,deve usar “%cd” onde “%” prefixa “magic commands”:%cd diretorio [muda para diretorio]%reset -f [apaga todas as variáveis e funções de Python]

Uma outra forma de mudar de diretório permanentemente é usar os.chdir:import osprint(os.getcwd())os.chdir("diretorio")print(os.getcwd())

5

Page 6: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

g) Apesar de que a maioria dos programas de TensorFlow v1 rodam sem alterações no TensorFlowv2, se quiser obrigar Google Colab usar TensorFlow v1, acrescente o seguinte comando no iníciodo programa Python:%tensorflow_version 1.x

Da mesma forma, o comando abaixo no início do notebook obriga a usar TensorFlow v2 (o que épadrão):%tensorflow_version 2.x

h) Como já disse, Colab não armazena permanentemente os arquivos dentro do seu computador vir-tual. Os arquivos são todos excluídos quando a seção Colab é fechada. Uma forma de armazenar ar-quivos permanentemente é você montar o seu Google Drive como um subdiretório do sistema de ar-quivos de Colab e deixar lá os seus arquivos. Isto pode ser feito clicando no botão laranja e depoisno botão vermelho (na figura abaixo à esquerda) ou rodando o código Python (da coluna da direita).

from google.colab import drivedrive.mount('/content/drive')

Ao apertar o botão ou executar o código, aparece um link para uma página onde você deve obter ocódigo de autorização para montar o seu Google Drive dentro do Colab. Você deve copiar-colaresse código:

Depois que o diretório estiver montado, você pode visualizar a sua estrutura de diretórios (comonum navegador de arquivos) clicando em:

O seu Google Drive ficará montado no diretório:“/content/drive/MyDrive”

Em 2020, tinha um espaço branco em “My Drive”. Isto causava um monte de problemas. Em 2021,Google resolveu eliminar esse espaço.

6

Page 7: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

O programa abaixo monta o seu Google Drive, vai para o seu Google Drive, cria um diretório“lixo” se não existir, grava um arquivo texto “lixo.txt” nesse diretório e depois lê esse arquivo texto.O arquivo “lixo.txt” não será apagado mesmo quando a sessão do Colab terminar, pois estará arma-zenado no seu Google Drive.

from google.colab import drivedrive.mount('/content/drive')%cd "/content/drive/MyDrive/"! [ ! -d "lixo" ] && mkdir lixo%cd "lixo"

arq=open("lixo.txt","w")arq.write("Testando arquivo texto.\n")arq.close()

arq=open("lixo.txt","r")st=arq.readline()print("Linha lida:",st)arq.close()

Nota: Apesar do seu Google Drive parecer um diretório local Colab (/content/drive/MyDrive/)o seu Google Drive pode estar fisicamente bem distante do computador Colab. Assim, a transferên-cia de arquivos entre Google Drive e Colab pode ser lenta, principalmente a transferência de váriosarquivos pequenos. É muito mais rápido transferir um arquivo compactado (.zip) grande entre Goo-gle Drive e Colab do que transferir vários arquivos pequenos.

Exercício: Faça “upload” de alguma imagem (digamos, lenna.jpg) para o seu Google Drive, diretó-rio “psi3472”. Escreva um Colab notebook que lê essa imagem e mostra-a na tela (dentro do brow-ser).

Nota: “cv2.imshow” do OpenCV não funciona dentro do Colab. No seu lugar, deve usar“plt.imshow” do pyplot.

from matplotlib import pyplot as plta=plt.imread(“lenna.jpg”)plt.imshow(a); plt.axis("off"); plt.show()

Outra opção é usar cv2_imshow:from google.colab.patches import cv2_imshowcv2_imshow(img)

i) É possível até rodar programas C/C++ em Google Colab. Para isso, escreva o seu programa (di-gamos, prog.cpp), armazene-o em algum diretório do Google Drive, monte o Google Drive dentrodo Google Colab, vá para o diretório onde está o programa e compile-o:!g++ prog.cpp -o prog

Depois execute-o:!./prog

Exercício: No diretório “psi3472” do seu Google Colab, escreva um programa C++ que imprime“Hello, world!”. Compile-o e execute-o.

Outras dicas sobre Google Colab estão em Anexo B.

7

Page 8: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

2. Regressão em Keras

Após instalar Python3/TensorFlow/Keras (ou usando Google Colab), vamos criar uma rede neuralsimples (não-convolucional) com camadas densas (fully-connected), para nos familiarizarmos como ambiente de programação. Vamos criar uma rede neural com 2 entradas e 2 saídas. Vamos usardois exemplos de treinamento: {[ax1; ay1]; [ax2; ay2]} = { [(0.9, 0.1); (0.1, 0.9)]; [(0.1, 0.9); (0.9,0.1)] }. Isto é, quando a entrada for ax1=(0.9, 0.1) queremos obter a saída ay1=(0.1, 0.9). Quando aentrada for ax2=(0.1, 0.9) queremos obter a saída ay2=(0.9, 0.1).

A figura 1 mostra a estrutura da rede. Esta rede possui duas entradas (i1 e i2), duas saídas (bolinhascinzentas sem nome) e quatro neurônios (h1, h2, o1 e o2).

Figura 1: Estrutura da rede neural do programa regression.py

A implementação desta rede em Keras está no programa 1. As linhas 2-6 importam os módulos aserem usados no programa. Tanto TensorFlow quanto OpenCV utilizam a biblioteca numpy paraefetuar operações com matrizes (linha 6). A linha 7 indica que não queremos que TensorFlow mos-tre informações excessivas. As linhas 10-12 constroem o modelo da rede sequencial. Uma rede se-quencial é formada por uma pilha linear de camadas (sem desvios nem recorrências).

1234567891011121314151617181920212223242526

#regression.py - pos2021import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflow.keras as kerasfrom keras.models import Sequentialfrom keras.layers import Dense, Activationfrom keras import optimizersimport numpy as np

#Modelo de redemodel = Sequential()model.add(Dense(2, activation='sigmoid', input_dim=2))model.add(Dense(2, activation='sigmoid'))sgd=optimizers.SGD(lr=1)model.compile(optimizer=sgd,loss='mse')

# Gera dado artificialAX = np.matrix('0.9 0.1; 0.1 0.9',dtype='float32')AY = np.matrix('0.1 0.9; 0.9 0.1',dtype='float32')

# As alternativas sao batch_size 2 ou 1model.fit(AX, AY, epochs=1000, batch_size=2, verbose=False)

QX = np.matrix('0.9 0.1; 0.1 0.9; 0.8 0.0; 0.2 0.9',dtype='float32')print(QX)QP=model.predict(QX)print(QP)

Programa 1: Regression.py

8

i1

i2

h1

h2

o1

o2

bb

bbbb

bb

b

Page 9: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Cada neurônio da rede (figura 1) recebe as duas entradas (isto é, dois números em ponto flutuante),multiplica-as pelos respectivos pesos wi (cada aresta direcionada possui um peso associado), somaviés (bias) b, e aplica uma função de ativação não-linear ao resultado (neste caso, a função sigmoi-de), gerando a saída (um número em ponto flutuante). A figura 2 ilustra o funcionamento de umneurônio da rede. A função “sigmoide” ou “logistic” é definida como:

sigmoid (x)=1

1+e− x

e o seu gráfico está no anexo A.2. No programa, as linhas 11 e 12 especificam que queremos usar afunção sigmoide.

Figura 2: Funcionamento de um neurônio.

Na figura 1, os 4 neurônios estão organizados em 2 camadas: verde e amarela. Cada camada recebeduas entradas e gera duas saídas. A camada verde (h1 e h2) é a camada escondida (linha 11 do pro-grama 1) que recebe os dados de entrada (dimensão 2). A camada amarela (o1 e o2) é a camada desaída (linha 12 do programa).

Uma rede neural M possui uma função custo (ou erro ou perda) C que mede o quanto a saída M(ax),para entrada ax, é diferente da saída desejada ay: C( M(ax), ay ). No nosso programa, vamos usar oerro quadrático médio (mean square error ou mse, linha 14).

Retro-propagação (backpropagation) é o processo que ajusta, aos poucos, os pesos da rede para di-minuir a função custo (diferença entre a saída da rede e a saída desejada), alterando “um pouco” osvalores dos pesos e dos bias. Para isso, devemos calcular as derivadas parciais da função custo Cem relação a cada peso e cada viés:

∂C∂w k

e ∂C∂b l

A função custo é calculada nos exemplos de treinamento organizados em mini-batches.

O nosso programa possui apenas dois exemplos de treinamento {a1, a2} (linhas 17 e 18). É possívelcalcular a função custo para cada um dos dois exemplos de treinamento C(a1) e C(a2). Ou é possí-vel calcular a média das funções de erro C(a) = [C(a1)+C(a2)]/2. No primeiro caso, o tamanho domini-batch será um (o treino tentará minimizar alternadamente cada uma das duas funções custo porvez). No segundo caso, o tamanho do mini-batch será dois (o treino tentará minimizar a média deerro das duas funções custo cada vez). Vamos usar batch de tamanho dois (linha 21).

Cada derivada parcial indica para onde deve se mover para aumentar a função custo. Como quere-mos diminuir a função custo, movemos “um pouco” cada peso w e cada viés b no sentido contrárioà sua derivada parcial (figura 4). Para especificar “um pouco”, utiliza-se a taxa de aprendizagem(learning rate) η:

9

z = w1*i1+w2*i2+ba=sigmoid(z)

W1

i1

W2i2

b

a

Page 10: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

w k→w' k=wk−η∂C∂w k

bl→b ' l=b l−η∂C∂ bl

Taxa de aprendizagem é o comprimento da flecha (dividido pela magnitude do gradiente) na figura4. No programa 1, a taxa de aprendizagem (learning rate ou lr) está especificada na linha 13 comosendo 1. Existem várias estratégias diferentes de atualização dos pesos e vieses. Vamos usar “sto-chastic gradient descent” (linha 13) que é a estratégia explicada acima.

Veja a apostila “redeneural” ou o site [Nielsen] para uma explicação mais detalhada de como retro-projeção funciona.

Figura 4: Retro-projeção muda os valores dos pesos e viés para diminuir a função custo (extraído de[Nielsen]).

10

Page 11: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A linha 21 do programa 1 executa a retro-projeção da rede neural, com 1000 épocas (epochs). Cadaepoch corresponde a executar descida de gradiente para cada mini-batch, até que todas as amostrasde treinamento tenham sido usadas. No nosso caso, cada época vai executar uma única descida degradiente (pois o número de amostras é 2 e tamanho do mini-batch é 2).

Nas linhas 23-26, aplicamos a rede neural treinada nos dados de teste {qx1, qx2, qx3, qx4} = { [0.9 0.1]; [0.1 0.9]; [0.8 0.0]; [0.2 0.9] }. Executando o programa, obtemos:

$ python3 regression.pyUsing TensorFlow backend.[[0.9 0.1] [0.1 0.9] [0.8 0. ] [0.2 0.9]][[0.10639106 0.89681536] [0.89438605 0.10273475] [0.11006932 0.8937683 ] [0.8765248 0.12138095]]

As saídas obtidas estão de acordo com o treino. A cada treino, a saída será um pouco diferente poisa rede é inicializada com pesos e vieses aleatórios (veja Anexo A.1).

11

Page 12: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

3. Classificação em adulto, bebê e criança em Keras

Vamos resolver em Keras, usando rede neural artificial, o problema de classificar indivíduos em“adulto, bebê, criança” a partir do seu peso em kg. Na aula “aprendizagem”, resolvemos este pro-blema usando vizinho mais próximo. A rede neural que resolve esse problema está na figura 5.Cada “flecha” da rede possui um peso associado e cada neurônio da rede possui um viés associado.Para simplificar, vou chamar de “pesos” o conjunto formado pelos os pesos mais o vieses. O proble-ma é encontrar os pesos que classifiquem corretamente os indivíduos em A, B ou C.

Figura 5: Estrutura da rede neural para resolver problema “Adulto”, “Bebê” e “Criança”.

Para usar rede neural, vamos converter os rótulos A, B e C em vetores (1, 0, 0), (0, 1, 0) e (0, 0, 1),pois a rede da figura 3 possui três saídas (tabelas 1 e 2). Precisamos encontrar os pesos que fazem aclassificação desejada. Para isso, o programa inicializa aleatoriamente os pesos (Anexo A.1). Paratreinar a rede, o programa efetua a retro-alimentação.

Vou descrever intuitivamente a retro-alimentação quando usa mini-batch de 1 elemento. O progra-ma apresenta à rede um exemplo de treinamento (por exemplo “4”) e pega a saída fornecida pelarede. A saída desejada é o vetor (0, 1, 0) significando “Bebê”. Então, o programa aumenta ou dimi-nui um pouquinho cada peso para que a saída obtida fique um pouco mais próxima da desejada.

Tabela 1: Amostras de treinamento (ax, ay) e vetor de categoria ay2.ax (características, entradas) ay (rótulos, saídas) ay2 (vetor de categoria)4 B 0 1 015 C 0 0 165 A 1 0 05 B 0 1 018 C 0 0 170 A 1 0 0

Tabela 2: Instâncias de teste a classificar (qx), classificação verdadeira (qy) e vetor de categoria(qy2).qx (instância de teste) qy (classificação verdadeira) qp (vetor de categoria)16 C 0 0 13 B 0 1 075 A 1 0 0

12

i

h1

h2

o1

h3

o2

o3

Page 13: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A implementação em Keras está no programa 2.

123456789

10111213141516171819202122232425262728293031323334

#abc1.py - pos2021import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflowimport tensorflow.keras as kerasfrom keras.models import Sequentialfrom keras.layers import Dense, Activationfrom keras import optimizersimport numpy as npimport sys

model = Sequential();model.add(Dense(3, activation='sigmoid', input_dim=1))model.add(Dense(3, activation='sigmoid'))sgd=optimizers.SGD(lr=10);model.compile(optimizer=sgd, loss='mse', metrics=['accuracy'])

ax = np.matrix('4; 15; 65; 5; 18; 70 ',dtype="float32")ax=ax/100ay = np.matrix('0 1 0; 0 0 1; 1 0 0; 0 1 0; 0 0 1; 1 0 0',dtype="float32")model.fit(ax, ay, epochs=500, batch_size=2, verbose=True)

qx = np.matrix('16; 3; 75 ',dtype="float32")qx=qx/100qy = np.matrix('0 0 1; 0 1 0; 1 0 0',dtype="float32")teste = model.evaluate(qx,qy)print("Custo e acuracidade de teste:",teste)

qp=model.predict(qx)print("Classificacao de teste:\n",qp)qp = qp.argmax(axis=-1)print("Rotulo de saida:\n",qp)

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

Programa 2: Resolução do problema ABC em Keras. Nota: Não se pode chamar o programa de“abc.py”, pois parece que “abc” é uma palavra reservada em Python.

As linhas 11-15 especificam o modelo de rede, o otimizador “stochastic gradient descent” (sgd)com “learning rate” 10, e compila a rede usando “mean squared error” (mse) como medida de erro.

As linhas 17-19 especificam as entradas ax e saídas ay de treinamento. Estou dividindo os pesos emax por 100, para que resultem em números de 0 a 1. A linha 20 efetua retro-alimentação em 100épocas, usando mini-batches de tamanho 2.

As linhas 22-24 especificam as entradas qx e saídas qy de teste. A linha 24 calcula o custo e acura-cidade da rede nos dados de teste. As linhas 28-31 calculam as classificações como vetores e comorótulos. As linhas 33-34 imprimem o modelo de rede da figura 5.

A saída obtida é:

python3 abc1.pyUsing TensorFlow backend.Epoch 1/500 - 1s 162ms/step - loss: 0.2754 - acc: 0.1667Epoch 2/500 - 0s 563us/step - loss: 0.2733 - acc: 0.1667...Epoch 499/500 - 0s 719us/step - loss: 0.0011 - acc: 1.0000Epoch 500/500 - 0s 706us/step - loss: 0.0010 - acc: 1.0000Custo e acuracidade de teste: [0.0006011513760313392, 1.0]Classificacao de teste: [[2.0841250e-02 3.5288446e-02 9.5049566e-01] [3.2123618e-04 9.8374093e-01 1.9736269e-02] [9.8454732e-01 1.4877369e-06 1.9679543e-02]]Rotulo de saida: [2 1 0]

13

Page 14: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

4. Leitura de MNIST em Keras

Vamos classificar os dígitos do MNIST usando rede neural (não-convolucional) construído em Ke-ras. Para isso, vamos ver primeiro como ler o banco de dados MNIST em Python.

12345678910111213141516171819202122

# mnist1.pyimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflow.keras as kerasfrom keras.datasets import mnistfrom matplotlib import pyplot as plt

(AX, AY), (QX, QY) = mnist.load_data()print("AX:",AX.shape, AX.dtype)print("AY:",AY.shape, AY.dtype)print("QX:",QX.shape, QX.dtype)print("QY:",QY.shape, QY.dtype)

AX=255-AX; QX=255-QXplt.imshow(AX[0],cmap="gray",interpolation="nearest")plt.show()

nclasses = 10AY2 = keras.utils.to_categorical(AY, nclasses)QY2 = keras.utils.to_categorical(QY, nclasses)print("AY[0]:",AY[0])print("AY2[0]:",AY2[0])print("AY2:",AY2.shape, AY2.dtype)

Programa 3: Leitura de MNIST em Python/Keras.

O programa 3 lê MNIST, imprime os formatos e os tipos das matrizes lidas (linhas 1-11):

AX: (60000, 28, 28) uint8AY: (60000,) uint8QX: (10000, 28, 28) uint8QY: (10000,) uint8

Isto significa que AX é um tensor com 60.000 imagens 28x28 em níveis de cinza. AY é um vetor deuint8 com 60.000 rótulos. E assim por diante. Depois, inverte preto com branco e mostra na tela aprimeira imagem de treino (linhas 13-15, figura 6).

Figura 6: Imagem AX[0], primeira imagem de treino de MNIST, lida em Python.

Depois disso, o programa converte os rótulos AY e QY (números entre 0 e 9) em saídas bináriasAY2 e QY2 (linhas 17-22), para poder alimentar uma rede neural com 10 neurônios de saída. Re-lembre que fizemos uma conversão semelhante para classificar MNIST com rede neural na aula“classificação”. As saídas impressas para compreender o que está acontecendo (linhas 20-22) são:

14

Page 15: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

AY[0]: 5AY2[0]: [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]AY2: (60000, 10) float32

Significando que a categoria AY[0] da primeira imagem de treino é “5”. Esta categoria foi converti-da para vetor binário com zero em todas as posições exceto na posição de índice 5 (6ª saída) quetem valor 1 indicando o dígito 5 (AY2[0]).

15

Page 16: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

5. Classificação de MNIST em Keras usando rede neural densa

5.1 Primeiro programa de rede neural densa

Agora, estamos prontos para escrever programa Keras para classificar MNIST com rede neural denso. Pro-grama 4 é essa implementação.

123456789

1011121314151617181920212223242526272829303132333435363738394041424344454647

# mlp1.pyimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflow.keras as kerasfrom keras.datasets import mnistfrom keras.models import Sequentialfrom keras.layers import Dense, Flattenfrom keras import optimizersimport numpy as npimport sys

(AX, AY), (QX, QY) = mnist.load_data()AX=255-AX; QX=255-QX

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 a 1QX = QX.astype('float32') / 255.0 # 0 a 1

model = Sequential()model.add(Flatten(input_shape=(nl,nc)))model.add(Dense(400, activation='sigmoid'))model.add(Dense(nclasses, activation='sigmoid'))

#from keras.utils import plot_model#plot_model(model, to_file='mlp1.png', show_shapes=True)model.summary()

#opt=optimizers.sgd(lr=0.5)opt=optimizers.Adam()model.compile(optimizer=opt, loss='mse', #loss='categorical_crossentropy', metrics=['accuracy'])

model.fit(AX, AY2, batch_size=100, epochs=40, verbose=True);

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

model.save('mlp1.h5')

Programa 4: Classificação de MNIST com rede neural densa.

Como fizemos das outras vezes, as linhas 19-20 convertem matrizes AX e QX de uint8 (valores de0 a 255) para float32 (valores de 0 a 1).

As linhas 22-25 especificam o modelo da rede neural, com uma única camada escondida. A primei-ra camada (“Flatten”, linha 23) é uma camada artificial que não faz nenhum processamento real. Sóconverte matriz 2D 28x28 para vetor de 784 elementos, pois a próxima camada (Dense) só conse-gue receber como entrada vetor 1D. A segunda camada (linha 24) é a camada escondida e possui400 neurônios e ativação sigmoide. A terceira camada (linha 25) é a camada de saída com 10 neurô-nios e ativação também sigmoide.

As linhas 27-29 mostram duas diferentes formas de imprimir o modelo de rede. Já vimos anterior-mente como pode imprimir o modelo como uma imagem (27-28). Uma outra forma de imprimir

16

Page 17: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

modelo de rede está na linha 29. A saída do modelo impressa pelo programa, mostrando as 3 cama-das da rede é:

_________________________________________________________________Layer (type) Output Shape Param # =================================================================flatten_1 (Flatten) (None, 784) 0 _________________________________________________________________dense_1 (Dense) (None, 400) 314000 _________________________________________________________________dense_2 (Dense) (None, 10) 4010 =================================================================Total params: 318,010Trainable params: 318,010Non-trainable params: 0

As linhas 31-36 descrevem otimizador, função custo e métricas adicionais para calcular. Escolhi ootimizador Adam, que é um otimizador melhor do que SGD [Optimizers]. Adam usa momentum etaxa de aprendizagem adaptativa para convergir mais rapidamente à solução ótima.

A função de erro continua sendo MSE e vamos imprimir também a acuracidade para melhor poderacompanhar o treino da rede.

As linhas 38-41 fazem o treino. Tamanho de mini-batch é 100 (vai calcular gradiente e ajustar pe-sos/vieses para cada 100 amostras), 3 vai rodar 40 épocas (todas as amostras vão ser utilizadas 40vezes). A saída obtida durante o treino é:

_________________________________________________________________Epoch 1/40 - 2s 39us/step - loss: 0.0448 - acc: 0.7178Epoch 2/40 - 1s 22us/step - loss: 0.0191 - acc: 0.8928(...)Epoch 39/40 - 1s 22us/step - loss: 0.0024 - acc: 0.9889Epoch 40/40 - 1s 22us/step - loss: 0.0024 - acc: 0.9890

As funções custo e acuracidade listados acima são calculados nos dados de treino AX, AY.

A função custo e acuracidade nos dados de teste são calculados e impressos nas linhas 43-45:

Test loss: 0.004075948440702632Test accuracy: 0.9775

Isto é, a taxa de erro de teste obtida foi 2,25%, melhor do que a menor taxa obtida na aula “classifi-cação”. A taxa de erro de treino foi 1,1%. Por fim, a linha 48 salve o modelo de rede obtida. Este ar-quivo .h5 permite fazer predições ou continuar o treino de onde parou.

17

Page 18: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

5.2 Segundo programa de rede neural densa

Agora, vamos tentar melhorar a rede densa utilizando técnicas mais modernas. Já tínhamos trocadoo otimizador SGD (stochastic gradient descent) pelo otimizador moderno ADAM. Vamos:

1) Colocar mais uma camada escondida.2) Trocar função de ativação de camadas escondidas (sigmoide) pela função relu (anexo A.2).3) Trocar função de ativação da última camada (sigmoide) pela função softmax (anexo A.3).4) Mudar a função de perda de MSE para categorical_crossentropy (anexo A.4).5) Aumentar número de épocas de 40 para 160.

Essas alterações estão marcados em amarelo no programa 5. Veja nos anexos as definições destasmelhorias.

123456789101112131415161718192021222324252627282930313233343536373839404142

# mlp2.pyimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import tensorflow.keras as kerasfrom keras.datasets import mnistfrom keras.models import Sequentialfrom keras.layers import Dense, Flattenfrom keras import optimizersimport numpy as npimport sys

(AX, AY), (QX, QY) = mnist.load_data()AX=255-AX; QX=255-QX

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 a 1QX = QX.astype('float32') / 255.0 # 0 a 1

model = Sequential()model.add(Flatten(input_shape=(nl,nc)))model.add(Dense(400, activation='relu'))model.add(Dense(100, activation='relu'))model.add(Dense(nclasses, activation='softmax'))

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

model.fit(AX, AY2, batch_size=100, epochs=160, verbose=True);

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

model.save('mlp2.h5')

Programa 5: Classificação de MNIST com rede neural denso melhorado.

18

Page 19: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Executando o programa 5, obtemos:

Epoch 1/160 - 1s 1ms/step - loss: 0.5868 - accuracy: 0.8241Epoch 20/160 - 1s 1ms/step - loss: 0.0644 - accuracy: 0.9793Epoch 40/160 - 1s 2ms/step - loss: 0.0338 - accuracy: 0.9885Epoch 60/160 - 1s 2ms/step - loss: 0.0226 - accuracy: 0.9925Epoch 80/160 - 1s 2ms/step - loss: 0.0179 - accuracy: 0.9944Epoch 100/160 - 1s 2ms/step - loss: 0.0073 - accuracy: 0.9973Epoch 120/160 - 1s 2ms/step - loss: 0.0169 - accuracy: 0.9943Epoch 140/160 - 1s 2ms/step - loss: 0.0102 - accuracy: 0.9969Epoch 160/160 - 1s 2ms/step - loss: 0.0110 - accuracy: 0.9962Test loss: 0.1477910578250885Test accuracy: 0.9771000146865845

Onde 0,0110 e 0,9962 são custo e acuracidade de treino (erro de treino é 0,38%) e 0,148 e 0,977 sãocusto e acuracidade de teste (erro de teste é 2,3%). A primeira observação é que o erro de teste émuito maior que o erro de treino. Isto se chama “overfitting”, isto é, a aprendizagem de máquinaaprendeu classificar muito bem os dados de treino mas falha quando tenta generalizar para exem-plos de teste não vistos. A segunda observação é que o erro de teste não está melhor do que o doprograma 4 (2,25%), apesar de ter gasto muito mais tempo treinando.

Podemos concluir que o programa 5 aprendeu a classificar quase perfeitamente os exemplos de trei-no. Mas isto não se traduziu numa melhoria ao tentar classificar os exemplos de teste não vistos.

Exercício: Os resultados obtidos acima não são comparáveis aos dos métodos vistos na aula “clas-sificação”, pois lá trabalhamos com dígitos eliminando linhas/colunas brancas e redimensionado-ospara 14x14 pixels. Modifique os programas acima para que trabalhem nas mesmas condições daaula “classificação” e compare as acurácias assim obtidas com as dos métodos daquela aula.

Exercício: Modifique os programas 4 ou 5 para obter taxa de erro de teste menor que 2% (sem usarrede neural convolucional). Algumas alterações possíveis são: (a) Acrescentar ou eliminar camadas.(b) Mudar o número de neurônios das camadas. (c) Mudar função de ativação. (d) Mudar o otimiza-dor e/ou os seus parâmetros. (e) Mudar o tamanho do batch. (f) Mudar o número de épocas. (g) Eli -minar linhas/colunas brancas das imagens de entrada. (h) Redimensionar as imagens de entrada. (i)Aumentar artificialmente os dados de treinamento, criando versões distorcidas das imagens. Descre-va (como comentários dentro do seu programa .cpp ou .py) a taxa de erro que obteve, o tempo deprocessamento, as alterações feitas e os testes que fez para chegar ao seu programa com baixa taxade erro.

19

Page 20: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

5.3 Exemplo de carregar rede já treinada para fazer predição

O programa abaixo mostra como carregar uma rede já treinada para fazer predição.

123456789

1011121314151617181920212223

#pred1.pyimport tensorflow.keras as kerasfrom keras.datasets import mnistfrom keras.models import load_modelfrom keras.utils import to_categoricalimport os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'

(_,_), (QX, QY) = mnist.load_data()QX=255-QX

nclasses = 10QY2 = keras.utils.to_categorical(QY, nclasses)nl, nc = QX.shape[1], QX.shape[2] #28, 28QX = QX.astype('float32') / 255.0 # 0 a 1

model=load_model('mlp2.h5')

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

QP = model.predict(QX)QP = QP.argmax(axis=-1)

Programa 6: Lê modelo já treinado e faz predição.

Referências:

[Mazur] http://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/

[Nielsen] http://neuralnetworksanddeeplearning.com/

[WikiRelu] https://en.wikipedia.org/wiki/Rectifier_(neural_networks)

[Optimizers] https://mlfromscratch.com/optimizers-explained/#/

[WikiSoftmax] https://en.wikipedia.org/wiki/Softmax_function

20

Page 21: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Anexo A: Algumas definições matemáticas

A.1 Inicialização dos pesos e vieses

Cada vez que roda um programa Keras, resulta numa taxa de erro um pouco diferente, pois os pesose vieses são inicializados aleatoriamente.

O inicializador default de Keras é (para maioria das camadas) glorot_uniform ou Xavier uniform.Do manual do Keras:

keras.initializers.glorot_uniform(seed=None)Glorot uniform initializer, also called Xavier uniform initializer.

It draws samples from a uniform distribution within [-limit, limit] where limit is sqrt(6 /(fan_in + fan_out)) where fan_in is the number of input units in the weight tensor and fan_outis the number of output units in the weight tensor.

Arguments seed: A Python integer. Used to seed the random generator.

A.2 Sigmoide

A função de ativação “sigmoid” ou “logistic” é definida como:

sigmoid (x)=1

1+e− x

e o seu gráfico está na figura abaixo.

Figura: Função logística sigmoide [extraída da Wikipedia]. A saída vai de 0 a 1.

21

Page 22: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A.3 ReLU

ReLU (rectified linear unit) é uma função de ativação introduzida no ano 2000 e é a função de ati-vação mais popular em 2017 [WikiRelu]. Foi demonstrada em 2011 que permite melhor treinamen-to de redes profundas. A sua definição é:

f (x)=max(0 , x)

Parece a função de transferência VxI de um diodo ideal.

Curva relu (rectified linear unit) em azul.

A grande vantagem desta função de ativação é a propagação eficiente de gradiente: minimiza pro-blema de “vanishing or exploding gradient” (veja mais detalhes no livro [Nielsen]). Note que a deri-vada da relu é zero ou um, o que ajuda a evitar que gradiente exploda ou desapareça.

22

Page 23: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A.4 Softmax

A função softmax, também conhecido como softargmax ou normalized exponential function, é umafunção que pega como entrada um vetor de K números reais e normaliza-o em distribuição de prob-abilidade com K probabilidades. Após aplicar a função softmax, cada componente do vetor estará nointervalo (0,1) e a soma dos componentes será 1, de forma que eles podem ser interpretados comoprobabilidades. Além disso, componentes de entrada maiores irão corresponder a probabilidadesmaiores.

A função softmax padrão σ :ℝK→ℝ

K é definida como:

σ( z)i=e zi

∑j=1

K

ez j

Exemplo numérico:

Vetor de entrada z=(-0.1, 1.3, 0.3)

Calculando a soma dos exp’s: ∑j=1

K

ez j=e−0.1+e1.3

+e0.2=5.7955

Calculando as saídas:

σ( z)1=e−0.1

5.7955=0.15613

σ( z)2=e1.3

5.7955=0.63313

σ( z)3=e0.2

5.7955=0.21075

Assim:σ(−0.1,1.3,0.3)=(0.15613,0.63313,0.21075)

23

Page 24: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A.5 Cross-entropy loss:

Vou seguir a explicação de:https://gombru.github.io/2018/05/23/cross_entropy_loss/ https://ml-cheatsheet.readthedocs.io/en/latest/loss_functions.html

Primeiro, vamos distinguir três tipos de problemas de classificação: binária, multi-class e multi-label. Problema binária ou booleana consiste em classificar instâncias em 2 grupos, por exemplo,câncer ou não-câncer. As definições de multi-class e multi-label ficam evidentes pela figura abaixo.

Figura de [https://gombru.github.io/2018/05/23/cross_entropy_loss/]

Cross-entropy loss L é definida como:

L( p , y )=−∑i=1

K

log( pi) y i , sendo log natural.

onde yi e pi são respectivamente o rótulo verdadeiro de uma instância x e saída fornecida pela rede processando x para cada classe i de K.

Exemplo de cross-entropy para “multi-label classification”: p=(0.4, 0.8, 0.6) y=(0, 1, 1) L(p,y) = -log(0.8) -log(0.6) = 0.734

Em “multi-class classification”, y contém um único componente 1, sendo o resto 0 (chamado “one-hot” labels). Assim, a equação acima torna-se:

L( p , y )=− log p i[ y i=1] .

Exemplo de cross-entropy para “multi-class classification”: p=(0.1, 0.8, 0.1) y=(0, 1, 0) L(p,y) = -log(0.8) = 0.22314

24

Page 25: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A.6 Categorical Cross-Entropy Loss

É a ativação softmax seguida pelo cross-entropy loss. É normalmente usado em “multi-class classi-fication”.

Exemplo: p=(0.4, 0.8, 0.6) y=(0, 1, 0) Calculando softmax(p,y):e1 = exp(0.4) = 1.4918e2 = exp(0.8) = 2.2255e3 = exp(0.6) = 1.8221soma = e1+e2+e3 = 5.5395s1 = a1/soma = 0.26931s2 = a2/soma = 0.40176s3 = a3/soma = 0.32893softmax(p,y) = (0.269, 0.402, 0.329)

Portanto:categorical_cross_entropy(p,y) = -log(0.402) = 0.91130

PyTorch chama esta função de CrossEntropyLoss (sem a palavra “categorical”) e internamente cal-cula softmax e cross-entropy:

torch.nn.CrossEntropyLoss.

import torchp = torch.tensor([[0.4, 0.8, 0.6]]); print("p=",p)y = torch.tensor([1]); print("y=",y)loss = torch.nn.CrossEntropyLoss(); L = loss(p, y); print("L=",L)

Saída:p= tensor([[0.4000, 0.8000, 0.6000]])y= tensor([1])L= tensor(0.9119)

Keras chama esta função de CategoricalCrossentropy. keras.losses.CategoricalCrossentropy(from_logits=False)

Por default, from_logits=False e a função não calcula internamente softmax. Colocando from_lo-gits=True, a função irá calcular softmax antes de cross-entropy, e a função ficará igual à definição eà da PyTorch.

Esta função exige y em formato “categórico” (ex: [0, 0, 1, 0]). Se quiser fornecer y em formato “ró-tulo” (ex: [2]), use a função SparseCategoricalCrossentropy.

import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'; import keras

y = [[0.0, 1.0, 0.0]]; print("y=",y)p = [[0.4, 0.8, 0.6]]; print("p=",p)loss = keras.losses.CategoricalCrossentropy(from_logits=True)L=loss(y,p).numpy(); print("from_logits=True L=",L)loss = keras.losses.CategoricalCrossentropy(from_logits=False)L=loss(y,p).numpy(); print("from_logits=False L=",L)

y = [1]; print("y=",y)p = [[0.4, 0.8, 0.6]]; print("p=",p)loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True)L=loss(y, p).numpy(); print("L=",L)

Saída:y= [[0.0, 1.0, 0.0]]p= [[0.4, 0.8, 0.6]]from_logits=True L= 0.9119015from_logits=False L= 0.8109302y= [1]p= [[0.4, 0.8, 0.6]]L= 0.9119015

25

Page 26: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A.7 Binary Cross-Entropy Loss

Esta função é utilizada para problemas de classificação binária e multi-label classification [https://stats.s-tackexchange.com/questions/260505/should-i-use-a-categorical-cross-entropy-or-binary-cross-entropy-loss-for-binary#:~:text=Binary%20cross%2Dentropy%20is%20for,belongs%20to%20a%20sin-gle%20class].

Definiçao para classificação binária: L( p , y )=−( y log p+(1− y) log(1−p))

Exemplo de classificação binária: Considere que, dada uma mamografia x, um programa devolveua probabilidade de p=0.7 da paciente ter câncer. Suponha que a paciente na verdade tem câncer, istoé, y=1. Neste caso,

L( p , y )=− log p i=0.3567

Exemplo de classificação binária: Considere que, dada uma mamografia, um programa devolve nú-meros negativos se tem pouca probabilidade de ter câncer e devolve números positivos se há muitaprobabilidade de ter câncer. Dada uma mamografia x, o programa devolveu número s=-2. Este nú-mero deve ser convertido para um número entre 0 e 1, para que fique “parecido com probabilidade”.Para isso, costuma utilizar a função sigmoide:

p = sigmoide(s) = sigmoide(-2) = 0.1192Suponha que a paciente na verdade não tem câncer, isto é, y=0. Neste caso:

L( p , y )=−log(1−pi)=0.1269

Definiçao para K multi-label classificação:

L( p , y )=−1K ∑i=1

Ky i log p i+(1− y i) log(1−pi)

Exemplo de multi-label classification: Considere que um programa identifica se numa imagem háavião, navio, automóvel e bicicleta. Dada uma imagem x, o programa devolveu a saída s=[-2, -1, 2,3], indicando que é pouco provável que haja avião e navio na imagem, mas é provável que haja au-tomóvel e bicicleta. Os elementos deste vetor devem ser convertidos em números entre 0 e 1, paraque se tornem uma espécie de “probabilidade”. Para isso, utiliza-se a função sigmoide:

p = sigmoide(s) = sigmoide([-2, -1, 2, 3]) = [0.119, 0.269, 0.881, 0.9526]

Suponha que os rótulos verdadeiros são y=[0, 0, 1, 1]. Agora, é possível aplicar binary cross-entropy loss a cada elemento de p:

BCE(p, y) = [0.1269, 0.3133, 0.1269, 0.0486]E é possível calcular a média dos elementos, obtendo:

L(p, y) = 0.1539

Exemplo em PyTorch:import torchs = torch.tensor([-2, -1, 2, 3], dtype=torch.float32)y = torch.tensor([0, 0, 1, 1], dtype=torch.float32)ativacao = torch.nn.Sigmoid(); p=ativacao(s); print("p=",p.numpy())loss = torch.nn.BCELoss(); L = loss(p, y); print("L=",L.numpy())

Saída:p= [0.11920292 0.26894143 0.880797 0.95257413]L= 0.15392625

26

Page 27: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Exemplo em Keras:

import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'import keras; import numpy as nps = np.array([-2, -1, 2, 3],dtype=np.float32)y = np.array([0, 0, 1, 1],dtype=np.float32)p = keras.activations.sigmoid(s); print("p=",p.numpy())loss = keras.losses.BinaryCrossentropy(from_logits=False)L = loss(y,p); print("L=",L.numpy())loss = keras.losses.BinaryCrossentropy(from_logits=True)L = loss(y,s); print("L=",L.numpy())

Saída:p= [0.11920292 0.26894143 0.880797 0.95257413]L= 0.15392613L= 0.15392627

27

Page 28: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Anexo B: Outras dicas sobre Google Colab

Descarregar arquivos de internet para Google Colab

a) É possível pegar um arquivo da internet e gravar no diretório de Colab usando o comando wget[https://linuxize.com/post/wget-command-examples/ ]:

!wget [opções] url

O comando acima faz download do arquivo especificado em url no diretório atual. Por exemplo:!wget https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png

baixa imagem Lenna_(test_image).png do site Wikipedia. Vários sites, incluindo muitos sites daUSP, bloqueiam download via wget. É possível contornar este problema especificando a opção “--user-agent” ou “-U”, emulando a requisição por um aplicativo diferente. O comando abaixo emula arequisição de download por Firefox 50.0, contornando o bloqueio:

!wget -U 'Firefox/50.0' 'http://www.lps.usp.br/hae/apostila/hummingbird.jpg'

O programa abaixo descarrega a imagem hummingbird.jpg do meu site no diretório /content do Co-lab (se a imagem já não estiver lá) e mostra-a na tela. Pode ser executado do Colab ou de bash:

#Funciona chamando python3 em bash ou Colaburl="http://www.lps.usp.br/hae/apostila/hummingbird.jpg"import os; nomeArq=os.path.split(url)[1]if not os.path.exists(nomeArq): os.system("wget -U 'Firefox/50.0' "+url)from matplotlib import pyplot as plta=plt.imread(nomeArq)plt.imshow(a); plt.axis("off"); plt.show()

b) Normalmente, é muito mais rápido transferir um arquivo grande do que vários arquivos peque-nos. Assim, se você precisa transferir um banco de dados com muitas imagens, é melhor transferir oarquivo compactado (por exemplo, como .zip) e descompactar no Colab. O programa abaixo trans-fere BD feiCorCorp com 400 imagens compactadas para diretório local da máquina Colab e o des-compacta.

nomeDir="/content/feiCorCrop"url="http://www.lps.usp.br/hae/apostila/feiCorCrop.zip"nomeZip=os.path.split(url)[1]import osif not os.path.exists(nomeDir): os.mkdir(nomeDir)prevDir=os.getcwd(); os.chdir(nomeDir)if not os.path.exists(nomeZip): st="wget -U 'Firefox/50.0' "+url os.system(st)os.system("unzip -u "+nomeZip) os.chdir(prevDir)

28

Page 29: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

c) Se você precisa trabalhar com base de dados (BD) com muitos arquivos em Colab, ficam lentasambas as opções a seguir: (1) baixar BD da internet frequentemente; (b) transferir muitos arquivosdo Google Drive para diretório local da máquina Colab. A solução é compactar todos os arquivosnum grande arquivo BD.zip e deixá-lo no Google Drive. Toda vez que precisar, transfere-se BD.zipdo Google Drive para um diretório local da máquina Colab e o descompacta:

# Montar drive Colabfrom google.colab import drivedrive.mount('/content/drive')

# criar diretorio local na maquina Colab!mkdir my_dir%cd my_dir/

# Copiar BD!cp '/content/drive/MyDrive/BD.zip' .

# Descompactar BD!unzip BD.zip

29

Page 30: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Anexo P: Programas em PyTorch

Este anexo não está terminada. Está sendo elaborada.

P1. Introdução

Como vimos, Keras é uma biblioteca de alto nível que permite criar aplicações rapidamente. Comoo código é muito sintético, não é possível executar tarefas “diferentes” daquelas pré-programadas.PyTorch, por outro lado, é uma biblioteca de baixo nível onde é necessário escrever explicitamentecada passo de execução. Isto torna o programa mais longo, mas é possível fazer tarefas “diferentes”das padronizadas. Por exemplo, com o único comando abaixo de Keras faz retro-propagação:

model.fit(AX, AY, epochs=1000)

Isto é bom, pois agiliza desenvolver programas. O problema é que não há uma forma direta de visu-alizar o que está acontecendo com rede neural durante o treino, nem alterar a forma como são feitosos cálculos. O comando equivalente de PyTorch: for i in range(1000): optimizer.zero_grad() AP = net(AX) loss = criterion(AP, AY) loss.backward() optimizer.step()

permite acessar os resultados intermediários e, se necessário, modificá-los.

Se o computador tiver GPU e as bibliotecas corretas estiverem instaladas, Keras vai usar automati-camente GPU para acelerar o processamento. Em PyTorch, o programador deve instruir se cada va-riável vai ficar em CPU ou GPU, e transferir explicitamente o conteúdo das variáveis de CPU paraGPU e vice-versa. Fazer tudo automaticamente tem a vantagem de ser mais simples. Mas às vezesqueremos controlar explicitamente em qual dispositivo cada variável vai ficar, principalmente quan-do GPU não tiver memória suficiente.

Uma desvantagem grande de PyTorch em relação a Keras/Tensorflow, neste momento, é a sua difi-culdade em usar TPU (tensor processing unit) da Google. Keras consegue utilizar TPU facilmente,pois tanto Keras/Tensorflow quanto TPU são desenvolvidos pela Google. TPU costuma ter quanti-dade de memória muito maior (tipo 64-128 GB) do que GPU (tipo 8-16 GB). PyTorch não conse-gue utilizar (ainda) TPU facilmente.

30

Page 31: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P2. Regressão em PyTorch

A tradução do programa 1 para PyTorch está no programa P1.

12345678910111213141516171819202122232425262728293031323334

# -*- coding: utf-8 -*-""" regression2.py - pytorch - baseado em:- https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html- https://towardsdatascience.com/handwritten-digit-mnist-pytorch-977b5338e627"""

import torchimport torch.nn as nnimport torch.nn.functional as Fimport numpy as npimport torch.optim as optim

net = nn.Sequential( nn.Linear(2, 2), nn.Sigmoid(), nn.Linear(2, 2), nn.Sigmoid())print(net)

AX = torch.from_numpy( np.matrix('0.9 0.1; 0.1 0.9',dtype='float32') )AY = torch.from_numpy( np.matrix('0.1 0.9; 0.9 0.1',dtype='float32') )criterion = nn.MSELoss()optimizer = optim.SGD(net.parameters(), lr=1)

for i in range(1000): optimizer.zero_grad() # zero the gradient buffers AP = net(AX); loss = criterion(AP, AY) loss.backward(); optimizer.step()

QX = torch.from_numpy( np.matrix('0.9 0.1; 0.1 0.9; 0.8 0.0; 0.2 0.9',dtype='float32') ); with torch.no_grad(): net.eval() QP = net(QX) print(QP.detach().numpy())

Programa P1: Regression2.py em PyTorch.

A estrutura da rede é definida pelo método Sequential (linhas 13-18). O código de treino que era umúnico comando “model.fit” em Keras torna-se um loop com vários comandos (linhas 25-28). A li-nha 18 imprime a estrutura da rede.

PyTorch trabalha com tensores próprios. Assim, é necessário converter matrizes NumPy para tenso-res PyTorch (linhas 20-21 e 30). E também converter tensor do PyTorch para NumPy (linha 34):detach() retira do tensor PyTorch as informações que permitem fazer retro-propagação, ficando so-mente com o tensor. Método numpy() faz conversão de tensor PyTorch para formato NumPy.

Para acelerar a predição, “with torch.no_grad()” (linha 31) desliga o cálculo dos gradientes. O co-mando “net.eval()” (linha 32) faz a rede entrar no modo de predição, pois algumas camadas funcio-nam de forma diferente no treino e na predição.

Saída do programa P1 em PyTorch:

Sequential( (0): Linear(in_features=2, out_features=2, bias=True) (1): Sigmoid() (2): Linear(in_features=2, out_features=2, bias=True) (3): Sigmoid())[[0.1120, 0.8883], [0.8829, 0.1167], [0.1114, 0.8896], [0.8751, 0.1248]]

Saída do programa 1 Keras:

(...)[[0.10639106 0.89681536] [0.89438605 0.10273475] [0.11006932 0.8937683 ] [0.8765248 0.12138095]]

Os resultados de PyTorch e Keras são praticamente idênticos. Dão resultados um pouco diferentespois os pesos são inicializados aleatoriamente.

31

Page 32: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P3. Classificação em adulto, bebê e criança em PyTorch

O programa 2 traduzido para PyTorch está em programa P2:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950525354

# -*- coding: utf-8 -*-"""abc1.py - Baseado em:- https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html"""import torchimport torch.nn as nnimport torch.optim as optimimport numpy as npimport sys

class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(1, 3) self.fc2 = nn.Linear(3, 3) def forward(self, x): x = torch.sigmoid(self.fc1(x)) x = torch.sigmoid(self.fc2(x)) return x

def acuracidade(p, y): p2=torch.argmax(p, 1); y2=torch.argmax(y, 1) soma = (p2==y2).sum() return soma

#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<net = Net()AX = torch.from_numpy( np.matrix('4; 15; 65; 5; 18; 70',dtype='float32') ); AX = AX/100AY = torch.from_numpy( np.matrix('0 1 0; 0 0 1; 1 0 0; 0 1 0; 0 0 1; 1 0 0',dtype='float32') )criterion = nn.MSELoss()

optimizer = optim.SGD(net.parameters(), lr=10)batch_size=2; epochs=500for i in range(epochs): net.train() indices = torch.randperm(AX.shape[0]) for j in range(AX.shape[0]//batch_size): indices2=indices[batch_size*j:batch_size*(j+1)] ax=AX[indices2]; ay=AY[indices2] optimizer.zero_grad() # zero the gradient buffers ap = net(ax) loss = criterion(ap, ay); loss.backward(); optimizer.step() if i%50==0: with torch.no_grad(): net.eval(); AP=net(AX) loss=criterion(AP,AY).detach().numpy() ac=acuracidade(AP,AY).numpy()/AY.shape[0] print("iteracao=%3d MSE=%6.4f acurac=%3.2f%%"%(i,loss,100*ac))

QX = torch.from_numpy( np.matrix('16; 3; 75',dtype='float32') ); QX=QX/100with torch.no_grad(): net.eval(); QP = net(QX)print(QP.detach().numpy())

Programa P2: Resolução do problema ABC em PyTorch. Nota: Não se pode chamar o programa de“abc.py”, pois parece que “abc” é uma palavra reservada em Python.

A rede tem 3 saídas (para uma saída para cada categoria A, B e C). Assim, para poder calcular ataxa de acerto, deve calcular argmax (o índice do neurônio de saída com a maior resposta) e verifi-car se os índices desejado e obtido são iguais. Para isso, foi escrita a função acuracidade (linhas 21-24).

A rede recebe 6 exemplos de treinamento (AX e AY). Esses 6 exemplos são divididos aleatoria-mente em 3 batches de 2 exemplos cada. Linha 35 gera índices aleatórios. Linhas 37-38 pegam 2exemplos aleatórios em cada batch. Linhas 42-47 imprimem o progresso do treino a cada 50 épocas.

Os comandos “with torch.no_grad()” e “net.eval()” fazem entrar a rede no modo de predição. O co-mando “net.train()” faz a rede entrar no modo de treino.

32

Page 33: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

A saída obtida em PyTorch é:

(...)[[6.1053205e-03 8.8202953e-02 8.4803396e-01] [3.3946228e-04 9.5721781e-01 5.3885687e-02] [9.8553991e-01 8.2046314e-10 7.2643034e-02]]

A saída obtida em Keras é:

(...) [[2.0841250e-02 3.5288446e-02 9.5049566e-01] [3.2123618e-04 9.8374093e-01 1.9736269e-02] [9.8454732e-01 1.4877369e-06 1.9679543e-02]](...)

Os resultados das duas redes são bem semelhantes.

33

Page 34: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P4. Leitura de MNIST em PyTorch

P4.1 Leitura de MNIST como tensor

O programa P3a mostra como ler MNIST como tensores NumPy em PyTorch. A função data-sets.MNIST faz a leitura. O parâmetro root indica o diretório onde ficará armazenada o BD. Após aleitura, A.data e Q.data contêm as imagens e A.targets e Q.targets contém os rótulos (0 a 9).

123456789101112131415161718192021222324252627

# -*- coding: utf-8 -*-"""mnist1.py- https://www.aiworkbox.com/lessons/load-mnist-dataset-from-pytorch-torchvision """import numpy as npimport torchimport torchvisionimport torchvision.datasets as datasetsimport matplotlib.pyplot as plt

A = datasets.MNIST(root='/home/hae/deep/torch/data', train=True, transform=None, download=True)Q = datasets.MNIST(root='/home/hae/deep/torch/data', train=False, transform=None, download=True)

AX=255-np.array(A.data)AY=np.array(A.targets)print(AX.shape,AX.dtype,AY.shape,AY.dtype)QX=255-np.array(Q.data)QY=np.array(Q.targets)print(QX.shape,QX.dtype,QY.shape,QY.dtype)

nl=3; nc=4fig = plt.figure()for i in range(nc*nl): plt.subplot(nl, nc, i+1); plt.axis('off') plt.imshow(AX[i],cmap='gray')fig.suptitle('MNIST Dataset - preview')plt.show()

Programa P3a: Leitura de MNIST em PyTorch.

Saída:

(60000, 28, 28) uint8 (60000,) int64(10000, 28, 28) uint8 (10000,) int64

34

Page 35: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P4.2 Leitura de MNIST usando DataLoader

O programa P3b mostra como ler MNIST usando DataLoader, que é a forma padrão para trabalhar com ima-gens em PyTorch. Após fazer a leitura com datasets.MNIST (linhas 16 e 20), a função torch.utils.data.Dat-aLoader cria DataLoader que irá retornar exemplos de treinamento do tamanho batch_size embaralhados ounão (linhas 17 e 21). Para pegar um batch, deve criar um iterator (linhas 18 e 22) e iterar usando next() (linha28).

1234567891011121314151617181920212223242526272829303132

# -*- coding: utf-8 -*-#mnist2.pyimport numpy as npimport torchimport torchvisionfrom torchvision import datasets, transformsimport matplotlib.pyplot as pltimport sys

#output[channel] = (input[channel] - mean[channel]) / std[channel]#As imagens vão de 0 a 1. Subtrair 1 e dividir por -1 faz trocar preto com branco.transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((1.0,), (-1.0,)), ] ) A = datasets.MNIST('/home/hae/deep/torch/data', download=True, train=True, transform=transform)Aloader = torch.utils.data.DataLoader(A, batch_size=1, shuffle=False)Aiter=iter(Aloader)

Q = datasets.MNIST('/home/hae/deep/torch/data', download=True, train=False, transform=transform)Qloader = torch.utils.data.DataLoader(Q, batch_size=1, shuffle=False)Qiter=iter(Qloader)

nl=3; nc=4fig = plt.figure()for i in range(nc*nl): plt.subplot(nl, nc, i+1); plt.axis('off') AX,_=Aiter.next() # ou AX,_=next(Aiter) AX=AX.squeeze() plt.imshow(AX,cmap='gray',vmin=0,vmax=1)fig.suptitle('MNIST Dataset carregado usando DataLoader')plt.savefig("mnist2.png")plt.show()

Programa 3b: Leitura de MNIST em PyTorch usando DataLoader.

35

Page 36: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P5. Classificação de MNIST em PyTorch usando rede neural densa

P5.1a Primeiro programa de rede neural densa em CPU (usando MSE e sem usar DataLoader)

O programa 4 traduzido para PyTorch está no programa P4a

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

# -*- coding: utf-8 -*-"""mlp1.py- https://www.aiworkbox.com/lessons/load-mnist-dataset-from-pytorch-torchvision- https://colab.research.google.com/drive/1db-E6mWSrphqI-IMwYajBDxNHyDEjpQ1#scrollTo=XCsoAdjdLjPb- http://datahacker.rs/005-pytorch-convolutional-neural-network-on-mnist-in-pytorch/- https://stackoverflow.com/questions/55627780/evaluating-pytorch-models-with-torch-no-grad-vs-model-eval"""import numpy as npimport torch; import torch.nn as nnimport torch.optim as optimimport torchvision; import torchvision.datasets as datasetsimport matplotlib.pyplot as pltfrom time import time

#<<<<<<<<<<<<<<<<<<<<<<<<<<<class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(nl*nc, 400) self.fc2 = nn.Linear(400, nclasses) def forward(self, x): x = torch.flatten(x, 1) x = torch.sigmoid(self.fc1(x)) x = torch.sigmoid(self.fc2(x)) return x

def to_categorical(y, nclasses): return np.eye(nclasses, dtype='float32')[y]

def acuracidade(p, y): p2=torch.argmax(p, 1); y2=torch.argmax(y, 1) soma = (p2==y2).sum() return soma

#<<<<<<<<<<<<<<<<<<<<<<<<<<<A = datasets.MNIST(root="/home/hae/deep/torch/data", train=True, transform=None, download=True)Q = datasets.MNIST(root="/home/hae/deep/torch/data", train=False, transform=None, download=True)

AX=(255-A.data)/255.0; AY=A.targetsQX=(255-Q.data)/255.0; QY=Q.targetsnl, nc = AX.shape[1], AX.shape[2] #28, 28nclasses=10AY2=to_categorical(AY, nclasses); AY2=torch.from_numpy(AY2)QY2=to_categorical(QY, nclasses); QY2=torch.from_numpy(QY2)

net=Net(); criterion=nn.MSELoss()optimizer=optim.Adam(net.parameters())batch_size=100; epochs=40

tempo0=time()for i in range(epochs): net.train() indices = torch.randperm(AX.shape[0]) for j in range(AX.shape[0]//batch_size): #batch_size de 100 batchIndices=indices[batch_size*j:batch_size*(j+1)] optimizer.zero_grad() ax=AX[batchIndices]; ay2=AY2[batchIndices] ap2=net(ax) loss=criterion(ap2, ay2); loss.backward(); optimizer.step() if (i+1)%5==0: with torch.no_grad(): net.eval(); AP2=net(AX) lossTotal=criterion(AP2,AY2).cpu().detach().numpy() ac=acuracidade(AP2,AY2).cpu().numpy()/AY2.shape[0] print("iteracao=%3d train_MSE=%6.4f train_acc=%3.2f%%"%(i+1,lossTotal,100*ac))tempo1=time(); print("Tempo de treino=%fs"%(tempo1-tempo0))

with torch.no_grad(): net.eval(); QP2=net(QX) lossTotal=criterion(QP2,QY2).detach().numpy() ac=acuracidade(QP2,QY2).numpy()/QY2.shape[0] print("Desempenho nos dados de teste:") print("Test_MSE=%6.4f test_acc=%3.2f%%"%(lossTotal,100*ac))

torch.save(net.state_dict(), 'mlp1.pth')

Programa P4a: Classificação de MNIST com rede neural densa em PyTorch.

36

Page 37: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

PyTorch não tem função pronta equivalente a função to_categorical do Keras. Relembrando, estafunção converte:

5 (com nclasses=10) para [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]

Ela foi implementada nas linhas 27-28.

A função que calcula a acuracidade entre duas matrizes com nclasses colunas está nas linhas 30-34.

A linha 72 mostra como salvar a rede PyTorch. PyTorch não permite salvar a rede toda, mas so-mente o seu estado.

Saída PyTorch:

iteracao= 5 train_MSE=0.0110 train_acc=93.86%iteracao= 10 train_MSE=0.0071 train_acc=96.18%iteracao= 15 train_MSE=0.0051 train_acc=97.27%iteracao= 20 train_MSE=0.0043 train_acc=97.79%iteracao= 25 train_MSE=0.0039 train_acc=98.07%iteracao= 30 train_MSE=0.0030 train_acc=98.56%iteracao= 35 train_MSE=0.0027 train_acc=98.68%iteracao= 40 train_MSE=0.0024 train_acc=98.89%Tempo de treino=40.856250sDesempenho nos dados de teste:Test_MSE=0.0043 test_acc=97.47%

Saída Keras:

Epoch 1/40 - 2s 39us/step - loss: 0.0448 - acc: 0.7178Epoch 2/40 - 1s 22us/step - loss: 0.0191 - acc: 0.8928(...)Epoch 39/40 - 1s 22us/step - loss: 0.0024 - acc: 0.9889Epoch 40/40 - 1s 22us/step - loss: 0.0024 - acc: 0.9890Test loss: 0.004075948440702632Test accuracy: 0.9775

As duas saídas são muito parecidas. PyTorch demorou 40s.

37

Page 38: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P5.1b Primeiro programa de rede neural densa em GPU (usando MSE e sem usar DataLoader)

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596

# -*- coding: utf-8 -*-"""mlp1c.py- https://www.aiworkbox.com/lessons/load-mnist-dataset-from-pytorch-torchvision- https://colab.research.google.com/drive/1db-E6mWSrphqI-IMwYajBDxNHyDEjpQ1#scrollTo=XCsoAdjdLjPb- http://datahacker.rs/005-pytorch-convolutional-neural-network-on-mnist-in-pytorch/- https://stackoverflow.com/questions/55627780/evaluating-pytorch-models-with-torch-no-grad-vs-model-eval- https://stackoverflow.com/questions/58216000/get-total-amount-of-free-gpu-memory-and-available-using-pytorch"""import numpy as npimport torch; import torch.nn as nn; import torch.cuda as cudaimport torch.optim as optimimport torchvision; import torchvision.datasets as datasetsimport matplotlib.pyplot as pltfrom time import time

#<<<<<<<<<<<<<<<<<<<<<<<<<<<class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(nl*nc, 400) self.fc2 = nn.Linear(400, nclasses) def forward(self, x): x = torch.flatten(x, 1) x = torch.sigmoid(self.fc1(x)) x = torch.sigmoid(self.fc2(x)) return x

def to_categorical(y, nclasses): return np.eye(nclasses, dtype='float32')[y]

def acuracidade(p, y): p2=torch.argmax(p, 1); y2=torch.argmax(y, 1) soma = (p2==y2).sum() return soma

from pynvml import *nvmlInit()h = nvmlDeviceGetHandleByIndex(0)def imp_gpu_mem(ponto): info = nvmlDeviceGetMemoryInfo(h) print('[{0}] total={1:,} free={2:,} used={3:,}'. format(ponto, info.total, info.free, info.used) )

#<<<<<<<<<<<<<<<<<<<<<<<<<<<device = 'cuda' if torch.cuda.is_available() else 'cpu'; print("Device=",device)A = datasets.MNIST(root="/home/hae/deep/torch/data", train=True, transform=None, download=True)Q = datasets.MNIST(root="/home/hae/deep/torch/data", train=False, transform=None, download=True)

AX=(255-A.data)/255.0; AY=A.targetsQX=(255-Q.data)/255.0; QY=Q.targetsnl, nc = AX.shape[1], AX.shape[2] #28, 28nclasses=10AY2=to_categorical(AY, nclasses); AY2=torch.from_numpy(AY2)QY2=to_categorical(QY, nclasses); QY2=torch.from_numpy(QY2)

imp_gpu_mem("P1")net=Net(); net.to(device); #net esta em GPUcriterion=nn.MSELoss()

optimizer=optim.Adam(net.parameters())batch_size=100; epochs=40

tempo0=time()AX=AX.to(device); AY2=AY2.to(device) #AX e AY2 estao em GPUfor i in range(epochs): net.train() indices = torch.randperm(AX.shape[0]) for j in range(AX.shape[0]//batch_size): #batch_size de 100 batchIndices=indices[batch_size*j:batch_size*(j+1)] optimizer.zero_grad() ax=AX[batchIndices]; ay2=AY2[batchIndices] #ax e ay2 estao em GPU ap2=net(ax) #ap2 esta em GPU loss=criterion(ap2, ay2); loss.backward(); optimizer.step() if (i+1)%5==0: with torch.no_grad(): net.eval(); AP2=net(AX) lossTotal=criterion(AP2,AY2).cpu().detach().numpy() ac=acuracidade(AP2,AY2).cpu().numpy()/AY2.shape[0] print("iteracao=%3d train_MSE=%6.4f train_acc=%3.2f%%"%(i+1,lossTotal,100*ac))tempo1=time(); print("Tempo de treino=%fs"%(tempo1-tempo0))imp_gpu_mem("P2")del AX, AY2, indices, batchIndices, ax, ay2, ap2, AP2; torch.cuda.empty_cache()imp_gpu_mem("P3")

with torch.no_grad(): net.eval(); QX=QX.to(device); QY2=QY2.to(device) #QX e QY2 estao em GPU QP2=net(QX) #QP2 esta em GPU QP2=QP2.cpu(); QY2=QY2.cpu() #QP2 e QY2 estao em CPU lossTotal=criterion(QP2,QY2).detach().numpy() ac=acuracidade(QP2,QY2).numpy()/QY2.shape[0]print("Test_MSE=%6.4f test_acc=%3.2f%%"%(lossTotal,100*ac))torch.save(net.state_dict(), 'mlp1.pth')imp_gpu_mem("P4")del QX, QY2, QP2, net; torch.cuda.empty_cache()imp_gpu_mem("P5")

Programa P4b: Classificação de MNIST com rede neural densa em PyTorch, para GPU.

38

Page 39: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

Em PyTorch, programa para CPU e GPU podem não ser iguais. O programa P4b mostra a versãopara GPU (que também poderia rodar em CPU).

Saída:

Device= cuda[P1] total=6,220,873,728 free=5,743,509,504 used=477,364,224iteracao= 5 train_MSE=0.0109 train_acc=93.68%iteracao= 10 train_MSE=0.0069 train_acc=96.13%iteracao= 15 train_MSE=0.0051 train_acc=97.26%iteracao= 20 train_MSE=0.0041 train_acc=97.84%iteracao= 25 train_MSE=0.0033 train_acc=98.36%iteracao= 30 train_MSE=0.0029 train_acc=98.56%iteracao= 35 train_MSE=0.0026 train_acc=98.81%iteracao= 40 train_MSE=0.0030 train_acc=98.66%Tempo de treino=21.868091s[P2] total=6,220,873,728 free=4,362,534,912 used=1,858,338,816[P3] total=6,220,873,728 free=4,746,313,728 used=1,474,560,000Test_MSE=0.0047 test_acc=97.50%[P4] total=6,220,873,728 free=4,681,302,016 used=1,539,571,712[P5] total=6,220,873,728 free=4,746,313,728 used=1,474,560,000

A função imp_gpu_mem mostra o estado de memória do GPU. Para isso, deve instalar:pip3 install pynvml

É possível apagar as variáveis do GPU, liberando mais memória, com o comando “del” seguido por“torch.cuda.empty_cache()”. Porém, não é recomendado fazer isso frequentemente, pois pode dei-xar o programa mais lento.

39

Page 40: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P5.2 Segundo programa de rede neural densa em GPU (usando CrossEntropy e sem usar DataLoa-der)

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677

# -*- coding: utf-8 -*-"""mlp3.py- https://www.aiworkbox.com/lessons/load-mnist-dataset-from-pytorch-torchvision- https://pytorch.org/tutorials/beginner/saving_loading_models.html- https://cnvrg.io/pytorch-cuda/?gclid=Cj0KCQiApY6BBhCsARIsAOI_GjaawBAcn04Rb2IaGCmsJfZ6QOrer_4cHpaJ9gbbA3ngmNIdQkSuuiYaAi-OREALw_wcB"""import numpy as npimport torch; import torch.nn as nn; import torch.optim as optimimport torchvision; import torchvision.datasets as datasetsimport matplotlib.pyplot as pltfrom time import time

#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(nl*nc, 400) self.fc2 = nn.Linear(400, 100) self.fc3 = nn.Linear(100, nclasses) def forward(self, x): x = torch.flatten(x, 1) x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) #Ou usar "x=torch.log_softmax(self.fc3(x),dim=1)" com "criterion=nn.NLLLoss()" return x

def acuracidade(p, y): p2=torch.argmax(p, 1) soma = (p2==y).sum() #Repare que compara p2 com y return soma

#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu'); print(DEVICE)A = datasets.MNIST(root='/home/hae/deep/torch/data', train=True, transform=None, download=True)Q = datasets.MNIST(root='/home/hae/deep/torch/data', train=False, transform=None, download=True)

AX=(255-A.data)/255.0; AY=A.targetsQX=(255-Q.data)/255.0; QY=Q.targetsnl, nc = AX.shape[1], AX.shape[2] #28, 28nclasses=10

net = Net(); net.to(DEVICE)criterion = nn.CrossEntropyLoss() #Ou usar "criterion=nn.NLLLoss()" com log_softmaxoptimizer = optim.Adam(net.parameters())batch_size=100; epochs=160

tempo0=time()AX=AX.to(DEVICE); AY=AY.to(DEVICE); #AX e AY estao em GPU. print(AX.is_cuda) for i in range(epochs): net.train() indices = torch.randperm(AX.shape[0]).to(DEVICE) for j in range(AX.shape[0]//batch_size): batchIndices=indices[batch_size*j:batch_size*(j+1)] optimizer.zero_grad() ax=AX[batchIndices]; ay=AY[batchIndices] #ax e ay2 estao em GPU ap2=net(ax) #ap2 esta em GPU loss=criterion(ap2, ay); loss.backward(); optimizer.step() if (i+1)%20==0: with torch.no_grad(): net.eval(); AP2=net(AX) lossTotal=criterion(AP2,AY).cpu().detach().numpy() ac=acuracidade(AP2,AY).cpu().numpy()/AY.shape[0] print("[%3d/%3d] Train_CrossEntropy=%6.4f Train_acc=%3.2f%%"%(i+1,epochs,lossTotal,100*ac))tempo1=time(); print("Tempo de treino=%fs"%(tempo1-tempo0))del AX, AY, indices, batchIndices, ax, ay, ap2, AP2; torch.cuda.empty_cache() #Libera memoria GPU

with torch.no_grad(): net.eval() QX=QX.to(DEVICE); QY=QY.to(DEVICE) #QX e QY estao em GPU QP2=net(QX) QP2=QP2.cpu(); QY=QY.cpu() #QP2 e QY estao em CPU lossTotal=criterion(QP2,QY).detach().numpy() ac=acuracidade(QP2,QY).numpy()/QY.shape[0]print("CrossEntropy=%6.4f acurac=%3.2f%%"%(lossTotal,100*ac))

torch.save(net.state_dict(), 'mlp3.pth')

Programa P5: Classificação de MNIST com rede neural densa em PyTorch, para GPU.

40

Page 41: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

O programa 5 traduzido para PyTorch resulta no programa P5. No criterion, o primeiroparâmetro é float32 e tem 10 colunas, enquanto que o segundo parâmetro é int64 e tem 1 col -una.

Saída:cuda[ 20/160] Train_CrossEntropy=0.0550 Train_acc=98.20%[ 40/160] Train_CrossEntropy=0.0335 Train_acc=98.86%[ 60/160] Train_CrossEntropy=0.0144 Train_acc=99.51%[ 80/160] Train_CrossEntropy=0.0219 Train_acc=99.20%[100/160] Train_CrossEntropy=0.0317 Train_acc=98.94%[120/160] Train_CrossEntropy=0.0093 Train_acc=99.65%[140/160] Train_CrossEntropy=0.0070 Train_acc=99.77%[160/160] Train_CrossEntropy=0.0018 Train_acc=99.94%Tempo de treino=109.502449sCrossEntropy=0.1300 acurac=98.12%

Há duas possibilidades para implementar o mesmo programa:

1) x = self.fc3(x) e criterion = nn.CrossEntropyLoss()2) x=torch.log_softmax(self.fc3(x),dim=1) e ecriterion=nn.NLLLoss()

41

Page 42: Rede neural densa em Tensorflow/Keras - LPS[A aula 2 de PSI3472 começa aqui para alunos que nunca usaram Python, Tensorflow, Keras e Go-ogle Colab ou que não cursaram PSI3471. Leiam

P5.3 Exemplo de carregar rede já treinada para fazer predição

O programa abaixo mostra como carregar uma rede já treinada para fazer predição.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

# -*- coding: utf-8 -*-"""pred1.py- https://www.aiworkbox.com/lessons/load-mnist-dataset-from-pytorch-torchvision- https://pytorch.org/tutorials/beginner/saving_loading_models.html- https://cnvrg.io/pytorch-cuda/?gclid=Cj0KCQiApY6BBhCsARIsAOI_GjaawBAcn04Rb2IaGCmsJfZ6QOrer_4cHpaJ9gbbA3ngmNIdQkSuuiYaAi-OREALw_wcB"""import numpy as npimport torch; import torch.nn as nn; import torch.optim as optimimport torchvision; import torchvision.datasets as datasetsimport matplotlib.pyplot as pltfrom time import time

#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(nl*nc, 400) self.fc2 = nn.Linear(400, 100) self.fc3 = nn.Linear(100, nclasses) def forward(self, x): x = torch.flatten(x, 1) x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) #Ou usar "x=torch.log_softmax(self.fc3(x),dim=1)" com "criterion=nn.NLLLoss()" return x

def acuracidade(p, y): p2=torch.argmax(p, 1) soma = (p2==y).sum() #Repare que compara p2 com y return soma

#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu'); print(DEVICE)Q = datasets.MNIST(root='/home/hae/deep/torch/data', train=False, transform=None, download=True)

QX=(255-Q.data)/255.0; QY=Q.targetsnl, nc = QX.shape[1], QX.shape[2] #28, 28nclasses=10

net = Net(); net.load_state_dict(torch.load("mlp3.pth")); net.to(DEVICE)criterion = nn.CrossEntropyLoss() #Ou usar "criterion=nn.NLLLoss()" com log_softmaxwith torch.no_grad(): net.eval() QX=QX.to(DEVICE); QY=QY.to(DEVICE) #QX e QY estao em GPU QP2=net(QX) QP2=QP2.cpu(); QY=QY.cpu() #QP2 e QY estao em CPU lossTotal=criterion(QP2,QY).detach().numpy() ac=acuracidade(QP2,QY).numpy()/QY.shape[0]print("CrossEntropy=%6.4f acurac=%3.2f%%"%(lossTotal,100*ac))

Programa 6: Lê modelo já treinado e faz predição.

42