CNTK - In-Memory e grandes conjuntos de dados

Neste capítulo, aprenderemos como trabalhar com os conjuntos de dados in-memory e grandes no CNTK.

Treinamento com pequenos conjuntos de dados de memória

Quando falamos sobre a alimentação de dados no treinador CNTK, pode haver muitas maneiras, mas isso vai depender do tamanho do conjunto de dados e do 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órios como segue -

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

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, isto é, 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 - A seguir, 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
[………]