Juin 2018

VOLUME 33, NUMÉRO 6

Cet article a fait l'objet d'une traduction automatique.

Série de tests - NEURONALE régression à l’aide de CNTK

Par James McCaffrey | Juin 2018

Téléchargement du code disponible msdn.com/magazine/0518magcode.

L’objectif d’un problème de régression est pour élaborer une prédiction où la valeur à prédire est une valeur numérique unique. Par exemple, vous pouvez

vous souhaitez prédire la hauteur d’une personne en fonction de leur poids, âge et sexe. Il existe plusieurs techniques qui peuvent être utilisés pour résoudre un problème de régression. Dans cet article vous explique comment utiliser la bibliothèque CNTK pour créer un modèle de régression de réseau neuronal.

Une bonne solution pour voir où cet article est menée consiste à examiner le programme de démonstration dans Figure 1. Le programme de démonstration crée un modèle de régression pour le test d’évaluation du jeu de données Yacht PROPRIETES HYDRODYNAMIQUES bien connu. L’objectif est de prévoir une mesure de résistance aux coque yacht, basée sur les variables de prédiction six : centre de poussée des convexe, coefficient PRISMATIQUE, ratio de déplacement de la longueur, tirage FAISCEAUX ratio, taux de croisement longueur et le nombre de Froude.

Figure 1 régression à l’aide d’un réseau neuronal CNTK

Le programme de démonstration crée un réseau neuronal avec deux couches masquées, chacun d’eux a cinq nœuds de traitement. Après l’apprentissage, le modèle est utilisé pour faire des prédictions pour deux éléments de données. Le premier élément a valeurs PRÉDICTEUR (0,52, 0,79, 0,55, 0.41, 0,65, 0.00). La résistance convexe prédite est 0.0078 et la résistance réelle est 0,0030. Le deuxième élément possède des valeurs de PRÉDICTEUR (1,00, 1,00, 0,55, 0.56, 0.46, 1,00). La résistance convexe prédite est 0.8125 et la résistance réelle est 0.8250. Le modèle semble être tout à fait exactes.

Cet article suppose que vous avez intermédiaires ou meilleures compétences de programmation mais que vous ne suppose pas que vous connaissez bien CNTK ou de réseaux neuronaux. La démonstration est codée à l’aide de Python, la langue par défaut pour l’apprentissage, mais même si vous ne connaissez pas Python, vous devez être en mesure de suivre son déroulement sans trop de difficultés. Le code du programme de démonstration est présenté dans son intégralité dans cet article. Le fichier de données de coque yacht utilisé par le programme de démonstration, consultez bit.ly/2Ibsm5Det est également disponible dans le téléchargement qui accompagne cet article.

Présentation des données

Lorsque vous créez un modèle d’apprentissage, la préparation des données est presque toujours la partie la plus longue du projet. Le jeu de données brut dispose de 308 éléments et ressemble à :

-2.3 0.568 4.78 3.99 3.17 0.125 0.11
-2.3 0.568 4.78 3.99 3.17 0.150 0.27
...
-5.0 0.530 4.78 3.75 3.15 0.125 0.09
...
-2.3 0.600 4.34 4.23 2.73 0.450 46.66

Le fichier est délimitées par un espace. Les six premières valeurs sont les valeurs de prévision (souvent appelés de fonctionnalités dans la terminologie de machine learning). La dernière valeur de chaque ligne est la « résistance residuary par unité de poids de déplacement ».

Étant donné que plusieurs variables explicatives, il n’est pas possible d’afficher l’ensemble complet de données dans un graphique. Mais vous pouvez obtenir une idée approximative de la structure des données en examinant le graphique dans Figure 2. Le graphique indique que les valeurs de PRÉDICTEUR coefficient PRISMATIQUE et la résistance convexe. Vous pouvez voir que les valeurs de coefficient PRISMATIQUE par eux-mêmes, ne vous fournissent pas suffisamment d’informations pour élaborer une prédiction précise de la résistance de coque.

Figure 2 Yacht partielle convexe données

Lorsque vous travaillez avec des réseaux neuronaux, il est généralement nécessaire de normaliser les données pour créer un modèle de prédiction correcte. J’ai utilisé la normalisation min-max sur les six valeurs PRÉDICTEUR et sur les valeurs de résistance convexe. J’ai supprimé les données brutes dans une feuille de calcul Excel et, pour chaque colonne, j’ai calculée les valeurs max et min. Ensuite, pour chaque colonne, j’ai remplacé chaque valeur v avec (v - min) / (max - min). Par exemple, la valeur minimale de coefficient PRISMATIQUE est 0,53 et la valeur maximale est 0,60. La première valeur dans la colonne est 0.568 et il est normalisée pour (0.568 - 0,53) / (0,60 - 0,53) = 0.038 / 0.07 = 0.5429.

Après la normalisation, inséré balises | PRÉDICTEURS et | résistance dans la feuille de calcul Excel pour les données peuvent être lues facilement par un objet lecteur de données CNTK. Ensuite, j’ai exporté les données sous forme de fichier délimité par des tabulations. Les données résultantes ressemblent à :

|predictors  0.540000  0.542857 . . |resistance  0.001602
|predictors  0.540000  0.542857 . . |resistance  0.004166
...

Alternatives à la normalisation min-max incluent la normalisation z-score et normalisation de grandeur de la commande.

Le programme de démonstration

Le programme de démonstration complète, avec quelques modifications mineures pour économiser l’espace, est présenté dans Figure 3. Vérification de toutes les erreurs normalement a été supprimé. Puis-je mettre en retrait avec deux espaces à la place les quatre habituelles, comme une question de préférences personnelles et pour économiser l’espace. Notez que le ' \' caractère est utilisé par les Python de continuation de ligne.

Programme de démonstration de régression figure 3

# hydro_reg.py
# CNTK 2.4 with Anaconda 4.1.1 (Python 3.5, NumPy 1.11.1)
# Predict yacht hull resistance based on six predictors

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='resistance',
    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("\nBegin yacht hull regression \n")
  print("Using CNTK version = " + \
    str(C.__version__) + "\n")
  input_dim = 6  # center of buoyancy, etc.
  hidden_dim = 5
  output_dim = 1  # residuary resistance
  train_file = ".\\Data\\hydro_data_cntk.txt"
  # data resembles:
  # |predictors 0.540  0.542 . . |resistance  0.001
  # |predictors 0.540  0.542 . . |resistance  0.004
  # 1. create neural network model
  X = C.ops.input_variable(input_dim, np.float32)
  Y = C.ops.input_variable(output_dim)
  print("Creating a 6-(5-5)-1 tanh regression NN for \
yacht hull dataset ")
  with C.layers.default_options():
    hLayer1 = C.layers.Dense(hidden_dim,
      activation=C.ops.tanh, name='hidLayer1')(X)
    hLayer2 = C.layers.Dense(hidden_dim,
      activation=C.ops.tanh, name='hidLayer2')(hLayer1)  
    oLayer = C.layers.Dense(output_dim,
      activation=None, name='outLayer')(hLayer2)
  model = C.ops.alias(oLayer)  # alias
  # 2. create learner and trainer
  print("Creating a squared error batch=11 Adam \
fixed LR=0.005 Trainer \n")
  tr_loss = C.squared_error(model, Y)
  max_iter = 50000
  batch_size = 11
  learn_rate = 0.005
  learner = C.adam(model.parameters, learn_rate, 0.99)
  trainer = C.Trainer(model, (tr_loss), [learner])
  # 3. create reader for train data
  rdr = create_reader(train_file, input_dim, output_dim,
    rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
  hydro_input_map = {
    X : rdr.streams.x_src,
    Y : rdr.streams.y_src
  }
  # 4. train
  print("Starting training \n")
  for i in range(0, max_iter):
    curr_batch = rdr.next_minibatch(batch_size,
      input_map=hydro_input_map)
    trainer.train_minibatch(curr_batch)
    if i % int(max_iter/10) == 0:
      mcee = trainer.previous_minibatch_loss_average
      print("batch %6d: mean squared error = %8.4f" % \
        (i, mcee))
  print("\nTraining complete")
  # (could save model to disk here)
  # 5. use trained model to make some predictions
  np.set_printoptions(precision=2, suppress=True)
  inpts = np.array(
    [[0.520000, 0.785714, 0.550000, 0.405512, \
      0.648352, 0.000000],
     [1.000000, 1.000000, 0.550000, 0.562992, \
      0.461538, 1.000000]],
    dtype=np.float32)
  actuals = np.array([0.003044, 0.825028],
    dtype=np.float32)
  for i in range(len(inpts)):
    print("\nInput: ", inpts[i])
    pred = model.eval(inpts[i])
    print("predicted resistance: %0.4f" % pred[0][0])
    print("actual resistance:    %0.4f" % actuals[i])
  print("\nEnd yacht hull regression ")

# ========================================================

if __name__ == "__main__":
  main()

Installation CNTK peut être un peu difficile. Tout d’abord, vous installez la distribution Anaconda de Python, qui contient l’interpréteur Python nécessaire, les packages requis tels que NumPy et SciPy, ainsi que des utilitaires tels que pip. J’ai utilisé Anaconda3 4.1.1 64 bits, ce qui a les Python 3.5. Après avoir installé Anaconda, vous installez CNTK en tant que package Python, pas un système autonome, à l’aide de l’utilitaire pip. À partir d’un shell ordinaire, la commande que j’ai utilisé a été :

>pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.4-cp35-cp35m-win_amd64.whl

La démonstration hydro_reg.py a une fonction d’assistance, create_reader. Vous pouvez envisager create_reader comme réutilisable pour un problème de régression CNTK. La seule chose que vous devrez modifier dans la plupart des scénarios est les noms de balise dans le fichier de données.

Toute logique de contrôle est dans une seule fonction principale. Le code commence :

def main():
  print("Begin yacht hull regression \n")
  print("Using CNTK version = " + \
    str(C.__version__) + "\n")
  input_dim = 6  # center of buoyancy, etc.
  hidden_dim = 5
  output_dim = 1  # residuary resistance
  train_file = ".\\Data\\hydro_data_cntk.txt"
...

Étant donné que CNTK est jeune et en cours de développement continu, il est judicieux d’afficher la version en cours d’utilisé (2.4 dans ce cas). Le nombre de nœuds d’entrée est déterminé par la structure du jeu de données. Pour un problème de régression, le nombre de nœuds de sortie est toujours défini sur 1. Le nombre de couches masquées et le nombre de nœuds de traitement de chaque couche masquée sont des paramètres libres, ils doivent être déterminées par la version d’évaluation et d’erreurs.

Le programme de démonstration utilise tous les 308 éléments pour l’apprentissage. Une autre approche consiste à fractionner un jeu d’apprentissage (généralement 80 pour cent des données) et un jeu de test (les 20 % restants) dans le jeu de données. Après une formation, vous pouvez calculer la métrique de perte et la précision du modèle sur le jeu de données de test pour vérifier que les mesures sont semblables à celles sur les données d’apprentissage.

Création du modèle de réseau neuronal

La démonstration définit les objets CNTK pour conserver les PRÉDICTEURS et les valeurs de résistance convexe true :

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim)

CNTK utilise des valeurs 32 bits par défaut, car la précision 64 bits est rarement nécessaire. Le nom de la fonction input_variable peut être prêter à confusion si vous débutez avec CNTK. Ici, la « input_ » fait référence au fait que les objets renvoyés contiennent des valeurs qui proviennent de données d’entrée (qui correspondent à l’entrée et de sortie du réseau neuronal).

Le réseau neuronal est créé avec ces instructions :

print("Creating a 6-(5-5)-1 NN")
with C.layers.default_options():
  hLayer1 = C.layers.Dense(hidden_dim,
    activation=C.ops.tanh, name='hidLayer1')(X)
  hLayer2 = C.layers.Dense(hidden_dim,
    activation=C.ops.tanh, name='hidLayer2')(hLayer1)  
  oLayer = C.layers.Dense(output_dim,
    activation=None, name='outLayer')(hLayer2)
model = C.ops.alias(oLayer)  # alias

Il existe quelques passe ici. Python « avec « instruction peut servir à passer d’un jeu commun de valeurs de paramètre à plusieurs fonctions. Dans ce cas, les valeurs de poids et des écarts de réseau neuronal sont initialisés à l’aide des valeurs par défaut CNTK. Les réseaux neuronaux sont très sensibles aux valeurs de poids et des écarts initiales, qui fournit les valeurs par défaut est une des premières choses à essayer en cas d’échec de votre réseau neuronal pour en savoir plus, une situation courante constaté.

Le réseau neuronal a deux couches masquées. L’objet X en tant que fait Office de l’entrée de la première couche masquée ; la première couche masquée joue le rôle d’entrée à la deuxième couche masquée ; et la seconde masqué couche agit en tant qu’entrée à la couche de sortie.

Les deux couches masquées utilisent tanh (tangente hyperbolique) l’activation. Les deux méthodes principales sont l’activation de la logistique sigmoïde et rectifié linéaire unités (ReLU). La couche de sortie utilise le « None » l’activation, ce qui signifie que les valeurs des nœuds de sortie ne sont pas modifiés. Il s’agit du modèle de conception à utiliser pour un problème de régression. À l’aide d’aucune activation n’est parfois appelé à l’aide de la fonction d’activation identifier, car la fonction mathématique identity est f (x) = x, ce qui n’a aucun effet.

Le programme de démonstration crée un alias nommé « modèle » de la couche de sortie. Cette technique est facultative et est un peu subtile. L’idée est qu’un réseau neuronal est essentiellement une fonction mathématique complexe. Les nœuds de sortie représentent sur le plan conceptuel à la fois une couche du réseau et le modèle de réseau/dans sa globalité.

Apprentissage du modèle

Le cœur de la fonctionnalité CNTK est la possibilité d’effectuer l’apprentissage d’un modèle de réseau neuronal. Formation est préparée avec ces instructions :

tr_loss = C.squared_error(model, Y)
max_iter = 50000
batch_size = 11
learn_rate = 0.005
learner = C.adam(model.parameters, learn_rate, 0.99)
trainer = C.Trainer(model, (tr_loss), [learner])

Une fonction de perte (erreur) est requise pour que l’objet de formation sache comment ajuster les poids et des écarts afin de réduire l’erreur. CNTK 2.4 a neuf fonctions perte, mais le simple squared_error convient presque toujours un problème de régression. Le nombre d’itérations, correspond au nombre d’opérations de mise à jour et doit être déterminé par la version d’évaluation et d’erreurs.

L’objet formateur nécessite un objet de l’apprenant. Vous pouvez considérer un apprenant comme un algorithme. CNTK prend en charge huit algorithmes d’apprentissage automatique. Pour les problèmes de régression, j’obtiens généralement de bons résultats à l’aide de gradient stochastique base, soit le plus sophistiqué Adam (« estimation momentum adaptive »).

La taille de lot est utilisée par CNTK pour déterminer la fréquence à laquelle effectuer des mises à jour de décalage et la pondération. La démonstration définit la taille du lot à 11. Par conséquent, les 308 éléments seront regroupés en 308 / 11 = 28 sélectionnées au hasard des lots. Chaque lot est analysé, et ensuite les mises à jour sont effectuées. Le taux d’apprentissage contrôle la grandeur des ajustements poids et biais. Pour déterminer les valeurs appropriées pour la taille de lot, le nombre maximal d’itérations et le taux d’apprentissage sont souvent plus grands défis lors de la création d’un modèle de prévision de réseau neuronal.

La fonction de create_reader des appels définis par le programme de démonstration, créer, un objet lecteur. Et un input_map est créé, qui indique le lecteur où les valeurs de fonctionnalité sont et où la valeur à prédire d’est :

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

Le paramètre rnd_order garantit que les articles sont traités différemment à chaque passage, ce qui est important empêcher la formation de bloquer les données. L’argument INFINITELY_REPEAT permet de formation sur plusieurs passages sur le jeu de données 308-item.

Après la préparation de l’apprentissage du modèle comme suit :

for i in range(0, max_iter):
  curr_batch = rdr.next_minibatch(batch_size,
    input_map=hydro_input_map)
  trainer.train_minibatch(curr_batch)
  if i % int(max_iter/10) == 0:
    mcee = trainer.previous_minibatch_loss_average
    print("batch %6d: mean squared error = %8.4f" % \
      (i, mcee))

La fonction next_minibatch extrait des éléments de 11 à partir des données. La fonction d’apprentissage utilise l’algorithme de Adam pour mettre à jour le poids et des écarts en fonction de l’erreur au carré entre convexe calculée résistance aux valeurs et résistance réel. L’erreur quadratique sur le lot 11-élément actuel s’affiche chaque 50 000 / lots de 10 = 5 000 pour que vous puissiez contrôler visuellement progrès de formation : Vous souhaitez afficher les valeurs de perte/erreur généralement de réduire.

L’utilisation du modèle

Une fois que le modèle a été formé, le programme de démonstration effectue des prédictions. Tout d’abord, les valeurs de PRÉDICTEUR de deux éléments arbitraires dans le jeu de données normalisé sélectionné (éléments 99 et 238) et placé dans une matrice de style de tableau de tableaux :

inpts = np.array(
  [[0.520000, 0.785714, 0.550000, 0.405512,
    0.648352, 0.000000],
   [1.000000, 1.000000, 0.550000, 0.562992,
    0.461538, 1.000000]],
  dtype=np.float32)

Ensuite, les valeurs de résistance normalisé convexe réelles correspondantes sont placés dans un tableau :

actuals = np.array([0.003044, 0.825028], dtype=np.float32)

Ensuite, les valeurs de prédiction sont utilisées pour calculer les valeurs prédites à l’aide de la fonction model.eval, et les valeurs prédites et réelles sont affichées :

for i in range(len(inpts)):
  print("\nInput: ", inpts[i])
  pred = model.eval(inpts[i])
  print("predicted resistance: %0.4f" % pred[0][0])
  print("actual resistance:    %0.4f" % actuals[i])
print("End yacht hull regression ")

Notez que la valeur de résistance convexe prédite est retournée comme une matrice de tableau de tableaux avec une seule valeur. Par conséquent, la valeur elle-même est [0] [0] (ligne 0, la colonne 0). Vous traitez des formes de CNTK vecteurs et les matrices est un défi important de syntaxe. Lorsque vous travaillez avec CNTK consacré beaucoup de temps à l’impression des objets et l’affichage de leur forme, le long des lignes de print(something.shape).

Pour résumer

Lorsque vous créez un modèle de régression de réseau neuronal, il n’existe aucune mesure de précision prédéfinis. Si vous souhaitez calculer la précision de prédiction que vous devez définir la signification d’une valeur prédite pour être suffisamment proches pour la valeur réelle correspondante pour être considéré comme correct. En règle générale, vous spécifiez une pourcentage/proportion, par exemple 0,10 et évaluer une valeur prédite comme correcte si elle se trouve dans ce pourcentage de la valeur réelle.

Étant donné que le modèle de démonstration fonctionne avec données normalisées, si vous utilisez le modèle pour élaborer une prédiction nouvelles valeurs de PRÉDICTEUR sans précédent, vous devez normaliser ces derniers en utilisant les mêmes valeurs min-max qui étaient utilisées sur les données d’apprentissage. De même, une valeur de résistance convexe prédite, pv, est normalisée, donc vous devez dénormaliser en informatique va * (max - min) + min.

Le terme « régression » peut avoir plusieurs significations. Dans cet article, le terme fait référence à un problème du scénario où l’objectif est de prédire une valeur numérique unique (résistance convexe). La technique de régression linéaire statistiques classique est beaucoup plus simple que la régression de réseau neuronal, mais généralement beaucoup moins précis. La technique de régression logistique apprentissage prédit une valeur numérique comprise entre 0,0 et 1,0, ce qui est interprétée comme une probabilité et ensuite utilisé pour prédire une valeur catégorielle tels que « male » (p < 0,5) ou « femme » (p > 0,5).


Récupération d’urgence. James McCaffrey fonctionne pour Microsoft Research à Redmond, Washington Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et Bing. Dr. McCaffrey peut être atteint à jamccaff@microsoft.com.