CNTK - Classification des réseaux neuronaux

Dans ce chapitre, nous étudierons comment classer un réseau de neurones en utilisant CNTK.

introduction

La classification peut être définie comme le processus permettant de prédire les étiquettes de sortie catégorielles ou les réponses pour les données d'entrée données. La sortie catégorisée, qui sera basée sur ce que le modèle a appris en phase de formation, peut avoir la forme telle que "Noir" ou "Blanc" ou "spam" ou "pas de spam".

D'un autre côté, mathématiquement, c'est la tâche d'approximer une fonction de mappage, disons f des variables d'entrée dire X aux variables de sortie dire Y.

Un exemple classique de problème de classification peut être la détection de spam dans les e-mails. Il est évident qu'il ne peut y avoir que deux catégories de sortie, "spam" et "pas de spam".

Pour implémenter une telle classification, nous devons d'abord faire la formation du classificateur où les e-mails "spam" et "pas de spam" seraient utilisés comme données de formation. Une fois que le classificateur s'est entraîné avec succès, il peut être utilisé pour détecter un e-mail inconnu.

Ici, nous allons créer un 4-5-3 NN en utilisant un ensemble de données de fleurs d'iris ayant les éléments suivants -

  • Nœuds à 4 entrées (un pour chaque valeur de prédicteur).

  • 5 nœuds de traitement cachés.

  • 3 nœuds de sortie (car il existe trois espèces possibles dans le jeu de données iris).

Chargement de l'ensemble de données

Nous utiliserons un ensemble de données sur les fleurs d'iris, à partir duquel nous voulons classer les espèces de fleurs d'iris en fonction des propriétés physiques de la largeur et de la longueur des sépales, ainsi que de la largeur et de la longueur des pétales. L'ensemble de données décrit les propriétés physiques de différentes variétés de fleurs d'iris -

  • Longueur sépale

  • Largeur sépale

  • Longueur des pétales

  • Largeur des pétales

  • Classe ie iris setosa ou iris versicolor ou iris virginica

Nous avons iris.CSVfichier que nous avons utilisé auparavant dans les chapitres précédents également. Il peut être chargé à l'aide dePandasbibliothèque. Mais, avant de l'utiliser ou de le charger pour notre classificateur, nous devons préparer les fichiers d'entraînement et de test, afin qu'il puisse être utilisé facilement avec CNTK.

Préparation des fichiers de formation et de test

L'ensemble de données Iris est l'un des ensembles de données les plus populaires pour les projets ML. Il contient 150 éléments de données et les données brutes se présentent comme suit -

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

Comme indiqué précédemment, les quatre premières valeurs de chaque ligne décrivent les propriétés physiques des différentes variétés, à savoir la longueur du sépale, la largeur du sépale, la longueur du pétale, la largeur du pétale des fleurs d'iris.

Mais, nous devrions avoir à convertir les données au format, qui peut être facilement utilisé par CNTK et ce format est le fichier .ctf (nous avons également créé un iris.ctf dans la section précédente). Cela ressemblera à ceci -

|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

Dans les données ci-dessus, la balise | attribs marque le début de la valeur de l'entité et les | espèces balise les valeurs de l'étiquette de classe. Nous pouvons également utiliser tout autre nom d'étiquette de notre souhait, même si nous pouvons également ajouter un identifiant d'article. Par exemple, regardez les données suivantes -

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

Il y a au total 150 éléments de données dans l'ensemble de données d'iris et pour cet exemple, nous utiliserons la règle de jeu de données de 80 à 20, c'est-à-dire 80% (120 éléments) éléments de données à des fins de formation et les 20% restants (30 éléments) éléments de données pour les tests objectif.

Construire un modèle de classification

Tout d'abord, nous devons traiter les fichiers de données au format CNTK et pour cela nous allons utiliser la fonction d'assistance nommée create_reader comme suit -

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

Maintenant, nous devons définir les arguments d'architecture pour notre NN et également fournir l'emplacement des fichiers de données. Cela peut être fait à l'aide du code python suivant -

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)

Maintenant, avec l'aide de la ligne de code suivante, notre programme créera le NN non entraîné -

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)

Maintenant, une fois que nous avons créé le modèle dual sans formation, nous devons configurer un objet d'algorithme d'apprentissage et l'utiliser ensuite pour créer un objet de formation Trainer. Nous allons utiliser l'apprenant SGD etcross_entropy_with_softmax fonction de perte -

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

Codez l'algorithme d'apprentissage comme suit -

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

Maintenant, une fois que nous avons terminé avec l'objet Trainer, nous devons créer une fonction de lecture pour lire les données d'entraînement -

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 }

Il est maintenant temps de former notre modèle 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))

Une fois que nous avons terminé l'entraînement, évaluons le modèle à l'aide d'éléments de données de test -

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)

Après avoir évalué la précision de notre modèle NN formé, nous l'utiliserons pour faire une prédiction sur des données invisibles -

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

Modèle de classification complet

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

Production

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]

Enregistrer le modèle entraîné

Cet ensemble de données Iris ne contient que 150 éléments de données, il ne faudrait donc que quelques secondes pour entraîner le modèle de classificateur NN, mais l'entraînement sur un vaste ensemble de données contenant des centaines ou des milliers d'éléments de données peut prendre des heures, voire des jours.

Nous pouvons sauvegarder notre modèle pour ne pas avoir à le conserver à partir de zéro. Avec l'aide du code Python suivant, nous pouvons enregistrer notre NN formé -

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

Voici les arguments de save() fonction utilisée ci-dessus -

  • Le nom de fichier est le premier argument de save()fonction. Il peut également être écrit avec le chemin du fichier.

  • Un autre paramètre est le format paramètre qui a une valeur par défaut C.ModelFormat.CNTKv2.

Chargement du modèle entraîné

Une fois que vous avez enregistré le modèle entraîné, il est très facile de charger ce modèle. Il suffit d'utiliser leload ()fonction. Vérifions cela dans l'exemple suivant -

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

L'avantage du modèle enregistré est que, une fois que vous chargez un modèle enregistré, il peut être utilisé exactement comme si le modèle venait d'être entraîné.