Kit de ferramentas cognitivas da Microsoft - Guia rápido

Neste capítulo, aprenderemos o que é CNTK, suas características, diferença entre sua versão 1.0 e 2.0 e importantes destaques da versão 2.7.

O que é o Microsoft Cognitive Toolkit (CNTK)?

O Microsoft Cognitive Toolkit (CNTK), anteriormente conhecido como Computational Network Toolkit, é um kit de ferramentas de nível comercial gratuito, fácil de usar e de código aberto que nos permite treinar algoritmos de aprendizagem profunda para aprender como o cérebro humano. Isso nos permite criar alguns sistemas populares de aprendizagem profunda, comofeed-forward neural network time series prediction systems and Convolutional neural network (CNN) image classifiers.

Para um desempenho ideal, suas funções de estrutura são escritas em C ++. Embora possamos chamar sua função usando C ++, a abordagem mais comumente usada para o mesmo é usar um programa Python.

Recursos do CNTK

A seguir estão alguns dos recursos e capacidades oferecidos na versão mais recente do Microsoft CNTK:

Componentes integrados

  • O CNTK possui componentes integrados altamente otimizados que podem lidar com dados multidimensionais densos ou esparsos de Python, C ++ ou BrainScript.

  • Podemos implementar CNN, FNN, RNN, normalização em lote e sequência a sequência com atenção.

  • Ele nos fornece a funcionalidade para adicionar novos componentes principais definidos pelo usuário na GPU do Python.

  • Ele também fornece ajuste automático de hiperparâmetros.

  • Podemos implementar aprendizagem por reforço, redes adversárias gerativas (GANs), aprendizagem supervisionada e não supervisionada.

  • Para conjuntos de dados massivos, o CNTK possui leitores otimizados integrados.

Uso de recursos de forma eficiente

  • O CNTK nos fornece paralelismo com alta precisão em várias GPUs / máquinas via SGD de 1 bit.

  • Para caber nos maiores modelos de memória GPU, ele fornece compartilhamento de memória e outros métodos integrados.

Expresse nossas próprias redes facilmente

  • CNTK tem APIs completas para definir sua própria rede, alunos, leitores, treinamento e avaliação de Python, C ++ e BrainScript.

  • Usando CNTK, podemos avaliar facilmente modelos com Python, C ++, C # ou BrainScript.

  • Ele fornece APIs de alto e baixo nível.

  • Com base em nossos dados, ele pode moldar automaticamente a inferência.

  • Ele tem loops de Rede Neural Recorrente Simbólica (RNN) totalmente otimizado.

Medindo o desempenho do modelo

  • O CNTK fornece vários componentes para medir o desempenho das redes neurais que você constrói.

  • Gera dados de registro do seu modelo e do otimizador associado, que podemos usar para monitorar o processo de treinamento.

Versão 1.0 vs Versão 2.0

A tabela a seguir compara o CNTK Versão 1.0 e 2.0:

Versão 1.0 Versão 2.0
Foi lançado em 2016. É uma reescrita significativa da versão 1.0 e foi lançada em junho de 2017.
Ele usava uma linguagem de script proprietária chamada BrainScript. Suas funções de framework podem ser chamadas usando C ++, Python. Podemos carregar facilmente nossos módulos em C # ou Java. BrainScript também é compatível com a versão 2.0.
Ele roda em sistemas Windows e Linux, mas não diretamente no Mac OS. Também é executado em sistemas Windows (Win 8.1, Win 10, Server 2012 R2 e posterior) e Linux, mas não diretamente no Mac OS.

Destaques importantes da versão 2.7

Version 2.7é a última versão principal lançada do Microsoft Cognitive Toolkit. Tem suporte total para ONNX 1.4.1. A seguir estão alguns destaques importantes desta última versão lançada do CNTK.

  • Suporte total para ONNX 1.4.1.

  • Suporte para CUDA 10 para sistemas Windows e Linux.

  • Suporta loop avançado de Redes Neurais Recorrentes (RNN) na exportação ONNX.

  • Pode exportar mais de modelos de 2 GB no formato ONNX.

  • Ele suporta FP16 na ação de treinamento da linguagem de script BrainScript.

Aqui, vamos entender sobre a instalação do CNTK no Windows e no Linux. Além disso, o capítulo explica a instalação do pacote CNTK, etapas para instalar o Anaconda, arquivos CNTK, estrutura de diretório e organização da biblioteca CNTK.

Pré-requisitos

Para instalar o CNTK, devemos ter o Python instalado em nossos computadores. Você pode ir para o linkhttps://www.python.org/downloads/e selecione a versão mais recente para o seu sistema operacional, ou seja, Windows e Linux / Unix. Para um tutorial básico sobre Python, você pode consultar o linkhttps://www.tutorialspoint.com/python3/index.htm.

O CNTK é compatível com o Windows e também com o Linux, portanto, examinaremos ambos.

Instalando no Windows

Para executar o CNTK no Windows, usaremos o Anaconda versionde Python. Nós sabemos disso, o Anaconda é uma redistribuição do Python. Inclui pacotes adicionais comoScipy eScikit-learn que são usados ​​pelo CNTK para realizar vários cálculos úteis.

Então, primeiro vamos ver os passos para instalar o Anaconda em sua máquina -

Step 1−Primeiro baixe os arquivos de configuração do site público https://www.anaconda.com/distribution/.

Step 2 - Depois de baixar os arquivos de configuração, inicie a instalação e siga as instruções do link https://docs.anaconda.com/anaconda/install/.

Step 3- Uma vez instalado, o Anaconda também instalará alguns outros utilitários, que irão incluir automaticamente todos os executáveis ​​do Anaconda na variável PATH do seu computador. Podemos gerenciar nosso ambiente Python a partir deste prompt, podemos instalar pacotes e executar scripts Python.

Instalando o pacote CNTK

Assim que a instalação do Anaconda estiver concluída, você pode usar a maneira mais comum de instalar o pacote CNTK através do executável pip usando o seguinte comando -

pip install cntk

Existem vários outros métodos para instalar o Cognitive Toolkit em sua máquina. A Microsoft possui um conjunto organizado de documentação que explica os outros métodos de instalação em detalhes. Por favor siga o linkhttps://docs.microsoft.com/en-us/cognitive-toolkit/Setup-CNTK-on-your-machine.

Instalando no Linux

A instalação do CNTK no Linux é um pouco diferente da instalação no Windows. Aqui, para o Linux, vamos usar o Anaconda para instalar o CNTK, mas em vez de um instalador gráfico para o Anaconda, usaremos um instalador baseado em terminal no Linux. Embora o instalador funcione com quase todas as distribuições Linux, limitamos a descrição ao Ubuntu.

Então, primeiro vamos ver os passos para instalar o Anaconda em sua máquina -

Passos para instalar o Anaconda

Step 1- Antes de instalar o Anaconda, certifique-se de que o sistema está totalmente atualizado. Para verificar, primeiro execute os dois comandos a seguir dentro de um terminal -

sudo apt update
sudo apt upgrade

Step 2 - Assim que o computador for atualizado, obtenha o URL do site público https://www.anaconda.com/distribution/ para os arquivos de instalação mais recentes do Anaconda.

Step 3 - Assim que o URL for copiado, abra uma janela de terminal e execute o seguinte comando -

wget -0 anaconda-installer.sh url SHAPE \* MERGEFORMAT 
     y

	
	
	             f
 
 
      x
	  
|                     }

Substitua o url placeholder com a URL copiada do site do Anaconda.

Step 4 - Em seguida, com a ajuda do seguinte comando, podemos instalar o Anaconda -

sh ./anaconda-installer.sh

O comando acima irá instalar por padrão Anaconda3 dentro de nosso diretório inicial.

Instalando o pacote CNTK

Assim que a instalação do Anaconda estiver concluída, você pode usar a maneira mais comum de instalar o pacote CNTK através do executável pip usando o seguinte comando -

pip install cntk

Examinando arquivos CNTK e estrutura de diretório

Assim que o CNTK for instalado como um pacote Python, podemos examinar sua estrutura de arquivos e diretórios. Está emC:\Users\ \Anaconda3\Lib\site-packages\cntk, como mostrado abaixo na imagem.

Verificando a instalação do CNTK

Depois que o CNTK for instalado como um pacote Python, você deve verificar se o CNTK foi instalado corretamente. No shell de comando do Anaconda, inicie o interpretador Python digitandoipython. Então, importe CNTK digitando o seguinte comando.

import cntk as c

Uma vez importado, verifique sua versão com a ajuda do seguinte comando -

print(c.__version__)

O intérprete responderá com a versão CNTK instalada. Se não responder, haverá um problema com a instalação.

A organização da biblioteca CNTK

CNTK, um pacote python tecnicamente, é organizado em 13 subpacotes de alto nível e 8 subpacotes menores. A tabela a seguir consiste nos 10 pacotes usados ​​com mais frequência:

Sr. Não Nome e descrição do pacote
1

cntk.io

Contém funções para leitura de dados. Por exemplo: next_minibatch ()

2

cntk.layers

Contém funções de alto nível para a criação de redes neurais. Por exemplo: Denso ()

3

cntk.learners

Contém funções para treinamento. Por exemplo: sgd ()

4

cntk.losses

Contém funções para medir o erro de treinamento. Por exemplo: squared_error ()

5

cntk.metrics

Contém funções para medir o erro do modelo. Por exemplo: classificatoin_error

6

cntk.ops

Contém funções de baixo nível para a criação de redes neurais. Por exemplo: tanh ()

7

cntk.random

Contém funções para gerar números aleatórios. Por exemplo: normal ()

8

cntk.train

Contém funções de treinamento. Por exemplo: train_minibatch ()

9

cntk.initializer

Contém inicializadores de parâmetro de modelo. Por exemplo: normal () e uniforme ()

10

cntk.variables

Contém construções de baixo nível. Por exemplo: Parameter () e Variable ()

O Microsoft Cognitive Toolkit oferece duas versões de compilação diferentes, ou seja, somente CPU e somente GPU.

Versão de compilação apenas para CPU

A versão compilada apenas para CPU do CNTK usa o Intel MKLML otimizado, onde MKLML é o subconjunto de MKL (Math Kernel Library) e lançado com Intel MKL-DNN como uma versão finalizada do Intel MKL para MKL-DNN.

GPU apenas compilar versão

Por outro lado, a versão compilada apenas para GPU do CNTK usa bibliotecas NVIDIA altamente otimizadas, como CUB e cuDNN. Ele oferece suporte a treinamento distribuído em várias GPUs e várias máquinas. Para um treinamento distribuído ainda mais rápido em CNTK, a versão de construção de GPU também inclui -

  • SGD quantizado em 1 bit desenvolvido por MSR.

  • Algoritmos de treinamento paralelo SGD de momento de bloco.

Ativando GPU com CNTK no Windows

Na seção anterior, vimos como instalar a versão básica do CNTK para usar com a CPU. Agora vamos discutir como podemos instalar o CNTK para usar com uma GPU. Mas, antes de se aprofundar nisso, primeiro você deve ter uma placa de vídeo compatível.

No momento, o CNTK suporta a placa de vídeo NVIDIA com pelo menos suporte CUDA 3.0. Para ter certeza, você pode verificar emhttps://developer.nvidia.com/cuda-gpus se sua GPU suporta CUDA.

Então, vamos ver as etapas para habilitar a GPU com CNTK no sistema operacional Windows -

Step 1 - Dependendo da placa gráfica que você está usando, primeiro você precisa ter os drivers GeForce ou Quadro mais recentes para sua placa gráfica.

Step 2 - Depois de baixar os drivers, você precisa instalar o kit de ferramentas CUDA Versão 9.0 para Windows do site da NVIDIA https://developer.nvidia.com/cuda-90-download-archive?target_os=Windows&target_arch=x86_64. Após a instalação, execute o instalador e siga as instruções.

Step 3 - Em seguida, você precisa instalar os binários cuDNN do site da NVIDIA https://developer.nvidia.com/rdp/form/cudnn-download-survey. Com a versão CUDA 9.0, cuDNN 7.4.1 funciona bem. Basicamente, cuDNN é uma camada no topo do CUDA, usada pelo CNTK.

Step 4 - Depois de baixar os binários cuDNN, você precisa extrair o arquivo zip para a pasta raiz da instalação do kit de ferramentas CUDA.

Step 5- Esta é a última etapa que permitirá o uso da GPU dentro do CNTK. Execute o seguinte comando dentro do prompt do Anaconda no sistema operacional Windows -

pip install cntk-gpu

Ativando GPU com CNTK no Linux

Vamos ver como podemos habilitar GPU com CNTK no sistema operacional Linux -

Baixando o kit de ferramentas CUDA

Primeiro, você precisa instalar o kit de ferramentas CUDA do site da NVIDIA https://developer.nvidia.com/cuda-90-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type = runfilelocal .

Executando o instalador

Agora, uma vez que você tenha binários no disco, execute o instalador abrindo um terminal e executando o seguinte comando e as instruções na tela -

sh cuda_9.0.176_384.81_linux-run

Modificar script de perfil Bash

Depois de instalar o kit de ferramentas CUDA em sua máquina Linux, você precisa modificar o script de perfil BASH. Para isso, primeiro abra o arquivo $ HOME / .bashrc no editor de texto. Agora, no final do script, inclua as seguintes linhas -

export PATH=/usr/local/cuda-9.0/bin${PATH:+:${PATH}} export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64\ ${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
Installing

Instalando bibliotecas cuDNN

Por fim, precisamos instalar os binários cuDNN. Ele pode ser baixado do site da NVIDIAhttps://developer.nvidia.com/rdp/form/cudnn-download-survey. Com a versão CUDA 9.0, cuDNN 7.4.1 funciona bem. Basicamente, cuDNN é uma camada no topo do CUDA, usada pelo CNTK.

Depois de baixar a versão para Linux, extraia-a para o /usr/local/cuda-9.0 pasta usando o seguinte comando -

tar xvzf -C /usr/local/cuda-9.0/ cudnn-9.0-linux-x64-v7.4.1.5.tgz

Altere o caminho para o nome do arquivo conforme necessário.

Neste capítulo, aprenderemos em detalhes sobre as sequências no CNTK e sua classificação.

Tensores

O conceito sobre o qual CNTK trabalha é tensor. Basicamente, as entradas, saídas e parâmetros do CNTK são organizados comotensors, que muitas vezes é considerada uma matriz generalizada. Cada tensor tem umrank -

  • Tensor de classificação 0 é um escalar.

  • Tensor de classificação 1 é um vetor.

  • Tensor de classificação 2 é amatrix.

Aqui, essas diferentes dimensões são chamadas de axes.

Eixos estáticos e eixos dinâmicos

Como o nome indica, os eixos estáticos têm o mesmo comprimento ao longo da vida da rede. Por outro lado, o comprimento dos eixos dinâmicos pode variar de instância para instância. Na verdade, seu comprimento normalmente não é conhecido antes de cada minibatch ser apresentado.

Os eixos dinâmicos são como eixos estáticos porque também definem um agrupamento significativo dos números contidos no tensor.

Exemplo

Para esclarecer, vamos ver como um minibatch de clipes de vídeo curtos é representado no CNTK. Suponha que a resolução dos clipes de vídeo seja de 640 * 480. E também os clipes são filmados em cores que normalmente são codificados com três canais. Além disso, significa que nosso minibatch tem o seguinte -

  • 3 eixos estáticos de comprimento 640, 480 e 3, respectivamente.

  • Dois eixos dinâmicos; a duração do vídeo e os eixos do minibatch.

Isso significa que se um minibatch tiver 16 vídeos, cada um com 240 quadros de comprimento, será representado como 16*240*3*640*480 tensores.

Trabalhando com sequências em CNTK

Vamos entender as sequências em CNTK aprendendo primeiro sobre Rede de memória de longo-curto prazo.

Rede de memória de longo-curto prazo (LSTM)

As redes de memória de longo-curto prazo (LSTMs) foram introduzidas por Hochreiter & Schmidhuber. Resolveu o problema de obter uma camada básica recorrente para lembrar coisas por um longo tempo. A arquitetura do LSTM é fornecida acima no diagrama. Como podemos ver, ele possui neurônios de entrada, células de memória e neurônios de saída. A fim de combater o problema do gradiente de desaparecimento, as redes de memória de longo-curto prazo usam uma célula de memória explícita (armazena os valores anteriores) e as seguintes portas -

  • Forget gate- Como o nome indica, diz à célula de memória para esquecer os valores anteriores. A célula de memória armazena os valores até que o portão, ou seja, 'esqueça o portão', diga para esquecê-los.

  • Input gate - Como o nome indica, adiciona coisas novas à célula.

  • Output gate - Como o nome indica, a porta de saída decide quando passar os vetores da célula para o próximo estado oculto.

É muito fácil trabalhar com sequências no CNTK. Vamos ver com a ajuda do seguinte exemplo -

import sys
import os
from cntk import Trainer, Axis
from cntk.io import MinibatchSource, CTFDeserializer, StreamDef, StreamDefs,\
   INFINITELY_REPEAT
from cntk.learners import sgd, learning_parameter_schedule_per_sample
from cntk import input_variable, cross_entropy_with_softmax, \
   classification_error, sequence
from cntk.logging import ProgressPrinter
from cntk.layers import Sequential, Embedding, Recurrence, LSTM, Dense
def create_reader(path, is_training, input_dim, label_dim):
   return MinibatchSource(CTFDeserializer(path, StreamDefs(
      features=StreamDef(field='x', shape=input_dim, is_sparse=True),
      labels=StreamDef(field='y', shape=label_dim, is_sparse=False)
   )), randomize=is_training,
   max_sweeps=INFINITELY_REPEAT if is_training else 1)
def LSTM_sequence_classifier_net(input, num_output_classes, embedding_dim,
LSTM_dim, cell_dim):
   lstm_classifier = Sequential([Embedding(embedding_dim),
      Recurrence(LSTM(LSTM_dim, cell_dim)),
      sequence.last,
      Dense(num_output_classes)])
return lstm_classifier(input)
def train_sequence_classifier():
   input_dim = 2000
   cell_dim = 25
   hidden_dim = 25
   embedding_dim = 50
   num_output_classes = 5
   features = sequence.input_variable(shape=input_dim, is_sparse=True)
   label = input_variable(num_output_classes)
   classifier_output = LSTM_sequence_classifier_net(
   features, num_output_classes, embedding_dim, hidden_dim, cell_dim)
   ce = cross_entropy_with_softmax(classifier_output, label)
   pe =      classification_error(classifier_output, label)
   rel_path = ("../../../Tests/EndToEndTests/Text/" +
      "SequenceClassification/Data/Train.ctf")
   path = os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)
   reader = create_reader(path, True, input_dim, num_output_classes)
input_map = {
   features: reader.streams.features,
   label: reader.streams.labels
}
lr_per_sample = learning_parameter_schedule_per_sample(0.0005)
progress_printer = ProgressPrinter(0)
trainer = Trainer(classifier_output, (ce, pe),
sgd(classifier_output.parameters, lr=lr_per_sample),progress_printer)
minibatch_size = 200
for i in range(255):
   mb = reader.next_minibatch(minibatch_size, input_map=input_map)
trainer.train_minibatch(mb)
   evaluation_average = float(trainer.previous_minibatch_evaluation_average)
   loss_average = float(trainer.previous_minibatch_loss_average)
return evaluation_average, loss_average
if __name__ == '__main__':
   error, _ = train_sequence_classifier()
   print(" error: %f" % error)
average  since  average  since  examples
loss     last   metric   last
------------------------------------------------------
1.61    1.61    0.886     0.886     44
1.61     1.6    0.714     0.629    133
 1.6    1.59     0.56     0.448    316
1.57    1.55    0.479      0.41    682
1.53     1.5    0.464     0.449   1379
1.46     1.4    0.453     0.441   2813
1.37    1.28     0.45     0.447   5679
 1.3    1.23    0.448     0.447  11365

error: 0.333333

A explicação detalhada do programa acima será abordada nas próximas seções, especialmente quando estivermos construindo redes neurais recorrentes.

Este capítulo trata da construção de um modelo de regressão logística no CNTK.

Noções básicas do modelo de regressão logística

A regressão logística, uma das técnicas de ML mais simples, é uma técnica especialmente para classificação binária. Em outras palavras, para criar um modelo de previsão em situações em que o valor da variável a ser prevista pode ser um de apenas dois valores categóricos. Um dos exemplos mais simples de Regressão Logística é prever se a pessoa é homem ou mulher, com base na idade, voz, cabelos e assim por diante.

Exemplo

Vamos entender o conceito de Regressão Logística matematicamente com a ajuda de outro exemplo -

Suponha que queiramos prever a capacidade de crédito de um pedido de empréstimo; 0 significa rejeitar e 1 significa aprovar, com base no candidatodebt , income e credit rating. Representamos dívida com X1, receita com X2 e classificação de crédito com X3.

Na Regressão Logística, determinamos um valor de peso, representado por w, para cada recurso e um único valor de polarização, representado por b.

Agora suponha,

X1 = 3.0
X2 = -2.0
X3 = 1.0

E suponha que determinemos o peso e o viés da seguinte forma -

W1 = 0.65, W2 = 1.75, W3 = 2.05 and b = 0.33

Agora, para prever a classe, precisamos aplicar a seguinte fórmula -

Z = (X1*W1)+(X2*W2)+(X3+W3)+b
i.e. Z = (3.0)*(0.65) + (-2.0)*(1.75) + (1.0)*(2.05) + 0.33
= 0.83

Em seguida, precisamos calcular P = 1.0/(1.0 + exp(-Z)). Aqui, a função exp () é o número de Euler.

P = 1.0/(1.0 + exp(-0.83)
= 0.6963

O valor P pode ser interpretado como a probabilidade de que a classe seja 1. Se P <0,5, a previsão é classe = 0, caso contrário, a previsão (P> = 0,5) é classe = 1.

Para determinar os valores de peso e polarização, devemos obter um conjunto de dados de treinamento com os valores preditores de entrada conhecidos e os valores de rótulos de classe corretos conhecidos. Depois disso, podemos usar um algoritmo, geralmente Gradient Descent, para encontrar os valores de peso e viés.

Exemplo de implementação de modelo LR

Para este modelo LR, vamos usar o seguinte conjunto de dados -

1.0, 2.0, 0
3.0, 4.0, 0
5.0, 2.0, 0
6.0, 3.0, 0
8.0, 1.0, 0
9.0, 2.0, 0
1.0, 4.0, 1
2.0, 5.0, 1
4.0, 6.0, 1
6.0, 5.0, 1
7.0, 3.0, 1
8.0, 5.0, 1

Para iniciar a implementação deste modelo LR no CNTK, precisamos primeiro importar os seguintes pacotes -

import numpy as np
import cntk as C

O programa é estruturado com a função main () da seguinte forma -

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")

Agora, precisamos carregar os dados de treinamento na memória da seguinte maneira -

data_file = ".\\dataLRmodel.txt"
print("Loading data from " + data_file + "\n")
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[0,1])
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[2], ndmin=2)

Agora, estaremos criando um programa de treinamento que cria um modelo de regressão logística compatível com os dados de treinamento -

features_dim = 2
labels_dim = 1
X = C.ops.input_variable(features_dim, np.float32)
y = C.input_variable(labels_dim, np.float32)
W = C.parameter(shape=(features_dim, 1)) # trainable cntk.Parameter
b = C.parameter(shape=(labels_dim))
z = C.times(X, W) + b
p = 1.0 / (1.0 + C.exp(-z))
model = p

Agora, precisamos criar Lerner e treinador da seguinte maneira -

ce_error = C.binary_cross_entropy(model, y) # CE a bit more principled for LR
fixed_lr = 0.010
learner = C.sgd(model.parameters, fixed_lr)
trainer = C.Trainer(model, (ce_error), [learner])
max_iterations = 4000

Treinamento de modelo LR

Depois de criar o modelo LR, em seguida, é hora de iniciar o processo de treinamento -

np.random.seed(4)
N = len(features_mat)
for i in range(0, max_iterations):
row = np.random.choice(N,1) # pick a random row from training items
trainer.train_minibatch({ X: features_mat[row], y: labels_mat[row] })
if i % 1000 == 0 and i > 0:
mcee = trainer.previous_minibatch_loss_average
print(str(i) + " Cross-entropy error on curr item = %0.4f " % mcee)

Agora, com a ajuda do código a seguir, podemos imprimir os pesos e o viés do modelo -

np.set_printoptions(precision=4, suppress=True)
print("Model weights: ")
print(W.value)
print("Model bias:")
print(b.value)
print("")
if __name__ == "__main__":
main()

Treinando um modelo de regressão logística - exemplo completo

import numpy as np
import cntk as C
   def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
print("Loading data from " + data_file + "\n")
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[0,1])
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",", skiprows=0, usecols=[2], ndmin=2)
features_dim = 2
labels_dim = 1
X = C.ops.input_variable(features_dim, np.float32)
y = C.input_variable(labels_dim, np.float32)
W = C.parameter(shape=(features_dim, 1)) # trainable cntk.Parameter
b = C.parameter(shape=(labels_dim))
z = C.times(X, W) + b
p = 1.0 / (1.0 + C.exp(-z))
model = p
ce_error = C.binary_cross_entropy(model, y) # CE a bit more principled for LR
fixed_lr = 0.010
learner = C.sgd(model.parameters, fixed_lr)
trainer = C.Trainer(model, (ce_error), [learner])
max_iterations = 4000
np.random.seed(4)
N = len(features_mat)
for i in range(0, max_iterations):
row = np.random.choice(N,1) # pick a random row from training items
trainer.train_minibatch({ X: features_mat[row], y: labels_mat[row] })
if i % 1000 == 0 and i > 0:
mcee = trainer.previous_minibatch_loss_average
print(str(i) + " Cross-entropy error on curr item = %0.4f " % mcee)
np.set_printoptions(precision=4, suppress=True)
print("Model weights: ")
print(W.value)
print("Model bias:")
print(b.value)
if __name__ == "__main__":
  main()

Resultado

Using CNTK version = 2.7
1000 cross entropy error on curr item = 0.1941
2000 cross entropy error on curr item = 0.1746
3000 cross entropy error on curr item = 0.0563
Model weights:
[-0.2049]
   [0.9666]]
Model bias:
[-2.2846]

Predição usando modelo LR treinado

Uma vez que o modelo LR foi treinado, podemos usá-lo para predição da seguinte forma -

Em primeiro lugar, nosso programa de avaliação importa o pacote numpy e carrega os dados de treinamento em uma matriz de recursos e uma matriz de rótulo de classe da mesma forma que o programa de treinamento que implementamos acima -

import numpy as np
def main():
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=(0,1))
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=[2], ndmin=2)

Em seguida, é hora de definir os valores dos pesos e do viés que foram determinados por nosso programa de treinamento -

print("Setting weights and bias values \n")
weights = np.array([0.0925, 1.1722], dtype=np.float32)
bias = np.array([-4.5400], dtype=np.float32)
N = len(features_mat)
features_dim = 2

Em seguida, nosso programa de avaliação calculará a probabilidade de regressão logística percorrendo cada item de treinamento da seguinte forma -

print("item pred_prob pred_label act_label result")
for i in range(0, N): # each item
   x = features_mat[i]
   z = 0.0
   for j in range(0, features_dim):
   z += x[j] * weights[j]
   z += bias[0]
   pred_prob = 1.0 / (1.0 + np.exp(-z))
  pred_label = 0 if pred_prob < 0.5 else 1
   act_label = labels_mat[i]
   pred_str = ‘correct’ if np.absolute(pred_label - act_label) < 1.0e-5 \
    else ‘WRONG’
  print("%2d %0.4f %0.0f %0.0f %s" % \ (i, pred_prob, pred_label, act_label, pred_str))

Agora vamos demonstrar como fazer previsões -

x = np.array([9.5, 4.5], dtype=np.float32)
print("\nPredicting class for age, education = ")
print(x)
z = 0.0
for j in range(0, features_dim):
z += x[j] * weights[j]
z += bias[0]
p = 1.0 / (1.0 + np.exp(-z))
print("Predicted p = " + str(p))
if p < 0.5: print("Predicted class = 0")
else: print("Predicted class = 1")

Programa completo de avaliação de previsão

import numpy as np
def main():
data_file = ".\\dataLRmodel.txt" # provide the name and the location of data file
features_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=(0,1))
labels_mat = np.loadtxt(data_file, dtype=np.float32, delimiter=",",
skiprows=0, usecols=[2], ndmin=2)
print("Setting weights and bias values \n")
weights = np.array([0.0925, 1.1722], dtype=np.float32)
bias = np.array([-4.5400], dtype=np.float32)
N = len(features_mat)
features_dim = 2
print("item pred_prob pred_label act_label result")
for i in range(0, N): # each item
   x = features_mat[i]
   z = 0.0
   for j in range(0, features_dim):
     z += x[j] * weights[j]
   z += bias[0]
   pred_prob = 1.0 / (1.0 + np.exp(-z))
   pred_label = 0 if pred_prob < 0.5 else 1
   act_label = labels_mat[i]
   pred_str = ‘correct’ if np.absolute(pred_label - act_label) < 1.0e-5 \
     else ‘WRONG’
  print("%2d %0.4f %0.0f %0.0f %s" % \ (i, pred_prob, pred_label, act_label, pred_str))
x = np.array([9.5, 4.5], dtype=np.float32)
print("\nPredicting class for age, education = ")
print(x)
z = 0.0
for j in range(0, features_dim):
   z += x[j] * weights[j]
z += bias[0]
p = 1.0 / (1.0 + np.exp(-z))
print("Predicted p = " + str(p))
if p < 0.5: print("Predicted class = 0")
else: print("Predicted class = 1")
if __name__ == "__main__":
  main()

Resultado

Definir pesos e valores de polarização.

Item  pred_prob  pred_label  act_label  result
0   0.3640         0             0     correct
1   0.7254         1             0      WRONG
2   0.2019         0             0     correct
3   0.3562         0             0     correct
4   0.0493         0             0     correct
5   0.1005         0             0     correct
6   0.7892         1             1     correct
7   0.8564         1             1     correct
8   0.9654         1             1     correct
9   0.7587         1             1     correct
10  0.3040         0             1      WRONG
11  0.7129         1             1     correct
Predicting class for age, education =
[9.5 4.5]
Predicting p = 0.526487952
Predicting class = 1

Este capítulo trata de conceitos de Rede Neural em relação ao CNTK.

Como sabemos, várias camadas de neurônios são usadas para fazer uma rede neural. Mas, surge a pergunta que no CNTK como podemos modelar as camadas de um NN? Isso pode ser feito com a ajuda de funções de camada definidas no módulo de camada.

Função de camada

Na verdade, no CNTK, trabalhar com as camadas tem uma sensação de programação funcional distinta. A função de camada se parece com uma função regular e produz uma função matemática com um conjunto de parâmetros predefinidos. Vamos ver como podemos criar o tipo de camada mais básico, Denso, com a ajuda da função de camada.

Exemplo

Com a ajuda das etapas básicas a seguir, podemos criar o tipo de camada mais básico -

Step 1 - Primeiro, precisamos importar a função de camada Densa do pacote de camadas do CNTK.

from cntk.layers import Dense

Step 2 - Em seguida, a partir do pacote raiz CNTK, precisamos importar a função input_variable.

from cntk import input_variable

Step 3- Agora, precisamos criar uma nova variável de entrada usando a função input_variable. Também precisamos fornecer o seu tamanho.

feature = input_variable(100)

Step 4 - Por fim, iremos criar uma nova camada usando a função Densi juntamente com o número de neurônios que queremos.

layer = Dense(40)(feature)

Agora, podemos invocar a função de camada Densa configurada para conectar a camada Densa à entrada.

Exemplo de implementação completo

from cntk.layers import Dense
from cntk import input_variable
feature= input_variable(100)
layer = Dense(40)(feature)

Personalização de camadas

Como vimos, o CNTK nos fornece um bom conjunto de padrões para a construção de NNs. Baseado emactivationfunção e outras configurações que escolhermos, o comportamento, bem como o desempenho do NN é diferente. É outro algoritmo de derivação muito útil. Por isso, é bom entender o que podemos configurar.

Etapas para configurar uma camada densa

Cada camada no NN tem suas opções de configuração exclusivas e quando falamos sobre a camada Densa, temos as seguintes configurações importantes para definir -

  • shape - Como o nome indica, ele define a forma de saída da camada que determina ainda mais o número de neurônios nessa camada.

  • activation - Define a função de ativação dessa camada, para que possa transformar os dados de entrada.

  • init- Define a função de inicialização dessa camada. Ele inicializará os parâmetros da camada quando começarmos a treinar o NN.

Vamos ver as etapas com a ajuda das quais podemos configurar um Dense camada -

Step1 - Primeiro, precisamos importar o Dense função de camada do pacote de camadas do CNTK.

from cntk.layers import Dense

Step2 - Em seguida, do pacote de operações CNTK, precisamos importar o sigmoid operator. Ele será usado para configurar como uma função de ativação.

from cntk.ops import sigmoid

Step3 - Agora, do pacote inicializador, precisamos importar o glorot_uniform inicializador.

from cntk.initializer import glorot_uniform

Step4 - Por fim, vamos criar uma nova camada usando a função Densi juntamente com o número de neurônios como primeiro argumento. Além disso, forneça osigmoid operador como activation função e o glorot_uniform Enquanto o init função para a camada.

layer = Dense(50, activation = sigmoid, init = glorot_uniform)

Exemplo de implementação completo -

from cntk.layers import Dense
from cntk.ops import sigmoid
from cntk.initializer import glorot_uniform
layer = Dense(50, activation = sigmoid, init = glorot_uniform)

Otimizando os parâmetros

Até agora, vimos como criar a estrutura de um NN e como definir várias configurações. Aqui, veremos como podemos otimizar os parâmetros de um NN. Com a ajuda da combinação de dois componentes, a saberlearners e trainers, podemos otimizar os parâmetros de um NN.

componente de treinador

O primeiro componente que é usado para otimizar os parâmetros de um NN é trainercomponente. Basicamente, ele implementa o processo de retropropagação. Se falarmos sobre seu funcionamento, ele passa os dados pelo NN para obter uma previsão.

Em seguida, utiliza outro componente denominado learner para obter os novos valores para os parâmetros de um NN. Depois de obter os novos valores, ele aplica esses novos valores e repete o processo até que um critério de saída seja atendido.

componente do aluno

O segundo componente que é usado para otimizar os parâmetros de um NN é learner componente, basicamente responsável pela execução do algoritmo de descida gradiente.

Alunos incluídos na biblioteca CNTK

A seguir está a lista de alguns dos alunos interessantes incluídos na biblioteca CNTK -

  • Stochastic Gradient Descent (SGD) - Este aluno representa a descida gradiente estocástica básica, sem quaisquer extras.

  • Momentum Stochastic Gradient Descent (MomentumSGD) - Com SGD, este aluno aplica o momentum para superar o problema dos máximos locais.

  • RMSProp - Este aluno, para controlar a taxa de descida, usa taxas de aprendizado decrescentes.

  • Adam - Esse aluno, para diminuir a taxa de descida ao longo do tempo, usa o momento de decadência.

  • Adagrad - Este aluno, para recursos de ocorrência frequente ou infrequente, usa taxas de aprendizagem diferentes.

CNTK - Criando a primeira rede neural

Este capítulo irá elaborar sobre a criação de uma rede neural no CNTK.

Construa a estrutura da rede

A fim de aplicar os conceitos de CNTK para construir nosso primeiro NN, vamos usar o NN para classificar as espécies de flores de íris com base nas propriedades físicas de largura e comprimento da sépala e largura e comprimento da pétala. O conjunto de dados que usaremos usando o conjunto de dados da íris que descreve as propriedades físicas de diferentes variedades de flores da íris -

  • Comprimento da sépala
  • Largura sépala
  • Comprimento da pétala
  • Largura da pétala
  • Classe ie iris setosa ou iris versicolor ou iris virginica

Aqui, estaremos construindo um NN regular chamado NN feedforward. Vejamos as etapas de implementação para construir a estrutura do NN -

Step 1 - Primeiro, importaremos os componentes necessários, como nossos tipos de camada, funções de ativação e uma função que nos permite definir uma variável de entrada para nosso NN, da biblioteca CNTK.

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu

Step 2- Depois disso, vamos criar nosso modelo usando a função sequencial. Uma vez criado, iremos alimentá-lo com as camadas que desejamos. Aqui, vamos criar duas camadas distintas em nosso NN; um com quatro neurônios e outro com três neurônios.

model = Sequential([Dense(4, activation=relu), Dense(3, activation=log_sogtmax)])

Step 3- Por fim, para compilar o NN, vamos vincular a rede à variável de entrada. Possui uma camada de entrada com quatro neurônios e uma camada de saída com três neurônios.

feature= input_variable(4)
z = model(feature)

Aplicando uma função de ativação

Existem muitas funções de ativação para escolher e escolher a função de ativação certa definitivamente fará uma grande diferença no desempenho de nosso modelo de aprendizado profundo.

Na camada de saída

Escolhendo um activation função na camada de saída dependerá do tipo de problema que vamos resolver com nosso modelo.

  • Para um problema de regressão, devemos usar um linear activation function na camada de saída.

  • Para um problema de classificação binária, devemos usar um sigmoid activation function na camada de saída.

  • Para o problema de classificação multi-classe, devemos usar um softmax activation function na camada de saída.

  • Aqui, vamos construir um modelo para prever uma das três classes. Isso significa que precisamos usarsoftmax activation function na camada de saída.

Na camada oculta

Escolhendo um activation A função na camada oculta requer alguma experimentação para monitorar o desempenho para ver qual função de ativação funciona bem.

  • Em um problema de classificação, precisamos prever a probabilidade de uma amostra pertencer a uma classe específica. É por isso que precisamos de umactivation functionque nos dá valores probabilísticos. Para alcançar este objetivo,sigmoid activation function pode nos ajudar.

  • Um dos principais problemas associados à função sigmóide é o problema do gradiente de desaparecimento. Para superar esse problema, podemos usarReLU activation function que cobre todos os valores negativos a zero e funciona como um filtro de passagem para valores positivos.

Escolha uma função de perda

Uma vez que temos a estrutura para nosso modelo NN, devemos otimizá-lo. Para otimizar, precisamos de umloss function. Ao contrárioactivation functions, temos muito menos funções de perda para escolher. No entanto, a escolha de uma função de perda dependerá do tipo de problema que vamos resolver com nosso modelo.

Por exemplo, em um problema de classificação, devemos usar uma função de perda que pode medir a diferença entre uma classe prevista e uma classe real.

função de perda

Para o problema de classificação, vamos resolver com nosso modelo NN, categorical cross entropya função de perda é a melhor candidata. No CNTK, é implementado comocross_entropy_with_softmax que pode ser importado de cntk.losses pacote, como segue -

label= input_variable(3)
loss = cross_entropy_with_softmax(z, label)

Métricas

Com a estrutura para nosso modelo NN e uma função de perda para aplicar, temos todos os ingredientes para começar a fazer a receita para otimizar nosso modelo de aprendizado profundo. Mas, antes de nos aprofundarmos nisso, devemos aprender sobre métricas.

cntk.metrics

CNTK tem o pacote denominado cntk.metricsa partir do qual podemos importar as métricas que vamos usar. Enquanto estamos construindo um modelo de classificação, estaremos usandoclassification_error matric que irá produzir um número entre 0 e 1. O número entre 0 e 1 indica a porcentagem de amostras previstas corretamente -

Primeiro, precisamos importar a métrica de cntk.metrics pacote -

from cntk.metrics import classification_error
error_rate = classification_error(z, label)

A função acima realmente precisa da saída do NN e do rótulo esperado como entrada.

CNTK - Treinamento da Rede Neural

Aqui, vamos entender sobre o treinamento da Rede Neural em CNTK.

Treinando um modelo em CNTK

Na seção anterior, definimos todos os componentes do modelo de aprendizado profundo. Agora é hora de treiná-lo. Como discutimos anteriormente, podemos treinar um modelo NN em CNTK usando a combinação delearner e trainer.

Escolher um aluno e configurar o treinamento

Nesta seção, iremos definir o learner. CNTK fornece várioslearnersescolher a partir de. Para o nosso modelo, definido nas seções anteriores, estaremos usandoStochastic Gradient Descent (SGD) learner.

Para treinar a rede neural, vamos configurar o learner e trainer com a ajuda das seguintes etapas -

Step 1 - Primeiro, precisamos importar sgd função de cntk.lerners pacote.

from cntk.learners import sgd

Step 2 - Em seguida, precisamos importar Trainer função de cntk.trainpacote .trainer.

from cntk.train.trainer import Trainer

Step 3 - Agora, precisamos criar um learner. Pode ser criado invocandosgd funcionar junto com o fornecimento de parâmetros do modelo e um valor para a taxa de aprendizagem.

learner = sgd(z.parametrs, 0.01)

Step 4 - Por fim, precisamos inicializar o trainer. Deve ser fornecida a rede, a combinação doloss e metric juntamente com o learner.

trainer = Trainer(z, (loss, error_rate), [learner])

A taxa de aprendizagem que controla a velocidade da otimização deve ser um pequeno número entre 0,1 e 0,001.

Escolhendo um aluno e configurando o treinamento - Exemplo completo

from cntk.learners import sgd
from cntk.train.trainer import Trainer
learner = sgd(z.parametrs, 0.01)
trainer = Trainer(z, (loss, error_rate), [learner])

Alimentando dados para o treinador

Depois de escolher e configurar o treinador, é hora de carregar o conjunto de dados. Nós salvamos oiris conjunto de dados como um.CSV arquivo e usaremos o pacote de wrangling de dados chamado pandas para carregar o conjunto de dados.

Etapas para carregar o conjunto de dados do arquivo .CSV

Step 1 - Primeiro, precisamos importar o pandas pacote.

from import pandas as pd

Step 2 - Agora, precisamos invocar a função chamada read_csv função para carregar o arquivo .csv do disco.

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, 
‘petal_length’, ‘petal_width’, index_col=False)

Depois de carregar o conjunto de dados, precisamos dividi-lo em um conjunto de recursos e um rótulo.

Etapas para dividir o conjunto de dados em recursos e rótulo

Step 1- Primeiro, precisamos selecionar todas as linhas e as primeiras quatro colunas do conjunto de dados. Isso pode ser feito usandoiloc função.

x = df_source.iloc[:, :4].values

Step 2- Em seguida, precisamos selecionar a coluna de espécies do conjunto de dados da íris. Estaremos usando a propriedade values ​​para acessar o subjacentenumpy array.

x = df_source[‘species’].values

Etapas para codificar a coluna de espécies em uma representação vetorial numérica

Como discutimos anteriormente, nosso modelo é baseado na classificação, requer valores de entrada numéricos. Portanto, aqui precisamos codificar a coluna de espécies em uma representação vetorial numérica. Vamos ver as etapas para fazer isso -

Step 1- Primeiro, precisamos criar uma expressão de lista para iterar sobre todos os elementos do array. Em seguida, execute uma pesquisa no dicionário label_mapping para cada valor.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 2- Em seguida, converta este valor numérico convertido em um vetor codificado de um ponto. Estaremos usandoone_hot funcionar da seguinte forma -

def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result

Step 3 - Por fim, precisamos transformar essa lista convertida em um numpy array.

y = np.array([one_hot(label_mapping[v], 3) for v in y])

Etapas para detectar overfitting

A situação, quando seu modelo lembra das amostras, mas não pode deduzir regras das amostras de treinamento, é overfitting. Com a ajuda das etapas a seguir, podemos detectar overfitting em nosso modelo -

Step 1 - Primeiro, de sklearn pacote, importe o train_test_split função do model_selection módulo.

from sklearn.model_selection import train_test_split

Step 2 - Em seguida, precisamos invocar a função train_test_split com os recursos xe rótulos y da seguinte forma -

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0-2, 
stratify=y)

Especificamos um test_size de 0,2 para reservar 20% dos dados totais.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Etapas para alimentar o conjunto de treinamento e o conjunto de validação para nosso modelo

Step 1 - Para treinar nosso modelo, primeiro, vamos invocar o train_minibatchmétodo. Em seguida, forneça a ele um dicionário que mapeie os dados de entrada para a variável de entrada que usamos para definir o NN e sua função de perda associada.

trainer.train_minibatch({ features: X_train, label: y_train})

Step 2 - Em seguida, ligue train_minibatch usando o seguinte for loop -

for _epoch in range(10):
trainer.train_minbatch ({ feature: X_train, label: y_train})
print(‘Loss: {}, Acc: {}’.format(
trainer.previous_minibatch_loss_average,
trainer.previous_minibatch_evaluation_average))

Alimentando dados para o treinador - exemplo completo

from import pandas as pd
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, index_col=False)
x = df_source.iloc[:, :4].values
x = df_source[‘species’].values
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result
y = np.array([one_hot(label_mapping[v], 3) for v in y])
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0-2, stratify=y)
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
trainer.train_minibatch({ features: X_train, label: y_train})
for _epoch in range(10):
trainer.train_minbatch ({ feature: X_train, label: y_train})
print(‘Loss: {}, Acc: {}’.format(
trainer.previous_minibatch_loss_average,
trainer.previous_minibatch_evaluation_average))

Medindo o desempenho de NN

Para otimizar nosso modelo NN, sempre que passamos dados pelo treinador, ele mede o desempenho do modelo por meio da métrica que configuramos para o treinador. Essa medida de desempenho do modelo NN durante o treinamento é nos dados de treinamento. Mas, por outro lado, para uma análise completa do desempenho do modelo, precisamos usar dados de teste também.

Portanto, para medir o desempenho do modelo usando os dados de teste, podemos invocar o test_minibatch método no trainer como segue -

trainer.test_minibatch({ features: X_test, label: y_test})

Fazendo previsão com NN

Depois de treinar um modelo de aprendizado profundo, o mais importante é fazer previsões usando isso. Para fazer a previsão do NN treinado acima, podemos seguir os passos dados−

Step 1 - Primeiro, precisamos escolher um item aleatório do conjunto de teste usando a seguinte função -

np.random.choice

Step 2 - Em seguida, precisamos selecionar os dados de amostra do conjunto de teste usando sample_index.

Step 3 - Agora, a fim de converter a saída numérica para o NN em um rótulo real, crie um mapeamento invertido.

Step 4 - Agora, use o selecionado sampledados. Faça uma previsão invocando o NN z como uma função.

Step 5- Agora, uma vez que você obteve a saída prevista, pegue o índice do neurônio que tem o valor mais alto como o valor previsto. Isso pode ser feito usando onp.argmax função do numpy pacote.

Step 6 - Por último, converta o valor do índice no rótulo real usando inverted_mapping.

Fazendo previsões com NN - exemplo completo

sample_index = np.random.choice(X_test.shape[0])
sample = X_test[sample_index]
inverted_mapping = {
   1:’Iris-setosa’,
   2:’Iris-versicolor’,
   3:’Iris-virginica’
}
prediction = z(sample)
predicted_label = inverted_mapping[np.argmax(prediction)]
print(predicted_label)

Resultado

Depois de treinar o modelo de aprendizado profundo acima e executá-lo, você obterá o seguinte resultado -

Iris-versicolor

CNTK - In-Memory e grandes conjuntos de dados

Neste capítulo, aprenderemos como trabalhar com os conjuntos de dados na memória e grandes no CNTK.

Treinamento com pequenos conjuntos de dados de memória

Quando falamos sobre alimentar dados no treinador CNTK, pode haver muitas maneiras, mas vai depender do tamanho do conjunto de dados e formato dos dados. Os conjuntos de dados podem ser pequenos na memória ou grandes conjuntos de dados.

Nesta seção, trabalharemos com conjuntos de dados na memória. Para isso, usaremos as duas estruturas a seguir -

  • Numpy
  • Pandas

Usando matrizes Numpy

Aqui, trabalharemos com um conjunto de dados gerado aleatoriamente baseado em numpy no CNTK. Neste exemplo, vamos simular dados para um problema de classificação binária. Suponha que temos um conjunto de observações com 4 recursos e queremos prever dois rótulos possíveis com nosso modelo de aprendizado profundo.

Exemplo de Implementação

Para isso, primeiro devemos gerar um conjunto de rótulos contendo uma representação vetorial de um elemento dos rótulos que queremos prever. Isso pode ser feito com a ajuda das seguintes etapas -

Step 1 - Importe o numpy pacote da seguinte forma -

import numpy as np
num_samples = 20000

Step 2 - Em seguida, gere um mapeamento de rótulo usando np.eye funcionar da seguinte forma -

label_mapping = np.eye(2)

Step 3 - Agora usando np.random.choice função, colete as 20000 amostras aleatórias da seguinte forma -

y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)

Step 4 - Agora, finalmente, usando a função np.random.random, gere uma matriz de valores de ponto flutuante aleatório da seguinte forma -

x = np.random.random(size=(num_samples, 4)).astype(np.float32)

Uma vez que geramos uma matriz de valores de ponto flutuante aleatórios, precisamos convertê-los em números de ponto flutuante de 32 bits para que possam corresponder ao formato esperado pelo CNTK. Vamos seguir as etapas abaixo para fazer isso -

Step 5 - Importe as funções das camadas Densa e Sequencial do módulo cntk.layers da seguinte forma -

from cntk.layers import Dense, Sequential

Step 6- Agora, precisamos importar a função de ativação para as camadas da rede. Vamos importar osigmoid como função de ativação -

from cntk import input_variable, default_options
from cntk.ops import sigmoid

Step 7- Agora, precisamos importar a função de perda para treinar a rede. Deixe-nos importarbinary_cross_entropy como função de perda -

from cntk.losses import binary_cross_entropy

Step 8- Em seguida, precisamos definir as opções padrão para a rede. Aqui, estaremos fornecendo osigmoidfunção de ativação como uma configuração padrão. Além disso, crie o modelo usando a função da camada sequencial da seguinte maneira -

with default_options(activation=sigmoid):
model = Sequential([Dense(6),Dense(2)])

Step 9 - Em seguida, inicialize um input_variable com 4 recursos de entrada servindo como entrada para a rede.

features = input_variable(4)

Step 10 - Agora, para completá-lo, precisamos conectar a variável features ao NN.

z = model(features)

Então, agora temos um NN, com a ajuda das etapas a seguir, vamos treiná-lo usando um conjunto de dados na memória -

Step 11 - Para treinar este NN, primeiro precisamos importar o aluno de cntk.learnersmódulo. Vamos importarsgd aluno da seguinte forma -

from cntk.learners import sgd

Step 12 - Junto com essa importação, o ProgressPrinter de cntk.logging módulo também.

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

Step 13 - Em seguida, defina uma nova variável de entrada para os rótulos da seguinte forma -

labels = input_variable(2)

Step 14 - A fim de treinar o modelo NN, a seguir, precisamos definir uma perda usando o binary_cross_entropyfunção. Além disso, forneça o modelo zea variável de rótulos.

loss = binary_cross_entropy(z, labels)

Step 15 - Em seguida, inicialize o sgd aluno da seguinte forma -

learner = sgd(z.parameters, lr=0.1)

Step 16- Por fim, chame o método train na função de perda. Além disso, forneça-lhe os dados de entrada, osgd aluno e o progress_printer.−

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

Exemplo de implementação completo

import numpy as np
num_samples = 20000
label_mapping = np.eye(2)
y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)
x = np.random.random(size=(num_samples, 4)).astype(np.float32)
from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid
from cntk.losses import binary_cross_entropy
with default_options(activation=sigmoid):
   model = Sequential([Dense(6),Dense(2)])
features = input_variable(4)
z = model(features)
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(2)
loss = binary_cross_entropy(z, labels)
learner = sgd(z.parameters, lr=0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

Resultado

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average   since   average   since examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.52      1.52      0         0     32
1.51      1.51      0         0     96
1.48      1.46      0         0    224
1.45      1.42      0         0    480
1.42       1.4      0         0    992
1.41      1.39      0         0   2016
1.4       1.39      0         0   4064
1.39      1.39      0         0   8160
1.39      1.39      0         0  16352

Usando Pandas DataFrames

Matrizes Numpy são muito limitadas no que podem conter e uma das formas mais básicas de armazenamento de dados. Por exemplo, uma única matriz n-dimensional pode conter dados de um único tipo de dados. Mas, por outro lado, para muitos casos do mundo real, precisamos de uma biblioteca que possa lidar com mais de um tipo de dados em um único conjunto de dados.

Uma das bibliotecas Python chamada Pandas torna mais fácil trabalhar com esse tipo de conjunto de dados. Ele apresenta o conceito de DataFrame (DF) e nos permite carregar conjuntos de dados do disco armazenado em vários formatos como DFs. Por exemplo, podemos ler DFs armazenados como CSV, JSON, Excel, etc.

Você pode aprender a biblioteca Python Pandas em mais detalhes em https://www.tutorialspoint.com/python_pandas/index.htm.

Exemplo de Implementação

Neste exemplo, vamos usar o exemplo de classificação de três espécies possíveis de flores de íris com base em quatro propriedades. Também criamos esse modelo de aprendizado profundo nas seções anteriores. O modelo é o seguinte -

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)

O modelo acima contém uma camada oculta e uma camada de saída com três neurônios para corresponder ao número de classes que podemos prever.

Em seguida, usaremos o train método e lossfunção para treinar a rede. Para isso, primeiro devemos carregar e pré-processar o conjunto de dados da íris, de modo que corresponda ao layout e formato de dados esperados para o NN. Isso pode ser feito com a ajuda das seguintes etapas -

Step 1 - Importe o numpy e Pandas pacote da seguinte forma -

import numpy as np
import pandas as pd

Step 2 - Em seguida, use o read_csv função para carregar o conjunto de dados na memória -

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’,
 ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

Step 3 - Agora, precisamos criar um dicionário que mapeará os rótulos no conjunto de dados com sua representação numérica correspondente.

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 4 - Agora, usando iloc indexador no DataFrame, selecione as primeiras quatro colunas da seguinte forma -

x = df_source.iloc[:, :4].values

Step 5−Em seguida, precisamos selecionar as colunas de espécies como rótulos para o conjunto de dados. Isso pode ser feito da seguinte forma -

y = df_source[‘species’].values

Step 6 - Agora, precisamos mapear os rótulos no conjunto de dados, o que pode ser feito usando label_mapping. Além disso, useone_hot codificação para convertê-los em matrizes de codificação one-hot.

y = np.array([one_hot(label_mapping[v], 3) for v in y])

Step 7 - Em seguida, para usar os recursos e os rótulos mapeados com CNTK, precisamos convertê-los em flutuantes -

x= x.astype(np.float32)
y= y.astype(np.float32)

Como sabemos, os rótulos são armazenados no conjunto de dados como strings e o CNTK não pode funcionar com essas strings. Essa é a razão, ele precisa de vetores codificados com um elemento representando os rótulos. Para isso, podemos definir uma função, digamosone_hot como segue -

def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result

Agora, temos o array numpy no formato correto, com a ajuda das etapas a seguir, podemos usá-los para treinar nosso modelo -

Step 8- Primeiro, precisamos importar a função de perda para treinar a rede. Deixe-nos importarbinary_cross_entropy_with_softmax como função de perda -

from cntk.losses import binary_cross_entropy_with_softmax

Step 9 - Para treinar este NN, também precisamos importar o aluno de cntk.learnersmódulo. Vamos importarsgd aluno da seguinte forma -

from cntk.learners import sgd

Step 10 - Junto com essa importação, o ProgressPrinter de cntk.logging módulo também.

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

Step 11 - Em seguida, defina uma nova variável de entrada para os rótulos da seguinte forma -

labels = input_variable(3)

Step 12 - A fim de treinar o modelo NN, a seguir, precisamos definir uma perda usando o binary_cross_entropy_with_softmaxfunção. Forneça também o modelo ze a variável de rótulos.

loss = binary_cross_entropy_with_softmax (z, labels)

Step 13 - Em seguida, inicialize o sgd aluno da seguinte forma -

learner = sgd(z.parameters, 0.1)

Step 14- Por fim, chame o método train na função de perda. Além disso, forneça-lhe os dados de entrada, osgd aluno e o progress_printer.

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=
[progress_writer],minibatch_size=16,max_epochs=5)

Exemplo de implementação completo

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)
import numpy as np
import pandas as pd
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
x = df_source.iloc[:, :4].values
y = df_source[‘species’].values
y = np.array([one_hot(label_mapping[v], 3) for v in y])
x= x.astype(np.float32)
y= y.astype(np.float32)
def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result
from cntk.losses import binary_cross_entropy_with_softmax
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(3)
loss = binary_cross_entropy_with_softmax (z, labels)
learner = sgd(z.parameters, 0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer],minibatch_size=16,max_epochs=5)

Resultado

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average    since    average   since   examples
loss        last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.1         1.1        0       0      16
0.835     0.704        0       0      32
1.993      1.11        0       0      48
1.14       1.14        0       0     112
[………]

Treinamento com grandes conjuntos de dados

Na seção anterior, trabalhamos com pequenos conjuntos de dados na memória usando Numpy e pandas, mas nem todos os conjuntos de dados são tão pequenos. Especialmente os conjuntos de dados contendo imagens, vídeos e amostras de som são grandes.MinibatchSourceé um componente que pode carregar dados em blocos, fornecido pelo CNTK para trabalhar com conjuntos de dados tão grandes. Algumas das características doMinibatchSource os componentes são os seguintes -

  • MinibatchSource pode evitar que o NN super ajuste aleatoriamente automaticamente as amostras lidas da fonte de dados.

  • Possui pipeline de transformação integrado que pode ser usado para aumentar os dados.

  • Ele carrega os dados em um thread de segundo plano separado do processo de treinamento.

Nas seções a seguir, vamos explorar como usar uma fonte de minibatch com dados sem memória para trabalhar com grandes conjuntos de dados. Também exploraremos como podemos usá-lo para alimentar um NN.

Criação de instância MinibatchSource

Na seção anterior, usamos o exemplo de flor de íris e trabalhamos com um pequeno conjunto de dados na memória usando Pandas DataFrames. Aqui, estaremos substituindo o código que usa dados de um pandas DF porMinibatchSource. Primeiro, precisamos criar uma instância deMinibatchSource com a ajuda das seguintes etapas -

Exemplo de Implementação

Step 1 - Primeiro, de cntk.io módulo importe os componentes para a fonte de minibatch da seguinte forma -

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer,
 INFINITY_REPEAT

Step 2 - Agora, usando StreamDef classe, crie uma definição de fluxo para os rótulos.

labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)

Step 3 - Em seguida, crie para ler os recursos arquivados do arquivo de entrada, crie outra instância de StreamDef do seguinte modo.

feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)

Step 4 - Agora, precisamos fornecer iris.ctf arquivo como entrada e inicializar o deserializer como segue -

deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=
label_stream, features=features_stream)

Step 5 - Por fim, precisamos criar uma instância de minisourceBatch usando deserializer como segue -

Minibatch_source = MinibatchSource(deserializer, randomize=True)

Criando uma instância MinibatchSource - Exemplo de implementação completo

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True)

Criando arquivo MCTF

Como você viu acima, estamos pegando os dados do arquivo 'iris.ctf'. Possui o formato de arquivo denominado CNTK Text Format (CTF). É obrigatório criar um arquivo CTF para obter os dados para oMinibatchSourceinstância que criamos acima. Vamos ver como podemos criar um arquivo CTF.

Exemplo de Implementação

Step 1 - Primeiro, precisamos importar os pacotes pandas e numpy da seguinte forma -

import pandas as pd
import numpy as np

Step 2- Em seguida, precisamos carregar nosso arquivo de dados, ou seja, iris.csv na memória. Em seguida, armazene-o nodf_source variável.

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

Step 3 - Agora, usando ilocindexador como os recursos, pegue o conteúdo das primeiras quatro colunas. Além disso, use os dados da coluna de espécies da seguinte forma -

features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values

Step 4- Em seguida, precisamos criar um mapeamento entre o nome do rótulo e sua representação numérica. Isso pode ser feito criandolabel_mapping como segue -

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

Step 5 - Agora, converta os rótulos em um conjunto de vetores codificados de um hot como segue -

labels = [one_hot(label_mapping[v], 3) for v in labels]

Agora, como fizemos antes, crie uma função de utilidade chamada one_hotpara codificar os rótulos. Isso pode ser feito da seguinte forma -

def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result

Como carregamos e pré-processamos os dados, é hora de armazená-los em disco no formato de arquivo CTF. Podemos fazer isso com a ajuda do seguinte código Python -

With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

Criação de um arquivo MCTF - Exemplo de implementação completo

import pandas as pd
import numpy as np
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
labels = [one_hot(label_mapping[v], 3) for v in labels]
def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result
With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

Alimentando os dados

Depois de criar MinibatchSource,exemplo, precisamos treiná-lo. Podemos usar a mesma lógica de treinamento usada quando trabalhamos com pequenos conjuntos de dados na memória. Aqui, vamos usarMinibatchSource instância como a entrada para o método de trem na função de perda da seguinte forma -

Exemplo de Implementação

Step 1 - Para registrar a saída da sessão de treinamento, primeiro importe o ProgressPrinter de cntk.logging módulo da seguinte forma -

from cntk.logging import ProgressPrinter

Step 2 - Em seguida, para configurar a sessão de treinamento, importe o trainer e training_session de cntk.train módulo da seguinte forma -

from cntk.train import Trainer,

Step 3 - Agora, precisamos definir algum conjunto de constantes como minibatch_size, samples_per_epoch e num_epochs como segue -

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30

Step 4 - Em seguida, para saber o CNTK como ler dados durante o treinamento, precisamos definir um mapeamento entre a variável de entrada para a rede e os fluxos na fonte do minibatch.

input_map = {
     features: minibatch.source.streams.features,
     labels: minibatch.source.streams.features
}

Step 5 - Em seguida, para registrar a saída do processo de treinamento, inicialize o progress_printer variável com um novo ProgressPrinter instância da seguinte forma -

progress_writer = ProgressPrinter(0)

Step 6 - Por fim, precisamos invocar o método train na perda da seguinte forma -

train_history = loss.train(minibatch_source,
parameter_learners=[learner],
  model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

Alimentando os dados - Exemplo de implementação completo

from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
input_map = {
   features: minibatch.source.streams.features,
   labels: minibatch.source.streams.features
}
progress_writer = ProgressPrinter(0)
train_history = loss.train(minibatch_source,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

Resultado

-------------------------------------------------------------------
average   since   average   since  examples
loss      last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.21      1.21      0        0       32
1.15      0.12      0        0       96
[………]

CNTK - Medindo Desempenho

Este capítulo irá explicar como medir o desempenho do modelo no CNKT.

Estratégia para validar o desempenho do modelo

Depois de construir um modelo de ML, costumávamos treiná-lo usando um conjunto de amostras de dados. Por causa desse treinamento, nosso modelo de ML aprende e deriva algumas regras gerais. O desempenho do modelo de ML é importante quando fornecemos ao modelo novas amostras, ou seja, amostras diferentes das fornecidas no momento do treinamento. O modelo se comporta de maneira diferente nesse caso. Pode ser pior fazer uma boa previsão sobre essas novas amostras.

Mas o modelo também deve funcionar bem para novas amostras, porque no ambiente de produção obteremos uma entrada diferente daquela usada para os dados de amostra para fins de treinamento. É por isso que devemos validar o modelo de ML usando um conjunto de amostras diferente das amostras que usamos para fins de treinamento. Aqui, vamos discutir duas técnicas diferentes para criar um conjunto de dados para validar um NN.

Conjunto de dados de retenção

É um dos métodos mais fáceis de criar um conjunto de dados para validar um NN. Como o nome indica, neste método iremos reter um conjunto de amostras do treinamento (digamos, 20%) e usá-lo para testar o desempenho do nosso modelo de ML. O diagrama a seguir mostra a proporção entre as amostras de treinamento e validação -

O modelo de conjunto de dados de sustentação garante que tenhamos dados suficientes para treinar nosso modelo de ML e, ao mesmo tempo, teremos um número razoável de amostras para obter uma boa medição do desempenho do modelo.

Para incluir no conjunto de treinamento e no conjunto de teste, é uma boa prática escolher amostras aleatórias do conjunto de dados principal. Ele garante uma distribuição uniforme entre o conjunto de treinamento e teste.

A seguir está um exemplo em que estamos produzindo nosso próprio conjunto de dados de validação usando train_test_split função do scikit-learn biblioteca.

Exemplo

from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)
# Here above test_size = 0.2 represents that we provided 20% of the data as test data.
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
classifier_knn = KNeighborsClassifier(n_neighbors=3)
classifier_knn.fit(X_train, y_train)
y_pred = classifier_knn.predict(X_test)
# Providing sample data and the model will make prediction out of that data
sample = [[5, 5, 3, 2], [2, 4, 3, 5]]
preds = classifier_knn.predict(sample)
pred_species = [iris.target_names[p] for p in preds] print("Predictions:", pred_species)

Resultado

Predictions: ['versicolor', 'virginica']

Ao usar CNTK, precisamos randomizar a ordem de nosso conjunto de dados cada vez que treinamos nosso modelo porque -

  • Algoritmos de aprendizado profundo são altamente influenciados pelos geradores de números aleatórios.

  • A ordem em que fornecemos as amostras ao NN durante o treinamento afeta muito seu desempenho.

A principal desvantagem de usar a técnica de conjunto de dados de validação é que ela não é confiável porque às vezes obtemos resultados muito bons, mas às vezes, obtemos resultados ruins.

Validação cruzada K-fold

Para tornar nosso modelo de ML mais confiável, existe uma técnica chamada validação cruzada K-fold. Na natureza, a técnica de validação cruzada K-fold é a mesma que a técnica anterior, mas a repete várias vezes - geralmente cerca de 5 a 10 vezes. O diagrama a seguir representa seu conceito -

Trabalho de validação cruzada K-fold

O funcionamento da validação cruzada K-fold pode ser compreendido com a ajuda das seguintes etapas -

Step 1- Como na técnica de conjunto de dados Hand-out, na técnica de validação cruzada K-fold, primeiro precisamos dividir o conjunto de dados em um conjunto de treinamento e teste. Idealmente, a proporção é de 80-20, ou seja, 80% do conjunto de treinamento e 20% do conjunto de teste.

Step 2 - Em seguida, precisamos treinar nosso modelo usando o conjunto de treinamento.

Step 3- Por último, usaremos o conjunto de testes para medir o desempenho do nosso modelo. A única diferença entre a técnica de conjunto de dados Hold-out e a técnica de validação k-cross é que o processo acima é repetido geralmente de 5 a 10 vezes e, no final, a média é calculada sobre todas as métricas de desempenho. Essa média seria a métrica de desempenho final.

Vejamos um exemplo com um pequeno conjunto de dados -

Exemplo

from numpy import array
from sklearn.model_selection import KFold
data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
kfold = KFold(5, True, 1)
for train, test in kfold.split(data):
   print('train: %s, test: %s' % (data[train],(data[test]))

Resultado

train: [0.1 0.2 0.4 0.5 0.6 0.7 0.8 0.9], test: [0.3 1. ]
train: [0.1 0.2 0.3 0.4 0.6 0.8 0.9 1. ], test: [0.5 0.7]
train: [0.2 0.3 0.5 0.6 0.7 0.8 0.9 1. ], test: [0.1 0.4]
train: [0.1 0.3 0.4 0.5 0.6 0.7 0.9 1. ], test: [0.2 0.8]
train: [0.1 0.2 0.3 0.4 0.5 0.7 0.8 1. ], test: [0.6 0.9]

Como vemos, por usar um cenário de treinamento e teste mais realista, a técnica de validação cruzada k-fold nos dá uma medição de desempenho muito mais estável, mas, por outro lado, leva muito tempo para validar modelos de aprendizado profundo.

CNTK não oferece suporte para validação k-cross, portanto, precisamos escrever nosso próprio script para fazer isso.

Detectando underfitting e overfitting

Quer usemos o conjunto de dados Hand-out ou a técnica de validação cruzada k-fold, descobriremos que a saída para as métricas será diferente para o conjunto de dados usado para treinamento e o conjunto de dados usado para validação.

Detectando overfitting

O fenômeno chamado overfitting é uma situação em que nosso modelo de ML modela os dados de treinamento excepcionalmente bem, mas falha em ter um bom desempenho nos dados de teste, ou seja, não foi capaz de prever os dados de teste.

Acontece quando um modelo de ML aprende um padrão específico e ruído dos dados de treinamento a tal ponto que afeta negativamente a capacidade do modelo de generalizar a partir dos dados de treinamento para novos, ou seja, dados não vistos. Aqui, o ruído é a informação irrelevante ou aleatoriedade em um conjunto de dados.

A seguir estão as duas maneiras com a ajuda das quais podemos detectar se nosso modelo está ajustado demais ou não -

  • O modelo overfit terá um bom desempenho nas mesmas amostras que usamos para o treinamento, mas terá um desempenho muito ruim nas novas amostras, ou seja, amostras diferentes do treinamento.

  • O modelo é ajustado em excesso durante a validação se a métrica no conjunto de teste for inferior à mesma métrica que usamos em nosso conjunto de treinamento.

Detectando underfitting

Outra situação que pode surgir em nosso ML é underfitting. Esta é uma situação em que nosso modelo de ML não modelou bem os dados de treinamento e não consegue prever resultados úteis. Quando começamos a treinar na primeira época, nosso modelo será insuficiente, mas se tornará menos inadequado com o progresso do treinamento.

Uma das maneiras de detectar se nosso modelo é insuficiente ou não é examinar as métricas do conjunto de treinamento e do conjunto de teste. Nosso modelo será insuficiente se a métrica do conjunto de teste for maior do que a métrica do conjunto de treinamento.

CNTK - Classificação da Rede Neural

Neste capítulo, estudaremos como classificar a rede neural usando CNTK.

Introdução

A classificação pode ser definida como o processo de prever rótulos de saída ou respostas categóricas para os dados de entrada fornecidos. A saída categorizada, que será baseada no que o modelo aprendeu na fase de treinamento, pode ter a forma "Preto" ou "Branco" ou "spam" ou "sem spam".

Por outro lado, matematicamente, é a tarefa de aproximar uma função de mapeamento, digamos f das variáveis ​​de entrada, diga X, e as variáveis ​​de saída, diga Y.

Um exemplo clássico de problema de classificação pode ser a detecção de spam em e-mails. É óbvio que pode haver apenas duas categorias de saída, "spam" e "sem spam".

Para implementar tal classificação, primeiro precisamos fazer o treinamento do classificador onde os e-mails "spam" e "sem spam" seriam usados ​​como dados de treinamento. Uma vez que o classificador seja treinado com sucesso, ele pode ser usado para detectar um email desconhecido.

Aqui, vamos criar um 4-5-3 NN usando o conjunto de dados de flores de íris com o seguinte -

  • 4 nós de entrada (um para cada valor do preditor).

  • 5 nós de processamento ocultos.

  • Nós de 3 saídas (porque há três espécies possíveis no conjunto de dados da íris).

Carregando conjunto de dados

Estaremos usando o conjunto de dados de flores de íris, a partir do qual queremos classificar as espécies de flores de íris com base nas propriedades físicas de largura e comprimento da sépala e largura e comprimento da pétala. O conjunto de dados descreve as propriedades físicas de diferentes variedades de flores de íris -

  • Comprimento da sépala

  • Largura sépala

  • Comprimento da pétala

  • Largura da pétala

  • Classe ie iris setosa ou iris versicolor ou iris virginica

Nós temos iris.CSVarquivo que usamos antes em capítulos anteriores também. Pode ser carregado com a ajuda dePandasbiblioteca. Mas, antes de usá-lo ou carregá-lo para nosso classificador, precisamos preparar os arquivos de treinamento e teste, para que possa ser usado facilmente com o CNTK.

Preparando arquivos de treinamento e teste

O conjunto de dados Iris é um dos conjuntos de dados mais populares para projetos de ML. Tem 150 itens de dados e os dados brutos têm a seguinte aparência -

5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
…
7.0 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
…
6.3 3.3 6.0 2.5 virginica
5.8 2.7 5.1 1.9 virginica

Como dito anteriormente, os primeiros quatro valores em cada linha descrevem as propriedades físicas de diferentes variedades, ou seja, comprimento da sépala, largura da sépala, comprimento da pétala, largura da pétala das flores da íris.

Mas, devemos ter que converter os dados no formato, que pode ser facilmente usado pelo CNTK e esse formato é o arquivo .ctf (criamos um iris.ctf na seção anterior também). Será parecido com o seguinte -

|attribs 5.1 3.5 1.4 0.2|species 1 0 0
|attribs 4.9 3.0 1.4 0.2|species 1 0 0
…
|attribs 7.0 3.2 4.7 1.4|species 0 1 0
|attribs 6.4 3.2 4.5 1.5|species 0 1 0
…
|attribs 6.3 3.3 6.0 2.5|species 0 0 1
|attribs 5.8 2.7 5.1 1.9|species 0 0 1

Nos dados acima, a marca | atribs marca o início do valor do recurso e a | espécie marca os valores do rótulo da classe. Também podemos usar qualquer outro nome de tag de nossa preferência, até mesmo podemos adicionar o ID do item. Por exemplo, observe os seguintes dados -

|ID 001 |attribs 5.1 3.5 1.4 0.2|species 1 0 0 |#setosa
|ID 002 |attribs 4.9 3.0 1.4 0.2|species 1 0 0 |#setosa
…
|ID 051 |attribs 7.0 3.2 4.7 1.4|species 0 1 0 |#versicolor
|ID 052 |attribs 6.4 3.2 4.5 1.5|species 0 1 0 |#versicolor
…

Há um total de 150 itens de dados no conjunto de dados da íris e, para este exemplo, usaremos a regra do conjunto de dados de retenção 80-20, ou seja, 80% (120 itens) de itens de dados para fins de treinamento e 20% (30 itens) de itens de dados restantes para teste objetivo.

Construindo modelo de classificação

Primeiro, precisamos processar os arquivos de dados no formato CNTK e, para isso, usaremos a função auxiliar chamada create_reader como segue -

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src

Agora, precisamos definir os argumentos de arquitetura para nosso NN e também fornecer a localização dos arquivos de dados. Isso pode ser feito com a ajuda do seguinte código python -

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 data items)

Agora, com a ajuda da seguinte linha de código, nosso programa criará o NN não treinado -

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)

Agora, uma vez que criamos o modelo dual não treinado, precisamos configurar um objeto de algoritmo de Learner e depois usá-lo para criar um objeto de treinamento Trainer. Vamos usar o aluno SGD ecross_entropy_with_softmax função de perda -

tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Codifique o algoritmo de aprendizagem da seguinte forma -

max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Agora, uma vez que terminamos com o objeto Trainer, precisamos criar uma função de leitor para ler os dados de treinamento -

rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }

Agora é hora de treinar nosso modelo NN-

for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))

Depois de concluir o treinamento, vamos avaliar o modelo usando itens de dados de teste -

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)

Depois de avaliar a precisão do nosso modelo NN treinado, iremos usá-lo para fazer uma previsão em dados não vistos -

np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[6.4, 3.2, 4.5, 1.5]], dtype=np.float32)
print("\nPredicting Iris species for input features: ")
print(unknown[0]) pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])

Modelo de classificação completo

Import numpy as np
Import cntk as C
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 data items)
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])
if __name__== ”__main__”:
main()

Resultado

Using CNTK version = 2.7
batch 0: mean loss = 1.0986, mean accuracy = 40.00%
batch 500: mean loss = 0.6677, mean accuracy = 80.00%
batch 1000: mean loss = 0.5332, mean accuracy = 70.00%
batch 1500: mean loss = 0.2408, mean accuracy = 100.00%
Evaluating test data
Classification accuracy = 94.58%
Predicting species for input features:
[7.0 3.2 4.7 1.4]
Prediction probabilities:
[0.0847 0.736 0.113]

Salvando o modelo treinado

Este conjunto de dados Iris tem apenas 150 itens de dados, portanto, levaria apenas alguns segundos para treinar o modelo do classificador NN, mas o treinamento em um grande conjunto de dados com centenas ou mil itens de dados pode levar horas ou mesmo dias.

Podemos salvar nosso modelo para que não tenhamos que mantê-lo do zero. Com a ajuda do seguinte código Python, podemos salvar nosso NN treinado -

nn_classifier = “.\\neuralclassifier.model” #provide the name of the file
model.save(nn_classifier, format=C.ModelFormat.CNTKv2)

A seguir estão os argumentos de save() função usada acima -

  • O nome do arquivo é o primeiro argumento de save()função. Também pode ser escrito junto com o caminho do arquivo.

  • Outro parâmetro é o format parâmetro que tem um valor padrão C.ModelFormat.CNTKv2.

Carregando o modelo treinado

Depois de salvar o modelo treinado, é muito fácil carregar esse modelo. Só precisamos usar oload ()função. Vamos verificar isso no exemplo a seguir -

import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralclassifier.model”)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])

A vantagem do modelo salvo é que, depois de carregar um modelo salvo, ele pode ser usado exatamente como se o modelo tivesse acabado de ser treinado.

CNTK - Classificação Binária de Rede Neural

Vamos entender, neste capítulo, o que é classificação binária de rede neural usando CNTK.

A classificação binária usando NN é como a classificação multiclasse, a única coisa é que existem apenas dois nós de saída em vez de três ou mais. Aqui, vamos realizar a classificação binária usando uma rede neural usando duas técnicas, a saber, a técnica de um nó e a técnica de dois nós. A técnica de um nó é mais comum do que a técnica de dois nós.

Carregando conjunto de dados

Para ambas as técnicas para implementar usando NN, usaremos o conjunto de dados de notas. O conjunto de dados pode ser baixado do UCI Machine Learning Repository, que está disponível emhttps://archive.ics.uci.edu/ml/datasets/banknote+authentication.

Para o nosso exemplo, usaremos 50 itens de dados autênticos com falsificação de classe = 0 e os primeiros 50 itens falsos com falsificação de classe = 1.

Preparando arquivos de treinamento e teste

Existem 1372 itens de dados no conjunto de dados completo. O conjunto de dados brutos tem a seguinte aparência -

3.6216, 8.6661, -2.8076, -0.44699, 0
4.5459, 8.1674, -2.4586, -1.4621, 0
…
-1.3971, 3.3191, -1.3927, -1.9948, 1
0.39012, -0.14279, -0.031994, 0.35084, 1

Agora, primeiro precisamos converter esses dados brutos no formato CNTK de dois nós, que seria o seguinte -

|stats 3.62160000 8.66610000 -2.80730000 -0.44699000 |forgery 0 1 |# authentic 
|stats 4.54590000 8.16740000 -2.45860000 -1.46210000 |forgery 0 1 |# authentic 
. . .
|stats -1.39710000 3.31910000 -1.39270000 -1.99480000 |forgery 1 0 |# fake 
|stats 0.39012000 -0.14279000 -0.03199400 0.35084000 |forgery 1 0 |# fake

Você pode usar o seguinte programa python para criar dados no formato CNTK a partir de dados brutos -

fin = open(".\\...", "r") #provide the location of saved dataset text file.
for line in fin:
   line = line.strip()
   tokens = line.split(",")
   if tokens[4] == "0":
    print("|stats %12.8f %12.8f %12.8f %12.8f |forgery 0 1 |# authentic" % \
(float(tokens[0]), float(tokens[1]), float(tokens[2]), float(tokens[3])) )
   else:
    print("|stats %12.8f %12.8f %12.8f %12.8f |forgery 1 0 |# fake" % \
(float(tokens[0]), float(tokens[1]), float(tokens[2]), float(tokens[3])) )
fin.close()

Modelo de classificação binário de dois nós

Há muito pouca diferença entre a classificação de dois nós e a classificação multiclasse. Aqui nós primeiro precisamos processar os arquivos de dados no formato CNTK e para isso vamos usar a função auxiliar chamadacreate_reader como segue -

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src

Agora, precisamos definir os argumentos de arquitetura para nosso NN e também fornecer a localização dos arquivos de dados. Isso pode ser feito com a ajuda do seguinte código python -

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 10
output_dim = 2
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file

Agora, com a ajuda da seguinte linha de código, nosso programa criará o NN não treinado -

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)

Agora, uma vez que criamos o modelo dual não treinado, precisamos configurar um objeto de algoritmo de Learner e depois usá-lo para criar um objeto de treinamento Trainer. Vamos usar o aluno SGD e a função cross_entropy_with_softmax loss -

tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 500
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

Agora, uma vez que terminamos com o objeto Trainer, precisamos criar uma função de leitor para ler os dados de treinamento -

rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }

Agora, é hora de treinar nosso modelo NN -

for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))

Assim que o treinamento for concluído, vamos avaliar o modelo usando itens de dados de teste -

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)

Depois de avaliar a precisão do nosso modelo NN treinado, iremos usá-lo para fazer uma previsão em dados não vistos -

np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])
if pred_prob[0,0] < pred_prob[0,1]:
  print(“Prediction: authentic”)
else:
  print(“Prediction: fake”)

Modelo de classificação de dois nós completo

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 10
output_dim = 2
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
withC.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 500
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])
if pred_prob[0,0] < pred_prob[0,1]:
print(“Prediction: authentic”)
else:
print(“Prediction: fake”)
if __name__== ”__main__”:
main()

Resultado

Using CNTK version = 2.7
batch 0: mean loss = 0.6928, accuracy = 80.00%
batch 50: mean loss = 0.6877, accuracy = 70.00%
batch 100: mean loss = 0.6432, accuracy = 80.00%
batch 150: mean loss = 0.4978, accuracy = 80.00%
batch 200: mean loss = 0.4551, accuracy = 90.00%
batch 250: mean loss = 0.3755, accuracy = 90.00%
batch 300: mean loss = 0.2295, accuracy = 100.00%
batch 350: mean loss = 0.1542, accuracy = 100.00%
batch 400: mean loss = 0.1581, accuracy = 100.00%
batch 450: mean loss = 0.1499, accuracy = 100.00%
Evaluating test data
Classification accuracy = 84.58%
Predicting banknote authenticity for input features:
[0.6 1.9 -3.3 -0.3]
Prediction probabilities are:
[0.7847 0.2536]
Prediction: fake

Modelo de classificação binária de um nó

O programa de implementação é quase como fizemos acima para a classificação de dois nós. A principal mudança é quando se usa a técnica de classificação de dois nós.

Podemos usar a função de classificação_error () embutida do CNTK, mas no caso da classificação de um nó, o CNTK não suporta a função de classificação_error (). Essa é a razão pela qual precisamos implementar uma função definida pelo programa da seguinte forma -

def class_acc(mb, x_var, y_var, model):
num_correct = 0; num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
   p = model.eval(x_mat[i]
   y = y_mat[i]
   if p[0,0] < 0.5 and y[0,0] == 0.0 or p[0,0] >= 0.5 and y[0,0] == 1.0:
num_correct += 1
 else:
  num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)

Com essa mudança, vamos ver o exemplo completo de classificação de um nó -

Modelo de classificação completo de um nó

import numpy as np
import cntk as C
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='stats', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='forgery', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def class_acc(mb, x_var, y_var, model):
num_correct = 0; num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
  p = model.eval(x_mat[i]
  y = y_mat[i]
  if p[0,0] < 0.5 and y[0,0] == 0.0 or p[0,0] >= 0.5 and y[0,0] == 1.0:
  num_correct += 1
 else:
  num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 10
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file
test_file = ".\\...\\" #provide the name of the test file
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = oLayer
tr_loss = C.cross_entropy_with_softmax(model, Y)
max_iter = 1000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(model.parameters, learn_rate)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
banknote_input_map = {X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 100 == 0:
mcee=trainer.previous_minibatch_loss_average
ca = class_acc(curr_batch, X,Y, model)
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, ca))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
banknote_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map)
acc = class_acc(all_test, X,Y, model)
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[0.6, 1.9, -3.3, -0.3]], dtype=np.float32)
print("\nPredicting Banknote authenticity for input features: ")
print(unknown[0])
pred_prob = model.eval({X:unknown})
print("Prediction probability: ")
print(“%0.4f” % pred_prob[0,0])
if pred_prob[0,0] < 0.5:
  print(“Prediction: authentic”)
else:
  print(“Prediction: fake”)
if __name__== ”__main__”:
   main()

Resultado

Using CNTK version = 2.7
batch 0: mean loss = 0.6936, accuracy = 10.00%
batch 100: mean loss = 0.6882, accuracy = 70.00%
batch 200: mean loss = 0.6597, accuracy = 50.00%
batch 300: mean loss = 0.5298, accuracy = 70.00%
batch 400: mean loss = 0.4090, accuracy = 100.00%
batch 500: mean loss = 0.3790, accuracy = 90.00%
batch 600: mean loss = 0.1852, accuracy = 100.00%
batch 700: mean loss = 0.1135, accuracy = 100.00%
batch 800: mean loss = 0.1285, accuracy = 100.00%
batch 900: mean loss = 0.1054, accuracy = 100.00%
Evaluating test data
Classification accuracy = 84.00%
Predicting banknote authenticity for input features:
[0.6 1.9 -3.3 -0.3]
Prediction probability:
0.8846
Prediction: fake

CNTK - Regressão da Rede Neural

O capítulo o ajudará a entender a regressão da rede neural em relação ao CNTK.

Introdução

Como sabemos que, para prever um valor numérico de uma ou mais variáveis ​​preditoras, usamos a regressão. Vejamos um exemplo de previsão do valor médio de uma casa em, digamos, uma das 100 cidades. Para fazer isso, temos dados que incluem -

  • Uma estatística de crime para cada cidade.

  • A idade das casas em cada cidade.

  • Uma medida da distância de cada cidade a uma localização privilegiada.

  • A proporção aluno-professor em cada cidade.

  • Uma estatística demográfica racial para cada cidade.

  • O valor médio da casa em cada cidade.

Com base nessas cinco variáveis ​​de previsão, gostaríamos de prever o valor médio da casa. E para isso podemos criar um modelo de regressão linear ao longo das linhas de -

Y = a0+a1(crime)+a2(house-age)+(a3)(distance)+(a4)(ratio)+(a5)(racial)

Na equação acima -

Y é um valor mediano previsto

a0 é uma constante e

a1 a a5 todos são constantes associadas aos cinco preditores que discutimos acima.

Também temos uma abordagem alternativa de uso de uma rede neural. Isso criará um modelo de previsão mais preciso.

Aqui, estaremos criando um modelo de regressão de rede neural usando CNTK.

Carregando conjunto de dados

Para implementar a regressão de rede neural usando CNTK, usaremos o conjunto de dados de valores de casas da área de Boston. O conjunto de dados pode ser baixado do UCI Machine Learning Repository, que está disponível emhttps://archive.ics.uci.edu/ml/machine-learning-databases/housing/. Este conjunto de dados tem um total de 14 variáveis ​​e 506 instâncias.

Mas, para nosso programa de implementação, usaremos seis das 14 variáveis ​​e 100 instâncias. De 6, 5 como preditores e um como valor a prever. De 100 instâncias, usaremos 80 para treinamento e 20 para fins de teste. O valor que queremos prever é o preço médio de uma casa em uma cidade. Vamos ver os cinco preditores que usaremos -

  • Crime per capita in the town - Esperaríamos que valores menores fossem associados a esse preditor.

  • Proportion of owner - unidades ocupadas construídas antes de 1940 - Esperaríamos que valores menores fossem associados a este preditor porque um valor maior significa uma casa mais antiga.

  • Weighed distance of the town to five Boston employment centers.

  • Area school pupil-to-teacher ratio.

  • An indirect metric of the proportion of black residents in the town.

Preparando arquivos de treinamento e teste

Como fizemos antes, primeiro precisamos converter os dados brutos para o formato CNTK. Vamos usar os primeiros 80 itens de dados para fins de treinamento, portanto, o formato CNTK delimitado por tabulação é o seguinte -

|predictors 1.612820 96.90 3.76 21.00 248.31 |medval 13.50
|predictors 0.064170 68.20 3.36 19.20 396.90 |medval 18.90
|predictors 0.097440 61.40 3.38 19.20 377.56 |medval 20.00
. . .

Os próximos 20 itens, também convertidos para o formato CNTK, serão usados ​​para fins de teste.

Construindo modelo de regressão

Primeiro, precisamos processar os arquivos de dados no formato CNTK e para isso, vamos usar a função auxiliar chamada create_reader como segue -

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src

Em seguida, precisamos criar uma função auxiliar que aceite um objeto minilote CNTK e calcule uma métrica de precisão personalizada.

def mb_accuracy(mb, x_var, y_var, model, delta):
   num_correct = 0
   num_wrong = 0
   x_mat = mb[x_var].asarray()
   y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
  v = model.eval(x_mat[i])
  y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)

Agora, precisamos definir os argumentos de arquitetura para nosso NN e também fornecer a localização dos arquivos de dados. Isso pode ser feito com a ajuda do seguinte código python -

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)

Agora, com a ajuda da seguinte linha de código, nosso programa criará o NN não treinado -

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)

Agora, depois de criarmos o modelo dual não treinado, precisamos configurar um objeto de algoritmo do Learner. Vamos usar o aluno SGD esquared_error função de perda -

tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch=C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])

Agora, assim que terminarmos com o objeto de algoritmo de aprendizagem, precisamos criar uma função de leitor para ler os dados de treinamento -

rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }

Agora é hora de treinar nosso modelo NN -

for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
mcee = trainer.previous_minibatch_loss_average
acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))

Depois de concluir o treinamento, vamos avaliar o modelo usando itens de dados de teste -

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)

Depois de avaliar a precisão do nosso modelo NN treinado, iremos usá-lo para fazer uma previsão em dados não vistos -

np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])

Modelo de regressão completa

import numpy as np
import cntk as C
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def mb_accuracy(mb, x_var, y_var, model, delta):
num_correct = 0
num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
   v = model.eval(x_mat[i])
   y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)
tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch = C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
   mcee = trainer.previous_minibatch_loss_average
   acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
   print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))
   print("\nEvaluating test data \n")
   rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
   boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
   num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
if __name__== ”__main__”:
   main()

Resultado

Using CNTK version = 2.7
batch 0: mean squared error = 385.6727, accuracy = 0.00%
batch 300: mean squared error = 41.6229, accuracy = 20.00%
batch 600: mean squared error = 28.7667, accuracy = 40.00%
batch 900: mean squared error = 48.6435, accuracy = 40.00%
batch 1200: mean squared error = 77.9562, accuracy = 80.00%
batch 1500: mean squared error = 7.8342, accuracy = 60.00%
batch 1800: mean squared error = 47.7062, accuracy = 60.00%
batch 2100: mean squared error = 40.5068, accuracy = 40.00%
batch 2400: mean squared error = 46.5023, accuracy = 40.00%
batch 2700: mean squared error = 15.6235, accuracy = 60.00%
Evaluating test data
Prediction accuracy = 64.00%
Predicting median home value for feature/predictor values:
[0.09 50. 4.5 17. 350.]
Predicted value is:
$21.02(x1000)

Salvando o modelo treinado

Este conjunto de dados de valores da casa de Boston tem apenas 506 itens de dados (entre os quais processamos apenas 100). Conseqüentemente, levaria apenas alguns segundos para treinar o modelo do regressor NN, mas o treinamento em um grande conjunto de dados com centenas ou milhares de itens de dados pode levar horas ou mesmo dias.

Podemos salvar nosso modelo, para que não tenhamos que retê-lo do zero. Com a ajuda do seguinte código Python, podemos salvar nosso NN treinado -

nn_regressor = “.\\neuralregressor.model” #provide the name of the file
model.save(nn_regressor, format=C.ModelFormat.CNTKv2)

A seguir estão os argumentos da função save () usada acima -

  • O nome do arquivo é o primeiro argumento de save()função. Também pode ser escrito junto com o caminho do arquivo.

  • Outro parâmetro é o format parâmetro que tem um valor padrão C.ModelFormat.CNTKv2.

Carregando o modelo treinado

Depois de salvar o modelo treinado, é muito fácil carregar esse modelo. Precisamos apenas usar a função load (). Vamos verificar isso no exemplo a seguir -

import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralregressor.model”)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting area median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])

O benefício do modelo salvo é que, depois de carregar um modelo salvo, ele pode ser usado exatamente como se o modelo tivesse acabado de ser treinado.

CNTK - Modelo de Classificação

Este capítulo o ajudará a entender como medir o desempenho do modelo de classificação no CNTK. Vamos começar com a matriz de confusão.

Matriz de confusão

Matriz de confusão - uma tabela com a saída prevista versus a saída esperada é a maneira mais fácil de medir o desempenho de um problema de classificação, onde a saída pode ser de dois ou mais tipos de classes.

Para entender como funciona, vamos criar uma matriz de confusão para um modelo de classificação binária que prevê se uma transação com cartão de crédito foi normal ou uma fraude. É mostrado da seguinte forma -

Fraude real Normal real

Predicted fraud

Verdadeiro positivo

Falso positivo

Predicted normal

Falso negativo

Verdadeiro negativo

Como podemos ver, o exemplo de matriz de confusão acima contém 2 colunas, uma para fraude de classe e outra para normal de classe. Da mesma forma, temos 2 linhas, uma é adicionada para fraude de classe e outra é adicionada para classe normal. A seguir está a explicação dos termos associados à matriz de confusão -

  • True Positives - Quando a classe real e a classe prevista do ponto de dados são 1.

  • True Negatives - Quando a classe real e a classe prevista do ponto de dados são 0.

  • False Positives - Quando a classe real do ponto de dados é 0 e a classe prevista do ponto de dados é 1.

  • False Negatives - Quando a classe real do ponto de dados é 1 e a classe prevista do ponto de dados é 0.

Vamos ver como podemos calcular o número de coisas diferentes da matriz de confusão -

  • Accuracy- É o número de previsões corretas feitas por nosso modelo de classificação de ML. Pode ser calculado com a ajuda da seguinte fórmula -

  • Precision−Ele nos diz quantas amostras foram preditas corretamente de todas as amostras que previmos. Pode ser calculado com a ajuda da seguinte fórmula -

  • Recall or Sensitivity- Recall é o número de positivos retornados por nosso modelo de classificação de ML. Em outras palavras, ele nos informa quantos casos de fraude no conjunto de dados foram realmente detectados pelo modelo. Pode ser calculado com a ajuda da seguinte fórmula -

  • Specificity- Ao invés de lembrar, ele fornece o número de negativos retornados por nosso modelo de classificação de ML. Pode ser calculado com a ajuda da seguinte fórmula -

Medida F

Podemos usar a medida F como uma alternativa da matriz de confusão. A principal razão por trás disso é que não podemos maximizar o recall e a precisão ao mesmo tempo. Há uma relação muito forte entre essas métricas e isso pode ser entendido com a ajuda do exemplo a seguir -

Suponha que queremos usar um modelo DL para classificar as amostras de células como cancerosas ou normais. Aqui, para atingir a precisão máxima, precisamos reduzir o número de previsões para 1. Embora isso possa nos dar cerca de 100 por cento de precisão, mas a recuperação ficará muito baixa.

Por outro lado, se quisermos atingir o máximo de recall, precisamos fazer tantas previsões quanto possível. Embora isso possa nos dar cerca de 100 por cento de recall, mas a precisão se tornará muito baixa.

Na prática, precisamos encontrar uma maneira de equilibrar precisão e recall. A métrica de medida F nos permite fazer isso, pois expressa uma média harmônica entre precisão e recall.

Essa fórmula é chamada de medida F1, onde o termo extra chamado B é definido como 1 para obter uma proporção igual de precisão e recuperação. Para enfatizar a lembrança, podemos definir o fator B para 2. Por outro lado, para enfatizar a precisão, podemos definir o fator B para 0,5.

Usando CNTK para medir o desempenho da classificação

Na seção anterior, criamos um modelo de classificação usando o conjunto de dados de flores Iris. Aqui, estaremos medindo seu desempenho usando a matriz de confusão e a métrica F-measure.

Criando matriz de confusão

Já criamos o modelo, então podemos iniciar o processo de validação, que inclui confusion matrix, na mesma. Primeiro, vamos criar uma matriz de confusão com a ajuda doconfusion_matrix função de scikit-learn. Para isso, precisamos dos rótulos reais para nossas amostras de teste e os rótulos previstos para as mesmas amostras de teste.

Vamos calcular a matriz de confusão usando o seguinte código python -

from sklearn.metrics import confusion_matrix
y_true = np.argmax(y_test, axis=1)
y_pred = np.argmax(z(X_test), axis=1)
matrix = confusion_matrix(y_true=y_true, y_pred=y_pred)
print(matrix)

Resultado

[[10 0 0]
[ 0 1 9]
[ 0 0 10]]

Também podemos usar a função de mapa de calor para visualizar uma matriz de confusão da seguinte forma -

import seaborn as sns
import matplotlib.pyplot as plt
g = sns.heatmap(matrix,
     annot=True,
     xticklabels=label_encoder.classes_.tolist(),
     yticklabels=label_encoder.classes_.tolist(),
     cmap='Blues')
g.set_yticklabels(g.get_yticklabels(), rotation=0)
plt.show()

Devemos também ter um único número de desempenho, que podemos usar para comparar o modelo. Para isso, precisamos calcular o erro de classificação usandoclassification_error função, do pacote de métricas no CNTK como feito durante a criação do modelo de classificação.

Agora, para calcular o erro de classificação, execute o método de teste na função de perda com um conjunto de dados. Depois disso, o CNTK pegará as amostras que fornecemos como entrada para esta função e fará uma previsão com base nos recursos de entrada X_test.

loss.test([X_test, y_test])

Resultado

{'metric': 0.36666666666, 'samples': 30}

Implementando medidas F

Para implementar F-Measures, o CNTK também inclui uma função chamada fmeasures. Podemos usar esta função, enquanto treinamos o NN, substituindo a célulacntk.metrics.classification_error, com uma chamada para cntk.losses.fmeasure ao definir a função de fábrica de critérios da seguinte forma -

import cntk
@cntk.Function
def criterion_factory(output, target):
   loss = cntk.losses.cross_entropy_with_softmax(output, target)
metric = cntk.losses.fmeasure(output, target)
   return loss, metric

Depois de usar a função cntk.losses.fmeasure, obteremos uma saída diferente para o loss.test chamada de método fornecida a seguir -

loss.test([X_test, y_test])

Resultado

{'metric': 0.83101488749, 'samples': 30}

CNTK - Modelo de Regressão

Aqui, estudaremos sobre como medir o desempenho em relação a um modelo de regressão.

Noções básicas de validação de um modelo de regressão

Como sabemos, os modelos de regressão são diferentes dos modelos de classificação, no sentido de que não existe uma medida binária de certo ou errado para amostras de indivíduos. Em modelos de regressão, queremos medir o quão próxima a previsão está do valor real. Quanto mais próximo o valor de previsão estiver da saída esperada, melhor será o desempenho do modelo.

Aqui, vamos medir o desempenho do NN usado para regressão usando diferentes funções de taxa de erro.

Calculando margem de erro

Conforme discutido anteriormente, ao validar um modelo de regressão, não podemos dizer se uma previsão está certa ou errada. Queremos que nossa previsão seja o mais próximo possível do valor real. Mas, uma pequena margem de erro é aceitável aqui.

A fórmula para calcular a margem de erro é a seguinte -

Aqui,

Predicted value = indicado por um chapéu

Real value = previsto por y

Primeiro, precisamos calcular a distância entre o valor previsto e o valor real. Então, para obter uma taxa de erro geral, precisamos somar essas distâncias ao quadrado e calcular a média. Isso é chamado demean squared função de erro.

Mas, se quisermos números de desempenho que expressem uma margem de erro, precisamos de uma fórmula que expresse o erro absoluto. A fórmula paramean absolute a função de erro é a seguinte -

A fórmula acima considera a distância absoluta entre o valor predito e o valor real.

Usando CNTK para medir o desempenho de regressão

Aqui, veremos como usar as diferentes métricas que discutimos em combinação com o CNTK. Usaremos um modelo de regressão, que prevê milhas por galão para carros usando as etapas abaixo.

Etapas de implementação -

Step 1 - Primeiro, precisamos importar os componentes necessários do cntk pacote da seguinte forma -

from cntk import default_option, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import relu

Step 2 - Em seguida, precisamos definir uma função de ativação padrão usando o default_optionsfunções. Em seguida, crie um novo conjunto de camadas sequenciais e forneça duas camadas densas com 64 neurônios cada. Em seguida, adicionamos uma camada Densa adicional (que atuará como a camada de saída) ao conjunto de camadas Sequencial e fornecemos 1 neurônio sem uma ativação da seguinte maneira -

with default_options(activation=relu):
model = Sequential([Dense(64),Dense(64),Dense(1,activation=None)])

Step 3- Uma vez que a rede foi criada, precisamos criar um recurso de entrada. Precisamos ter certeza de que tem o mesmo formato dos recursos que usaremos para o treinamento.

features = input_variable(X.shape[1])

Step 4 - Agora, precisamos criar outro input_variable com tamanho 1. Será usado para armazenar o valor esperado para NN.

target = input_variable(1)
z = model(features)

Agora, precisamos treinar o modelo e, para isso, vamos dividir o conjunto de dados e realizar o pré-processamento usando as seguintes etapas de implementação -

Step 5−Primeiro, importe StandardScaler de sklearn.preprocessing para obter os valores entre -1 e +1. Isso nos ajudará contra a explosão de problemas de gradiente no NN.

from sklearn.preprocessing import StandardScalar

Step 6 - Em seguida, importe train_test_split de sklearn.model_selection da seguinte maneira−

from sklearn.model_selection import train_test_split

Step 7 - Largue o mpg coluna do conjunto de dados usando o dropmétodo. Por fim, divida o conjunto de dados em um conjunto de treinamento e validação usando otrain_test_split funcionar da seguinte forma -

x = df_cars.drop(columns=[‘mpg’]).values.astype(np.float32)
y=df_cars.iloc[: , 0].values.reshape(-1, 1).astype(np.float32)
scaler = StandardScaler()
X = scaler.fit_transform(x)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

Step 8 - Agora, precisamos criar outra input_variable com tamanho 1. Ela será usada para armazenar o valor esperado para NN.

target = input_variable(1)
z = model(features)

Dividimos e pré-processamos os dados, agora precisamos treinar o NN. Como fizemos nas seções anteriores durante a criação do modelo de regressão, precisamos definir uma combinação de uma perda emetric função para treinar o modelo.

import cntk
def absolute_error(output, target):
   return cntk.ops.reduce_mean(cntk.ops.abs(output – target))
@ cntk.Function
def criterion_factory(output, target):
   loss = squared_error(output, target)
   metric = absolute_error(output, target)
   return loss, metric

Agora, vamos dar uma olhada em como usar o modelo treinado. Para nosso modelo, usaremos criterion_factory como a combinação de perda e métrica.

from cntk.losses import squared_error
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_printer = ProgressPrinter(0)
loss = criterion_factory (z, target)
learner = sgd(z.parameters, 0.001)
training_summary=loss.train((x_train,y_train),parameter_learners=[learner],callbacks=[progress_printer],minibatch_size=16,max_epochs=10)

Exemplo de implementação completo

from cntk import default_option, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import relu
with default_options(activation=relu):
model = Sequential([Dense(64),Dense(64),Dense(1,activation=None)])
features = input_variable(X.shape[1])
target = input_variable(1)
z = model(features)
from sklearn.preprocessing import StandardScalar
from sklearn.model_selection import train_test_split
x = df_cars.drop(columns=[‘mpg’]).values.astype(np.float32)
y=df_cars.iloc[: , 0].values.reshape(-1, 1).astype(np.float32)
scaler = StandardScaler()
X = scaler.fit_transform(x)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
target = input_variable(1)
z = model(features)
import cntk
def absolute_error(output, target):
   return cntk.ops.reduce_mean(cntk.ops.abs(output – target))
@ cntk.Function
def criterion_factory(output, target):
loss = squared_error(output, target)
metric = absolute_error(output, target)
return loss, metric
from cntk.losses import squared_error
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_printer = ProgressPrinter(0)
loss = criterion_factory (z, target)
learner = sgd(z.parameters, 0.001)
training_summary=loss.train((x_train,y_train),parameter_learners=[learner],callbacks=[progress_printer],minibatch_size=16,max_epochs=10)

Resultado

-------------------------------------------------------------------
average  since   average   since  examples
loss     last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.001
690       690     24.9     24.9       16
654       636     24.1     23.7       48
[………]

Para validar nosso modelo de regressão, precisamos ter certeza de que o modelo lida com novos dados tão bem quanto com os dados de treinamento. Para isso, precisamos invocar otest método em loss e metric combinação com dados de teste da seguinte forma -

loss.test([X_test, y_test])

Output−

{'metric': 1.89679785619, 'samples': 79}

CNTK - Conjuntos de dados sem memória

Neste capítulo, será explicado como medir o desempenho de conjuntos de dados sem memória.

Nas seções anteriores, discutimos sobre vários métodos para validar o desempenho de nosso NN, mas os métodos que discutimos são aqueles que lidam com os conjuntos de dados que cabem na memória.

Aqui, surge a pergunta sobre os conjuntos de dados sem memória, porque no cenário de produção, precisamos de muitos dados para treinar NN. Nesta seção, vamos discutir como medir o desempenho ao trabalhar com fontes de minibatch e loop manual de minibatch.

Fontes de minibatch

Ao trabalhar com conjuntos de dados sem memória, ou seja, fontes de minibatch, precisamos de uma configuração ligeiramente diferente para perda, bem como métrica, do que a configuração que usamos ao trabalhar com pequenos conjuntos de dados, ou seja, conjuntos de dados em memória. Primeiro, veremos como configurar uma forma de alimentar o treinador do modelo NN.

A seguir estão as etapas de implementação -

Step 1 - Primeiro, de cntk.O módulo io importa os componentes para criar a fonte do minibatch da seguinte maneira−

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer,
 INFINITY_REPEAT

Step 2 - Em seguida, crie uma nova função chamada say create_datasource. Esta função terá dois parâmetros a saber, nome de arquivo e limite, com um valor padrão deINFINITELY_REPEAT.

def create_datasource(filename, limit =INFINITELY_REPEAT)

Step 3 - Agora, dentro da função, usando StreamDefclass crate uma definição de fluxo para os rótulos que lê do campo rótulos que tem três recursos. Também precisamos definiris_sparse para False como segue -

labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)

Step 4 - Em seguida, crie para ler os recursos arquivados do arquivo de entrada, crie outra instância de StreamDef do seguinte modo.

feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)

Step 5 - Agora, inicialize o CTFDeserializerclasse de instância. Especifique o nome do arquivo e os fluxos que precisamos desserializar da seguinte forma -

deserializer = CTFDeserializer(filename, StreamDefs(labels=
label_stream, features=features_stream)

Step 6 - Em seguida, precisamos criar uma instância de minisourceBatch usando o desserializador da seguinte forma -

Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source

Step 7- Por fim, precisamos fornecer fonte de treinamento e teste, que criamos nas seções anteriores também. Estamos usando o conjunto de dados de flores de íris.

training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)

Depois de criar MinibatchSourceexemplo, precisamos treiná-lo. Podemos usar a mesma lógica de treinamento usada quando trabalhamos com pequenos conjuntos de dados na memória. Aqui, vamos usarMinibatchSource exemplo, como a entrada para o método de trem na função de perda da seguinte forma -

A seguir estão as etapas de implementação -

Step 1 - Para registrar o resultado da sessão de treinamento, primeiro importe o ProgressPrinter de cntk.logging módulo da seguinte forma -

from cntk.logging import ProgressPrinter

Step 2 - Em seguida, para configurar a sessão de treinamento, importe o trainer e training_session de cntk.train módulo da seguinte forma -

from cntk.train import Trainer, training_session

Step 3 - Agora, precisamos definir algum conjunto de constantes como minibatch_size, samples_per_epoch e num_epochs como segue -

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs

Step 4 - A seguir, para saber como ler os dados durante o treinamento em CNTK, precisamos definir um mapeamento entre a variável de entrada da rede e os fluxos na fonte do minibatch.

input_map = {
   features: training_source.streams.features,
   labels: training_source.streams.labels
}

Step 5 - Em seguida, para registrar a saída do processo de treinamento, inicialize o progress_printer variável com um novo ProgressPrinterinstância. Além disso, inicialize otrainer e fornecê-lo com o modelo da seguinte maneira−

progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels

Step 6 - Por fim, para iniciar o processo de treinamento, precisamos invocar o training_session funcionar da seguinte forma -

session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()

Depois de treinar o modelo, podemos adicionar validação a esta configuração usando um TestConfig objeto e atribuí-lo ao test_config argumento de palavra-chave do train_session função.

A seguir estão as etapas de implementação -

Step 1 - Primeiro, precisamos importar o TestConfig classe do módulo cntk.train como segue -

from cntk.train import TestConfig

Step 2 - Agora, precisamos criar uma nova instância do TestConfig com o test_source como entrada−

Test_config = TestConfig(test_source)

Exemplo Completo

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
def create_datasource(filename, limit =INFINITELY_REPEAT)
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(filename, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source
training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)
from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs
input_map = {
   features:   training_source.streams.features,
   labels: training_source.streams.labels
 }
progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels
session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()
from cntk.train import TestConfig
Test_config = TestConfig(test_source)

Resultado

-------------------------------------------------------------------
average   since   average   since  examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.57      1.57     0.214    0.214   16
1.38      1.28     0.264    0.289   48
[………]
Finished Evaluation [1]: Minibatch[1-1]:metric = 69.65*30;

Loop de minibatch manual

Como vimos acima, é fácil medir o desempenho de nosso modelo NN durante e após o treinamento, usando as métricas ao treinar com APIs regulares em CNTK. Mas, por outro lado, as coisas não serão tão fáceis ao trabalhar com um loop de minibatch manual.

Aqui, estamos usando o modelo fornecido abaixo com 4 entradas e 3 saídas do conjunto de dados Iris Flower, criado também nas seções anteriores -

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu, sigmoid
from cntk.learners import sgd
model = Sequential([
   Dense(4, activation=sigmoid),
   Dense(3, activation=log_softmax)
])
features = input_variable(4)
labels = input_variable(3)
z = model(features)

Em seguida, a perda para o modelo é definida como a combinação da função de perda de entropia cruzada e a métrica de medida F como usada nas seções anteriores. Vamos usar ocriterion_factory utilitário, para criá-lo como um objeto de função CNTK, conforme mostrado abaixo -

import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}

Agora, como definimos a função de perda, veremos como podemos usá-la no treinador, para configurar uma sessão de treinamento manual.

A seguir estão as etapas de implementação -

Step 1 - Primeiro, precisamos importar os pacotes necessários, como numpy e pandas para carregar e pré-processar os dados.

import pandas as pd
import numpy as np

Step 2 - Em seguida, para registrar informações durante o treinamento, importe o ProgressPrinter classe como segue -

from cntk.logging import ProgressPrinter

Step 3 - Então, precisamos importar o módulo do treinador do módulo cntk.train da seguinte forma -

from cntk.train import Trainer

Step 4 - Em seguida, crie uma nova instância de ProgressPrinter como segue -

progress_writer = ProgressPrinter(0)

Step 5 - Agora, precisamos inicializar o treinador com os parâmetros a perda, o aluno e o progress_writer como segue -

trainer = Trainer(z, loss, learner, progress_writer)

Step 6−A seguir, para treinar o modelo, criaremos um loop que irá iterar sobre o conjunto de dados trinta vezes. Este será o ciclo de treinamento externo.

for _ in range(0,30):

Step 7- Agora, precisamos carregar os dados do disco usando o pandas. Então, para carregar o conjunto de dados emmini-batches, colocou o chunksize argumento de palavra-chave para 16.

input_data = pd.read_csv('iris.csv',
names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)

Step 8 - Agora, crie um treinamento interno para que o loop itere sobre cada um dos mini-batches.

for df_batch in input_data:

Step 9 - Agora, dentro deste loop, leia as primeiras quatro colunas usando o iloc indexador, como o features para treinar e convertê-los em float32 -

feature_values = df_batch.iloc[:,:4].values
feature_values = feature_values.astype(np.float32)

Step 10 - Agora, leia a última coluna como os rótulos para treinar, como segue -

label_values = df_batch.iloc[:,-1]

Step 11 - A seguir, usaremos vetores one-hot para converter as strings de rótulo em sua apresentação numérica da seguinte forma -

label_values = label_values.map(lambda x: label_mapping[x])

Step 12- Em seguida, faça a apresentação numérica das etiquetas. Em seguida, converta-os em uma matriz numpy, para que seja mais fácil trabalhar com eles da seguinte maneira -

label_values = label_values.values

Step 13 - Agora, precisamos criar uma nova matriz numpy que tenha o mesmo número de linhas que os valores de rótulo que convertemos.

encoded_labels = np.zeros((label_values.shape[0], 3))

Step 14 - Agora, a fim de criar rótulos com codificação one-hot, selecione as colunas com base nos valores numéricos dos rótulos.

encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.

Step 15 - Por fim, precisamos invocar o train_minibatch no treinador e fornecer os recursos processados ​​e rótulos para o minibatch.

trainer.train_minibatch({features: feature_values, labels: encoded_labels})

Exemplo Completo

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu, sigmoid
from cntk.learners import sgd
model = Sequential([
   Dense(4, activation=sigmoid),
   Dense(3, activation=log_softmax)
])
features = input_variable(4)
labels = input_variable(3)
z = model(features)
import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}
import pandas as pd
import numpy as np
from cntk.logging import ProgressPrinter
from cntk.train import Trainer
progress_writer = ProgressPrinter(0)
trainer = Trainer(z, loss, learner, progress_writer)
for _ in range(0,30):
   input_data = pd.read_csv('iris.csv',
      names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
      index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
label_values = label_values.map(lambda x: label_mapping[x])
label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), 
label_values] = 1.
   trainer.train_minibatch({features: feature_values, labels: encoded_labels})

Resultado

-------------------------------------------------------------------
average    since    average   since  examples
loss       last      metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.45       1.45     -0.189    -0.189   16
1.24       1.13     -0.0382    0.0371  48
[………]

Na saída acima, obtivemos a saída para a perda e a métrica durante o treinamento. É porque combinamos uma métrica e uma perda em um objeto de função e usamos uma impressora de progresso na configuração do treinador.

Agora, a fim de avaliar o desempenho do modelo, precisamos realizar a mesma tarefa do treinamento do modelo, mas desta vez, precisamos usar um Evaluatorinstância para testar o modelo. É mostrado no seguinte código Python−

from cntk import Evaluator
evaluator = Evaluator(loss.outputs[1], [progress_writer])
input_data = pd.read_csv('iris.csv',
   names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
   label_values = label_values.map(lambda x: label_mapping[x])
   label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.
   evaluator.test_minibatch({ features: feature_values, labels:
      encoded_labels})
evaluator.summarize_test_progress()

Agora, obteremos a saída algo como o seguinte−

Resultado

Finished Evaluation [1]: Minibatch[1-11]:metric = 74.62*143;

CNTK - Monitorando o Modelo

Neste capítulo, vamos entender como monitorar um modelo no CNTK.

Introdução

Nas seções anteriores, fizemos algumas validações em nossos modelos NN. Mas também é necessário e possível monitorar nosso modelo durante o treinamento?

Sim, ja usamos ProgressWriterpara monitorar nosso modelo e há muitas outras maneiras de fazer isso. Antes de nos aprofundarmos nos métodos, primeiro vamos dar uma olhada em como funciona o monitoramento em CNTK e como podemos usá-lo para detectar problemas em nosso modelo NN.

Chamadas de retorno em CNTK

Na verdade, durante o treinamento e a validação, o CNTK nos permite especificar callbacks em vários pontos da API. Primeiro, vamos examinar mais de perto quando o CNTK invoca retornos de chamada.

Quando o CNTK invoca retornos de chamada?

O CNTK irá invocar os callbacks nos momentos de treinamento e teste quando -

  • Um minibatch é concluído.

  • Uma varredura completa sobre o conjunto de dados é concluída durante o treinamento.

  • Um minibatch de teste é concluído.

  • Uma varredura completa no conjunto de dados é concluída durante o teste.

Especificando retornos de chamada

Ao trabalhar com o CNTK, podemos especificar retornos de chamada em vários pontos da API. Por exemplo -

Quando chamar o trem em uma função de perda?

Aqui, quando chamamos train em uma função de perda, podemos especificar um conjunto de callbacks por meio do argumento callbacks como segue−

training_summary=loss.train((x_train,y_train),
parameter_learners=[learner],
callbacks=[progress_writer]),
minibatch_size=16, max_epochs=15)

Ao trabalhar com fontes de minibatch ou usar um loop de minibatch manual

Neste caso, podemos especificar retornos de chamada para fins de monitoramento ao criar o Trainer como segue -

from cntk.logging import ProgressPrinter
callbacks = [
   ProgressPrinter(0)
]
Trainer = Trainer(z, (loss, metric), learner, [callbacks])

Várias ferramentas de monitoramento

Vamos estudar sobre diferentes ferramentas de monitoramento.

ProgressPrinter

Ao ler este tutorial, você encontrará ProgressPrintercomo a ferramenta de monitoramento mais utilizada. Algumas das características deProgressPrinter ferramenta de monitoramento são-

ProgressPrinterclasse implementa log básico baseado em console para monitorar nosso modelo. Ele pode registrar no disco que quisermos.

Especialmente útil ao trabalhar em um cenário de treinamento distribuído.

Também é muito útil ao trabalhar em um cenário em que não podemos fazer login no console para ver a saída de nosso programa Python.

Com a ajuda do código a seguir, podemos criar uma instância de ProgressPrinter-

ProgressPrinter(0, log_to_file=’test.txt’)

Obteremos a saída de algo que vimos nas seções anteriores -

Test.txt
CNTKCommandTrainInfo: train : 300
CNTKCommandTrainInfo: CNTKNoMoreCommands_Total : 300
CNTKCommandTrainBegin: train
-------------------------------------------------------------------
average since average since examples
loss last metric last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.45 1.45 -0.189 -0.189 16
1.24 1.13 -0.0382 0.0371 48
[………]

TensorBoard

Uma das desvantagens de usar o ProgressPrinter é que não podemos ter uma boa visão de como a perda e o progresso da métrica ao longo do tempo são difíceis. TensorBoardProgressWriter é uma ótima alternativa para a classe ProgressPrinter no CNTK.

Antes de usá-lo, precisamos primeiro instalá-lo com a ajuda do seguinte comando -

pip install tensorboard

Agora, para usar o TensorBoard, precisamos configurar TensorBoardProgressWriter em nosso código de treinamento da seguinte maneira−

import time
from cntk.logging import TensorBoardProgressWriter
tensorbrd_writer = TensorBoardProgressWriter(log_dir=’logs/{}’.format(time.time()),freq=1,model=z)

É uma boa prática chamar o método de fechamento em TensorBoardProgressWriter exemplo depois de feito com o treinamento de NNmodelo.

Podemos visualizar o TensorBoard registrando dados com a ajuda do seguinte comando -

Tensorboard –logdir logs

CNTK - Rede Neural Convolucional

Neste capítulo, vamos estudar como construir uma Rede Neural Convolucional (CNN) no CNTK.

Introdução

As redes neurais convolucionais (CNNs) também são compostas por neurônios, que têm pesos e vieses aprendíveis. É por isso que, dessa maneira, eles são como redes neurais comuns (NNs).

Se nos lembrarmos do funcionamento de NNs comuns, cada neurônio recebe uma ou mais entradas, faz uma soma ponderada e passou por uma função de ativação para produzir a saída final. Aqui, surge a questão de que, se CNNs e NNs comuns têm tantas semelhanças, o que torna essas duas redes diferentes uma da outra?

O que os torna diferentes é o tratamento de dados de entrada e tipos de camadas? A estrutura dos dados de entrada é ignorada no NN comum e todos os dados são convertidos em array 1-D antes de alimentá-los na rede.

Porém, a arquitetura de Rede Neural Convolucional pode considerar a estrutura 2D das imagens, processá-las e permitir que extraia as propriedades que são específicas das imagens. Além disso, as CNNs têm a vantagem de ter uma ou mais camadas convolucionais e camadas de pooling, que são os principais blocos de construção das CNNs.

Essas camadas são seguidas por uma ou mais camadas totalmente conectadas como em NNs multicamadas padrão. Então, podemos pensar na CNN, como um caso especial de redes totalmente conectadas.

Arquitetura de Rede Neural Convolucional (CNN)

A arquitetura da CNN é basicamente uma lista de camadas que transforma o volume tridimensional, ou seja, largura, altura e profundidade do volume da imagem em um volume de saída tridimensional. Um ponto importante a se notar aqui é que cada neurônio na camada atual está conectado a um pequeno patch da saída da camada anterior, que é como sobrepor um filtro N * N na imagem de entrada.

Ele usa filtros M, que são basicamente extratores de recursos que extraem recursos como bordas, cantos e assim por diante. A seguir estão as camadas [INPUT-CONV-RELU-POOL-FC] que são usados ​​para construir redes neurais convolucionais (CNNs) -

  • INPUT- Como o nome indica, esta camada contém os valores de pixel brutos. Os valores de pixel brutos significam os dados da imagem como ela é. Exemplo, INPUT [64 × 64 × 3] é uma imagem RGB de 3 canais de largura-64, altura-64 e profundidade-3.

  • CONV- Esta camada é um dos blocos de construção das CNNs, pois a maior parte da computação é feita nesta camada. Exemplo - se usarmos 6 filtros na ENTRADA mencionada acima [64 × 64 × 3], isso pode resultar no volume [64 × 64 × 6].

  • RELU−Também chamado de camada de unidade linear retificada, que aplica uma função de ativação à saída da camada anterior. De outra maneira, uma não linearidade seria adicionada à rede por RELU.

  • POOL- Esta camada, ou seja, a camada Pooling, é outro bloco de construção das CNNs. A principal tarefa dessa camada é a redução da amostragem, o que significa que ela opera independentemente em cada fatia da entrada e a redimensiona espacialmente.

  • FC- É chamada de camada Fully Connected ou, mais especificamente, camada de saída. É usado para calcular a pontuação da classe de saída e a saída resultante é um volume de tamanho 1 * 1 * L, onde L é o número correspondente à pontuação da classe.

O diagrama abaixo representa a arquitetura típica das CNNs-

Criando estrutura CNN

Vimos a arquitetura e os fundamentos da CNN, agora vamos construir uma rede convolucional usando CNTK. Aqui, primeiro veremos como montar a estrutura da CNN e depois veremos como treinar seus parâmetros.

Por fim, veremos como podemos melhorar a rede neural alterando sua estrutura com várias configurações de camadas diferentes. Vamos usar o conjunto de dados de imagens MNIST.

Então, primeiro vamos criar uma estrutura CNN. Geralmente, quando construímos uma CNN para reconhecer padrões em imagens, fazemos o seguinte−

  • Usamos uma combinação de camadas de convolução e pooling.

  • Uma ou mais camadas ocultas no final da rede.

  • Por fim, finalizamos a rede com uma camada softmax para fins de classificação.

Com a ajuda das etapas a seguir, podemos construir a estrutura da rede -

Step 1- Primeiro, precisamos importar as camadas necessárias para a CNN.

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling

Step 2- Em seguida, precisamos importar as funções de ativação para CNN.

from cntk.ops import log_softmax, relu

Step 3- Depois disso, para inicializar as camadas convolucionais mais tarde, precisamos importar o glorot_uniform_initializer como segue -

from cntk.initializer import glorot_uniform

Step 4- Em seguida, para criar variáveis ​​de entrada, importe o input_variablefunção. E importardefault_option função, para tornar a configuração do NN um pouco mais fácil.

from cntk import input_variable, default_options

Step 5- Agora, para armazenar as imagens de entrada, crie um novo input_variable. Ele conterá três canais: vermelho, verde e azul. Ele teria o tamanho de 28 por 28 pixels.

features = input_variable((3,28,28))

Step 6−Em seguida, precisamos criar outro input_variable para armazenar os rótulos para prever.

labels = input_variable(10)

Step 7- Agora, precisamos criar o default_optionpara o NN. E, precisamos usar oglorot_uniform como a função de inicialização.

with default_options(initialization=glorot_uniform, activation=relu):

Step 8- A seguir, para definir a estrutura do NN, precisamos criar um novo Sequential conjunto de camadas.

Step 9- Agora precisamos adicionar um Convolutional2D camada com um filter_shape de 5 e um strides definição de 1, dentro do Sequentialconjunto de camadas. Além disso, ative o preenchimento, para que a imagem seja preenchida para manter as dimensões originais.

model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),

Step 10- Agora é hora de adicionar um MaxPooling camada com filter_shape de 2 e um strides configuração de 2 para comprimir a imagem pela metade.

MaxPooling(filter_shape=(2,2), strides=(2,2)),

Step 11- Agora, como fizemos na etapa 9, precisamos adicionar outro Convolutional2D camada com um filter_shape de 5 e um stridesconfiguração de 1, use 16 filtros. Além disso, ative o preenchimento, para que o tamanho da imagem produzida pela camada de pool anterior seja mantido.

Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),

Step 12- Agora, como fizemos na etapa 10, adicione outro MaxPooling camada com um filter_shape de 3 e um strides configuração de 3 para reduzir a imagem a um terço.

MaxPooling(filter_shape=(3,3), strides=(3,3)),

Step 13- Por fim, adicione uma camada Densa com dez neurônios para as 10 classes possíveis, a rede pode prever. Para transformar a rede em um modelo de classificação, use umlog_siftmax função de ativação.

Dense(10, activation=log_softmax)
])

Exemplo completo para a criação de estrutura CNN

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)

Treinamento CNN com imagens

Como criamos a estrutura da rede, é hora de treinar a rede. Mas antes de iniciar o treinamento de nossa rede, precisamos configurar fontes de minibatch, pois treinar um NN que trabalha com imagens requer mais memória do que a maioria dos computadores.

Já criamos fontes de minibatch nas seções anteriores. A seguir está o código Python para configurar duas fontes de minibatch -

Como temos o create_datasource função, agora podemos criar duas fontes de dados separadas (treinamento e teste) para treinar o modelo.

train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)

Agora, como preparamos as imagens, podemos começar a treinar nosso NN. Como fizemos nas seções anteriores, podemos usar o método de trem na função de perda para iniciar o treinamento. A seguir está o código para isso -

from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)

Com a ajuda do código anterior, configuramos a perda e o aluno para o NN. O código a seguir irá treinar e validar o NN−

from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   labels: train_datasource.streams.labels
}
loss.train(train_datasource,
     max_epochs=10,
     minibatch_size=64,
     epoch_size=60000,
        parameter_learners=[learner],
     model_inputs_to_streams=input_map,
     callbacks=[progress_writer, test_config])

Exemplo de implementação completo

from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
   Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
   mapping_file = os.path.join(folder, 'mapping.bin')
   image_transforms = []
   if train:
    image_transforms += [
     xforms.crop(crop_type='randomside', side_ratio=0.8),
     xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
   stream_definitions = StreamDefs(
   features=StreamDef(field='image', transforms=image_transforms),
    labels=StreamDef(field='label', shape=10)
)
   deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
   loss = cross_entropy_with_softmax(output, targets)
   metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   labels: train_datasource.streams.labels
}
loss.train(train_datasource,
     max_epochs=10,
     minibatch_size=64,
     epoch_size=60000,
        parameter_learners=[learner],
     model_inputs_to_streams=input_map,
     callbacks=[progress_writer, test_config])

Resultado

-------------------------------------------------------------------
average  since  average  since  examples
loss     last   metric   last
------------------------------------------------------
Learning rate per minibatch: 0.2
142      142      0.922   0.922    64
1.35e+06 1.51e+07 0.896   0.883    192
[………]

Transformações de imagem

Como vimos, é difícil treinar NN usados ​​para reconhecimento de imagem e, para treinar, eles também exigem muitos dados. Mais um problema é que eles tendem a se ajustar demais às imagens usadas durante o treinamento. Vejamos com um exemplo, quando temos fotos de rostos na posição vertical, nosso modelo terá dificuldade em reconhecer rostos que são girados em outra direção.

Para contornar esse problema, podemos usar o aumento de imagem e o CNTK suporta transformações específicas, ao criar fontes de minibatch para imagens. Podemos usar várias transformações como segue−

  • Podemos cortar aleatoriamente imagens usadas para treinamento com apenas algumas linhas de código.

  • Podemos usar uma escala e uma cor também.

Vamos ver, com a ajuda do seguinte código Python, como podemos alterar a lista de transformações incluindo uma transformação de recorte dentro da função usada para criar a origem do minibatch anteriormente.

import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
   mapping_file = os.path.join(folder, 'mapping.bin')
   image_transforms = []
   if train:
   image_transforms += [
     xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
   stream_definitions = StreamDefs(
   features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
   deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)

Com a ajuda do código acima, podemos aprimorar a função para incluir um conjunto de transformações de imagem, para que, quando estivermos em treinamento, possamos recortar a imagem aleatoriamente, para obtermos mais variações da imagem.

CNTK - Rede Neural Recorrente

Agora, vamos entender como construir uma Rede Neural Recorrente (RNN) em CNTK.

Introdução

Aprendemos como classificar imagens com uma rede neural, e é uma das tarefas icônicas do aprendizado profundo. Mas, outra área onde a rede neural se destaca e muitas pesquisas acontecendo são as Redes Neurais Recorrentes (RNN). Aqui, vamos saber o que é RNN e como ele pode ser usado em cenários em que precisamos lidar com dados de série temporal.

O que é Rede Neural Recorrente?

Redes neurais recorrentes (RNNs) podem ser definidas como a raça especial de NNs que são capazes de raciocinar ao longo do tempo. Os RNNs são usados ​​principalmente em cenários, nos quais precisamos lidar com valores que mudam com o tempo, ou seja, dados de séries temporais. Para entendê-lo de uma maneira melhor, vamos fazer uma pequena comparação entre redes neurais regulares e redes neurais recorrentes -

  • Como sabemos que, em uma rede neural regular, podemos fornecer apenas uma entrada. Isso o limita a resultados em apenas uma previsão. Para dar um exemplo, podemos fazer o trabalho de tradução de texto usando redes neurais regulares.

  • Por outro lado, em redes neurais recorrentes, podemos fornecer uma sequência de amostras que resulta em uma única previsão. Em outras palavras, usando RNNs, podemos prever uma sequência de saída com base em uma sequência de entrada. Por exemplo, houve alguns experimentos bem-sucedidos com RNN em tarefas de tradução.

Usos da rede neural recorrente

Os RNNs podem ser usados ​​de várias maneiras. Alguns deles são os seguintes -

Prevendo uma única saída

Antes de mergulhar fundo nas etapas, como o RNN pode prever uma única saída com base em uma sequência, vamos ver como é um RNN básico -

Como podemos no diagrama acima, RNN contém uma conexão de loopback para a entrada e sempre que alimentamos uma sequência de valores, ele processará cada elemento na sequência como etapas de tempo.

Além disso, por causa da conexão de loopback, o RNN pode combinar a saída gerada com a entrada para o próximo elemento na sequência. Desta forma, o RNN construirá uma memória sobre toda a sequência que pode ser usada para fazer uma previsão.

A fim de fazer a previsão com RNN, podemos realizar as seguintes etapas−

  • Primeiro, para criar um estado inicial oculto, precisamos alimentar o primeiro elemento da sequência de entrada.

  • Depois disso, para produzir um estado oculto atualizado, precisamos pegar o estado oculto inicial e combiná-lo com o segundo elemento na sequência de entrada.

  • Por fim, para produzir o estado oculto final e prever a saída para o RNN, precisamos pegar o elemento final na sequência de entrada.

Dessa forma, com a ajuda dessa conexão de loopback, podemos ensinar um RNN a reconhecer padrões que acontecem com o tempo.

Prevendo uma sequência

O modelo básico, discutido acima, de RNN pode ser estendido para outros casos de uso também. Por exemplo, podemos usá-lo para prever uma sequência de valores com base em uma única entrada. Neste cenário, para fazer a previsão com RNN, podemos realizar as seguintes etapas -

  • Primeiro, para criar um estado inicial oculto e prever o primeiro elemento na sequência de saída, precisamos alimentar uma amostra de entrada na rede neural.

  • Depois disso, para produzir um estado oculto atualizado e o segundo elemento na sequência de saída, precisamos combinar o estado oculto inicial com a mesma amostra.

  • Por fim, para atualizar o estado oculto mais uma vez e prever o elemento final na sequência de saída, alimentamos a amostra outra vez.

Prever sequências

Como vimos, como prever um único valor com base em uma sequência e como prever uma sequência com base em um único valor. Agora vamos ver como podemos prever sequências para sequências. Neste cenário, para fazer a previsão com RNN, podemos realizar as seguintes etapas -

  • Primeiro, para criar um estado inicial oculto e prever o primeiro elemento na sequência de saída, precisamos pegar o primeiro elemento na sequência de entrada.

  • Depois disso, para atualizar o estado oculto e prever o segundo elemento na sequência de saída, precisamos assumir o estado oculto inicial.

  • Por fim, para prever o elemento final na sequência de saída, precisamos obter o estado oculto atualizado e o elemento final na sequência de entrada.

Trabalho de RNN

Para entender o funcionamento das redes neurais recorrentes (RNNs), precisamos primeiro entender como as camadas recorrentes na rede funcionam. Portanto, primeiro vamos discutir como podemos prever a saída com uma camada recorrente padrão.

Previsão de saída com camada RNN padrão

Como já discutimos anteriormente, uma camada básica em RNN é bastante diferente de uma camada regular em uma rede neural. Na seção anterior, também demonstramos no diagrama a arquitetura básica do RNN. A fim de atualizar o estado oculto para a sequência de introdução pela primeira vez, podemos usar a seguinte fórmula -

Na equação acima, calculamos o novo estado oculto calculando o produto escalar entre o estado oculto inicial e um conjunto de pesos.

Agora, para a próxima etapa, o estado oculto para a etapa de tempo atual é usado como o estado oculto inicial para a próxima etapa de tempo na sequência. É por isso que, para atualizar o estado oculto pela segunda etapa, podemos repetir os cálculos realizados na etapa inicial da seguinte forma -

Em seguida, podemos repetir o processo de atualização do estado oculto para a terceira e última etapa na sequência, conforme abaixo -

E quando tivermos processado todas as etapas acima na sequência, podemos calcular a saída da seguinte forma -

Para a fórmula acima, usamos um terceiro conjunto de pesos e o estado oculto da etapa de tempo final.

Unidades Recorrentes Avançadas

O principal problema com a camada recorrente básica é o problema do gradiente de desaparecimento e, devido a isso, não é muito bom para aprender correlações de longo prazo. Em palavras simples, a camada recorrente básica não lida muito bem com sequências longas. Essa é a razão pela qual alguns outros tipos de camadas recorrentes que são muito mais adequados para trabalhar com sequências mais longas são os seguintes -

Memória de longo-curto prazo (LSTM)

As redes de memória de longo-curto prazo (LSTMs) foram introduzidas por Hochreiter & Schmidhuber. Resolveu o problema de obter uma camada básica recorrente para lembrar coisas por um longo tempo. A arquitetura do LSTM é fornecida acima no diagrama. Como podemos ver, ele possui neurônios de entrada, células de memória e neurônios de saída. A fim de combater o problema do gradiente de desaparecimento, as redes de memória de longo-curto prazo usam uma célula de memória explícita (armazena os valores anteriores) e as seguintes portas -

  • Forget gate- Como o nome indica, diz à célula de memória para esquecer os valores anteriores. A célula de memória armazena os valores até que o portão, ou seja, 'esqueça o portão', diga para esquecê-los.

  • Input gate- Como o nome indica, adiciona coisas novas à célula.

  • Output gate- Como o nome indica, a porta de saída decide quando passar os vetores da célula para o próximo estado oculto.

Unidades recorrentes bloqueadas (GRUs)

Gradient recurrent units(GRUs) é uma pequena variação da rede LSTMs. Ele tem uma porta a menos e os fios são ligeiramente diferentes dos LSTMs. Sua arquitetura é mostrada no diagrama acima. Possui neurônios de entrada, células de memória bloqueadas e neurônios de saída. A rede de unidades recorrentes bloqueadas tem as duas portas a seguir -

  • Update gate- Isso determina as duas coisas a seguir−

    • Qual quantidade de informação deve ser mantida do último estado?

    • Que quantidade de informações deve ser permitida da camada anterior?

  • Reset gate- A funcionalidade da porta de redefinição é muito parecida com a porta de esquecer da rede LSTMs. A única diferença é que ele está localizado de forma um pouco diferente.

Em contraste com a rede de memória de longo prazo, as redes de Gated Recurrent Unit são ligeiramente mais rápidas e fáceis de operar.

Criando estrutura RNN

Antes de começarmos, fazendo previsões sobre a saída de qualquer uma de nossas fontes de dados, precisamos primeiro construir RNN e construir RNN é exatamente o mesmo que tínhamos construído rede neural regular na seção anterior. A seguir está o código para construir um -

from cntk.losses import squared_error
from cntk.io import CTFDeserializer, MinibatchSource, INFINITELY_REPEAT, StreamDefs, StreamDef
from cntk.learners import adam
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
BATCH_SIZE = 14 * 10
EPOCH_SIZE = 12434
EPOCHS = 10

Estaqueamento de camadas múltiplas

Também podemos empilhar várias camadas recorrentes no CNTK. Por exemplo, podemos usar a seguinte combinação de camadas−

from cntk import sequence, default_options, input_variable
from cntk.layers import Recurrence, LSTM, Dropout, Dense, Sequential, Fold
features = sequence.input_variable(1)
with default_options(initial_state = 0.1):
   model = Sequential([
      Fold(LSTM(15)),
      Dense(1)
   ])(features)
target = input_variable(1, dynamic_axes=model.dynamic_axes)

Como podemos ver no código acima, temos as duas maneiras a seguir em que podemos modelar RNN em CNTK -

  • Primeiro, se quisermos apenas a saída final de uma camada recorrente, podemos usar o Fold camada em combinação com uma camada recorrente, como GRU, LSTM ou mesmo RNNStep.

  • Em segundo lugar, como uma forma alternativa, também podemos usar o Recurrence quadra.

Treinamento RNN com dados de série temporal

Depois de construir o modelo, vamos ver como podemos treinar RNN em CNTK -

from cntk import Function
@Function
def criterion_factory(z, t):
   loss = squared_error(z, t)
   metric = squared_error(z, t)
   return loss, metric
loss = criterion_factory(model, target)
learner = adam(model.parameters, lr=0.005, momentum=0.9)

Agora, para carregar os dados no processo de treinamento, devemos desserializar as sequências de um conjunto de arquivos CTF. O código a seguir tem ocreate_datasource função, que é uma função de utilidade útil para criar a fonte de dados de treinamento e teste.

target_stream = StreamDef(field='target', shape=1, is_sparse=False)
features_stream = StreamDef(field='features', shape=1, is_sparse=False)
deserializer = CTFDeserializer(filename, StreamDefs(features=features_stream, target=target_stream))
   datasource = MinibatchSource(deserializer, randomize=True, max_sweeps=sweeps)
return datasource
train_datasource = create_datasource('Training data filename.ctf')#we need to provide the location of training file we created from our dataset.
test_datasource = create_datasource('Test filename.ctf', sweeps=1) #we need to provide the location of testing file we created from our dataset.

Agora, como configuramos as fontes de dados, o modelo e a função de perda, podemos iniciar o processo de treinamento. É bastante semelhante ao que fizemos nas seções anteriores com redes neurais básicas.

progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
   features: train_datasource.streams.features,
   target: train_datasource.streams.target
}
history = loss.train(
   train_datasource,
   epoch_size=EPOCH_SIZE,
   parameter_learners=[learner],
   model_inputs_to_streams=input_map,
   callbacks=[progress_writer, test_config],
   minibatch_size=BATCH_SIZE,
   max_epochs=EPOCHS
)

Obteremos uma saída semelhante à seguinte -

Output−

average  since  average  since  examples
loss      last  metric  last
------------------------------------------------------
Learning rate per minibatch: 0.005
0.4      0.4    0.4      0.4      19
0.4      0.4    0.4      0.4      59
0.452    0.495  0.452    0.495   129
[…]

Validando o modelo

Na verdade, redefinir com um RNN é bastante semelhante a fazer previsões com qualquer outro modelo CNK. A única diferença é que precisamos fornecer sequências em vez de amostras únicas.

Agora, como nosso RNN finalmente concluiu o treinamento, podemos validar o modelo testando-o usando algumas sequências de amostras como segue -

import pickle
with open('test_samples.pkl', 'rb') as test_file:
test_samples = pickle.load(test_file)
model(test_samples) * NORMALIZE

Output−

array([[ 8081.7905],
[16597.693 ],
[13335.17 ],
...,
[11275.804 ],
[15621.697 ],
[16875.555 ]], dtype=float32)