CNTK - En mémoire et grands ensembles de données

Dans ce chapitre, nous allons apprendre comment travailler avec les ensembles de données en mémoire et volumineux dans CNTK.

Entraînement avec de petits ensembles de données en mémoire

Lorsque nous parlons d'alimenter des données dans le formateur CNTK, il peut y avoir de nombreuses façons, mais cela dépendra de la taille de l'ensemble de données et du format des données. Les ensembles de données peuvent être de petits ensembles de données en mémoire ou de grands ensembles de données.

Dans cette section, nous allons travailler avec des ensembles de données en mémoire. Pour cela, nous utiliserons les deux frameworks suivants -

  • Numpy
  • Pandas

Utilisation de tableaux Numpy

Ici, nous travaillerons avec un ensemble de données généré aléatoirement basé sur numpy dans CNTK. Dans cet exemple, nous allons simuler des données pour un problème de classification binaire. Supposons que nous ayons un ensemble d'observations avec 4 fonctionnalités et que nous souhaitons prédire deux étiquettes possibles avec notre modèle d'apprentissage en profondeur.

Exemple d'implémentation

Pour cela, nous devons d'abord générer un ensemble d'étiquettes contenant une représentation vectorielle ponctuelle des étiquettes, que nous voulons prédire. Cela peut être fait à l'aide des étapes suivantes -

Step 1 - Importez le numpy paquet comme suit -

import numpy as np
num_samples = 20000

Step 2 - Ensuite, générez un mappage d'étiquettes en utilisant np.eye fonction comme suit -

label_mapping = np.eye(2)

Step 3 - Maintenant en utilisant np.random.choice fonction, collectez les 20000 échantillons aléatoires comme suit -

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

Step 4 - Enfin, en utilisant la fonction np.random.random, générez un tableau de valeurs flottantes aléatoires comme suit -

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

Une fois que nous générons un tableau de valeurs à virgule flottante aléatoires, nous devons les convertir en nombres à virgule flottante 32 bits afin qu'il puisse être mis en correspondance avec le format attendu par CNTK. Suivons les étapes ci-dessous pour ce faire -

Step 5 - Importez les fonctions de couche dense et séquentielle du module cntk.layers comme suit -

from cntk.layers import Dense, Sequential

Step 6- Maintenant, nous devons importer la fonction d'activation pour les couches du réseau. Importons lesigmoid comme fonction d'activation -

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

Step 7- Maintenant, nous devons importer la fonction de perte pour former le réseau. Importonsbinary_cross_entropy comme fonction de perte -

from cntk.losses import binary_cross_entropy

Step 8- Ensuite, nous devons définir les options par défaut pour le réseau. Ici, nous fournirons lesigmoidfonction d'activation comme paramètre par défaut. Créez également le modèle à l'aide de la fonction de calque séquentiel comme suit -

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

Step 9 - Ensuite, initialisez un input_variable avec 4 fonctions d'entrée servant d'entrée pour le réseau.

features = input_variable(4)

Step 10 - Maintenant, pour le compléter, nous devons connecter la variable features au NN.

z = model(features)

Donc, maintenant nous avons un NN, à l'aide des étapes suivantes, entraînons-le en utilisant un jeu de données en mémoire -

Step 11 - Pour former ce NN, nous devons d'abord importer l'apprenant de cntk.learnersmodule. Nous importeronssgd l'apprenant comme suit -

from cntk.learners import sgd

Step 12 - Parallèlement à cela, importez le ProgressPrinter de cntk.logging module également.

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

Step 13 - Ensuite, définissez une nouvelle variable d'entrée pour les étiquettes comme suit -

labels = input_variable(2)

Step 14 - Afin de former le modèle NN, nous devons ensuite définir une perte en utilisant le binary_cross_entropyfonction. Fournissez également le modèle z et la variable labels.

loss = binary_cross_entropy(z, labels)

Step 15 - Ensuite, initialisez le sgd l'apprenant comme suit -

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

Step 16- Enfin, appelez la méthode train sur la fonction perte. Aussi, fournissez-lui les données d'entrée, lesgd l'apprenant et le progress_printer.−

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

Exemple d'implémentation complet

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])

Production

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

Utilisation de Pandas DataFrames

Les tableaux Numpy sont très limités dans ce qu'ils peuvent contenir et constituent l'un des moyens les plus élémentaires de stocker des données. Par exemple, un seul tableau à n dimensions peut contenir des données d'un seul type de données. Mais d'un autre côté, pour de nombreux cas réels, nous avons besoin d'une bibliothèque capable de gérer plus d'un type de données dans un seul ensemble de données.

L'une des bibliothèques Python appelée Pandas facilite le travail avec ce type d'ensembles de données. Il introduit le concept de DataFrame (DF) et nous permet de charger des ensembles de données à partir d'un disque stocké dans divers formats sous forme de DF. Par exemple, nous pouvons lire les DF stockés au format CSV, JSON, Excel, etc.

Vous pouvez apprendre la bibliothèque Python Pandas plus en détail sur

Exemple d'implémentation

Dans cet exemple, nous allons utiliser l'exemple de la classification de trois espèces possibles de fleurs d'iris en fonction de quatre propriétés. Nous avons également créé ce modèle d'apprentissage en profondeur dans les sections précédentes. Le modèle est le suivant -

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)

Le modèle ci-dessus contient une couche cachée et une couche de sortie avec trois neurones pour correspondre au nombre de classes que nous pouvons prédire.

Ensuite, nous utiliserons le train méthode et lossfonction pour former le réseau. Pour cela, nous devons d'abord charger et prétraiter l'ensemble de données iris, afin qu'il corresponde à la disposition et au format de données attendus pour le NN. Cela peut être fait à l'aide des étapes suivantes -

Step 1 - Importez le numpy et Pandas paquet comme suit -

import numpy as np
import pandas as pd

Step 2 - Ensuite, utilisez le read_csv fonction pour charger le jeu de données en mémoire -

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

Step 3 - Nous devons maintenant créer un dictionnaire qui mappera les étiquettes de l'ensemble de données avec leur représentation numérique correspondante.

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

Step 4 - Maintenant, en utilisant iloc indexeur sur le DataFrame, sélectionnez les quatre premières colonnes comme suit -

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

Step 5- Ensuite, nous devons sélectionner les colonnes d'espèces comme étiquettes pour l'ensemble de données. Cela peut être fait comme suit -

y = df_source[‘species’].values

Step 6 - Maintenant, nous devons mapper les étiquettes dans l'ensemble de données, ce qui peut être fait en utilisant label_mapping. Utiliser aussione_hot encodage pour les convertir en tableaux d'encodage one-hot.

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

Step 7 - Ensuite, pour utiliser les fonctionnalités et les étiquettes mappées avec CNTK, nous devons les convertir tous les deux en flottants -

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

Comme nous le savons, les étiquettes sont stockées dans l'ensemble de données sous forme de chaînes et CNTK ne peut pas fonctionner avec ces chaînes. C'est la raison pour laquelle il a besoin de vecteurs encodés à chaud représentant les étiquettes. Pour cela, on peut définir une fonction direone_hot comme suit -

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

Maintenant, nous avons le tableau numpy dans le format correct, à l'aide des étapes suivantes, nous pouvons les utiliser pour entraîner notre modèle -

Step 8- Tout d'abord, nous devons importer la fonction de perte pour former le réseau. Importonsbinary_cross_entropy_with_softmax comme fonction de perte -

from cntk.losses import binary_cross_entropy_with_softmax

Step 9 - Pour former ce NN, nous devons également importer l'apprenant de cntk.learnersmodule. Nous importeronssgd l'apprenant comme suit -

from cntk.learners import sgd

Step 10 - Parallèlement à cela, importez le ProgressPrinter de cntk.logging module également.

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

Step 11 - Ensuite, définissez une nouvelle variable d'entrée pour les étiquettes comme suit -

labels = input_variable(3)

Step 12 - Afin de former le modèle NN, nous devons ensuite définir une perte en utilisant le binary_cross_entropy_with_softmaxfonction. Fournissez également le modèle z et la variable labels.

loss = binary_cross_entropy_with_softmax (z, labels)

Step 13 - Ensuite, initialisez le sgd l'apprenant comme suit -

learner = sgd(z.parameters, 0.1)

Step 14- Enfin, appelez la méthode train sur la fonction perte. Aussi, fournissez-lui les données d'entrée, lesgd l'apprenant et le progress_printer.

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

Exemple d'implémentation complet

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)

Production

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
[………]

Formation avec de grands ensembles de données

Dans la section précédente, nous avons travaillé avec de petits ensembles de données en mémoire à l'aide de Numpy et de pandas, mais tous les ensembles de données ne sont pas aussi petits. En particulier, les ensembles de données contenant des images, des vidéos et des échantillons sonores sont volumineux.MinibatchSourceest un composant capable de charger des données par blocs, fourni par CNTK pour travailler avec des ensembles de données aussi volumineux. Certaines des caractéristiques deMinibatchSource les composants sont les suivants -

  • MinibatchSource peut empêcher NN de se surajouter en randomisant automatiquement les échantillons lus à partir de la source de données.

  • Il a un pipeline de transformation intégré qui peut être utilisé pour augmenter les données.

  • Il charge les données sur un thread d'arrière-plan distinct du processus d'entraînement.

Dans les sections suivantes, nous allons explorer comment utiliser une source de minibatch avec des données hors mémoire pour travailler avec de grands ensembles de données. Nous allons également explorer, comment nous pouvons l'utiliser pour nourrir pour la formation d'un NN.

Création d'une instance MinibatchSource

Dans la section précédente, nous avons utilisé l'exemple de fleur d'iris et travaillé avec un petit jeu de données en mémoire à l'aide de Pandas DataFrames. Ici, nous remplacerons le code qui utilise les données d'un pandas DF parMinibatchSource. Tout d'abord, nous devons créer une instance deMinibatchSource à l'aide des étapes suivantes -

Exemple d'implémentation

Step 1 - D'abord, de cntk.io module importer les composants pour la minibatchsource comme suit -

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

Step 2 - Maintenant, en utilisant StreamDef classe, créez une définition de flux pour les étiquettes.

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

Step 3 - Ensuite, créez pour lire les caractéristiques déposées à partir du fichier d'entrée, créez une autre instance de StreamDef comme suit.

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

Step 4 - Maintenant, nous devons fournir iris.ctf comme entrée et initialisez le deserializer comme suit -

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

Step 5 - Enfin, nous devons créer une instance de minisourceBatch en utilisant deserializer comme suit -

Minibatch_source = MinibatchSource(deserializer, randomize=True)

Création d'une instance MinibatchSource - Exemple d'implémentation complet

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)

Création d'un fichier MCTF

Comme vous l'avez vu ci-dessus, nous prenons les données du fichier «iris.ctf». Il a le format de fichier appelé CNTK Text Format (CTF). Il est obligatoire de créer un fichier CTF pour obtenir les données duMinibatchSourceinstance que nous avons créée ci-dessus. Voyons comment nous pouvons créer un fichier CTF.

Exemple d'implémentation

Step 1 - Tout d'abord, nous devons importer les paquets pandas et numpy comme suit -

import pandas as pd
import numpy as np

Step 2- Ensuite, nous devons charger notre fichier de données, ie iris.csv en mémoire. Ensuite, stockez-le dans ledf_source variable.

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

Step 3 - Maintenant, en utilisant ilocindexer comme fonctionnalités, prenez le contenu des quatre premières colonnes. Utilisez également les données de la colonne des espèces comme suit -

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

Step 4- Ensuite, nous devons créer un mappage entre le nom de l'étiquette et sa représentation numérique. Cela peut être fait en créantlabel_mapping comme suit -

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

Step 5 - Maintenant, convertissez les étiquettes en un ensemble de vecteurs encodés à chaud comme suit -

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

Maintenant, comme nous l'avons fait auparavant, créez une fonction utilitaire appelée one_hotpour encoder les étiquettes. Cela peut être fait comme suit -

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

Comme nous avons chargé et prétraité les données, il est temps de les stocker sur disque au format de fichier CTF. Nous pouvons le faire à l'aide du code Python suivant -

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))

Création d'un fichier MCTF - Exemple d'implémentation complet

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))

Nourrir les données

Une fois que vous créez MinibatchSource,exemple, nous devons le former. Nous pouvons utiliser la même logique d'entraînement que celle utilisée lorsque nous travaillons avec de petits ensembles de données en mémoire. Ici, nous allons utiliserMinibatchSource instance comme entrée pour la méthode de train sur la fonction de perte comme suit -

Exemple d'implémentation

Step 1 - Pour enregistrer la sortie de la session de formation, importez d'abord ProgressPrinter depuis cntk.logging module comme suit -

from cntk.logging import ProgressPrinter

Step 2 - Ensuite, pour configurer la session de formation, importez le trainer et training_session de cntk.train module comme suit -

from cntk.train import Trainer,

Step 3 - Maintenant, nous devons définir un ensemble de constantes comme minibatch_size, samples_per_epoch et num_epochs comme suit -

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30

Step 4 - Ensuite, pour savoir à CNTK comment lire les données pendant l'entraînement, nous devons définir un mappage entre la variable d'entrée pour le réseau et les flux dans la source du minibatch.

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

Step 5 - Ensuite, pour enregistrer la sortie du processus de formation, initialisez le progress_printer variable avec un nouveau ProgressPrinter exemple comme suit -

progress_writer = ProgressPrinter(0)

Step 6 - Enfin, nous devons invoquer la méthode de train sur la perte comme suit -

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)

Nourrir les données - Exemple d'implémentation complet

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)

Production

-------------------------------------------------------------------
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
[………]