Partager via


Série de tests

Rétropropagation du réseau neuronal pour programmeurs

James McCaffrey

Télécharger l'exemple de code

James McCaffreyUn réseau neuronal artificiel peut être considéré comme une métafonction qui accepte un nombre fixe d'entrées numériques et produit un nombre fixe de sorties numériques. Dans la plupart des cas, un réseau neuronal comporte une couche de neurones cachés, chacun de ces derniers étant totalement connecté aux neurones d'entrée et à ceux de sortie. Un ensemble de valeurs de poids et une seule valeur dite de biais sont associés à chaque neurone caché et à chaque neurone de sortie. Les poids et les biais déterminent les valeurs de sortie d'un ensemble donné de valeurs d'entrée.

Lorsque les réseaux neuronaux sont utilisés pour modéliser un ensemble de données existantes afin de pouvoir réaliser des prévisions sur de nouvelles données, le défi principal consiste à trouver l'ensemble des valeurs de poids et de biais qui génèrent les sorties correspondant le mieux aux données existantes. La technique la plus courante permettant d'estimer les poids et les biais optimaux d'un réseau neuronal est qualifiée de rétropropagation. Bien qu'un grand nombre d'excellentes références décrivent les mathématiques complexes qui sous-tendent la rétropropagation, il existe très peu de guides destinés aux programmeurs qui expliquent clairement la programmation de l'algorithme de rétropropagation. Cet article explique comment implémenter la rétropropagation. J'utilise le langage C#, mais vous ne devriez avoir aucune difficulté à refactoriser le code présenté ici dans d'autres langages.

Pour mieux comprendre où je veux en venir, observez la capture d'écran de la figure 1, qui illustre le cas d'un programme de démonstration. Ce dernier crée un réseau neuronal connecté à trois neurones d'entrée, une couche cachée de quatre neurones et deux neurones de sortie. Les réseaux neuronaux avec une seule couche cachée ont besoin de deux fonctions d'activation. Dans de nombreux cas de figure, cependant, les deux fonctions d'activation sont identiques et des fonctions sigmoïdes sont généralement utilisées. Dans le cadre de cette démonstration, toutefois, j'utilise des fonctions d'activation différentes afin d'illustrer la relation entre celles-ci et la rétropropagation : la fonction sigmoïde pour les calculs de la couche d'entrée vers la couche cachée et la fonction tanh (tangente hyperbolique) pour les calculs de la couche cachée vers la couche de sortie.

Back-Propagation Algorithm in Action
Figure 1 L'algorithme de rétropropagation en action

Un réseau neuronal 3-4-2 totalement connecté a besoin de 3*4 + 4*2 = 20 valeurs de poids et de 4+2 = 6 valeurs de biais pour un total de 26 poids et biais. Les valeurs de poids et de biais initiales sont plus ou moins arbitraires. Les trois valeurs d'entrée factices sont définies sur 1.0, 2.0 et 3.0. Avec les valeurs initiales de poids, de biais et d'entrée, les valeurs initiales de sortie suivantes sont calculées par le réseau neuronal : {0.7225, -0.8779}. Le programme de démonstration suppose de façon arbitraire que les deux valeurs de sortie correctes sont les suivantes :{-0.8500, 0.7500}. L'objectif de l'algorithme de rétropropagation est de trouver un nouvel ensemble de poids et de biais capable de générer des sorties très proches des valeurs correctes des entrées {1.0, 2.0, 3.0}.

La rétropropagation requiert deux paramètres libres. Le taux d'apprentissage, généralement représenté par la lettre grecque êta dans les documents consacrés à la rétropropagation, contrôle la rapidité avec laquelle l'algorithme converge vers une estimation finale. L'inertie, généralement représentée par la lettre grecque alpha, permet à l'algorithme de rétropropagation d'éviter des situations dans lesquelles l'algorithme oscille et ne converge jamais vers une estimation finale. Dans le programme de démonstration, le taux d'apprentissage est défini sur 0.90 et l'inertie, sur 0.04. Vous trouvez généralement ces valeurs à force de tests et d'erreurs.

La recherche du meilleur ensemble de poids et de biais pour un réseau neuronal est généralement qualifiée d'entraînement du réseau. L'entraînement avec rétropropagation est un processus itératif. Lors de chaque itération, la rétropropagation calcule un nouvel ensemble de valeurs de poids et de biais du réseau neuronal. Ces valeurs génèrent théoriquement des valeurs de sortie qui sont plus proches des valeurs cibles. Après la première itération d'entraînement du programme de démonstration, l'algorithme de rétropropagation a trouvé les nouvelles valeurs de poids et de biais qui ont généré les nouvelles sorties suivantes : {-0.8932, -0.8006}. La nouvelle première valeur de sortie égale à -0.8932 était nettement plus proche de la première valeur de sortie cible, à savoir -0.8500. La deuxième nouvelle valeur de sortie, -0.8006, restait très éloignée de sa valeur cible, 0.7500.

Le processus d'entraînement peut se terminer de différentes façons. Le programme de démonstration effectue une itération de l'entraînement jusqu'à ce que la somme des valeurs absolues entre les valeurs de sortie et les valeurs cibles soit <= 0.01 ou que l'entraînement atteigne 1 000 itérations. Dans la démonstration, après six itérations d'entraînement, la rétropropagation a trouvé pour le réseau neuronal un ensemble de valeurs de poids et de biais qui ont généré les sorties {-0.8423, 0.7481}, très proches des valeurs cibles souhaitées égales à {-0.8500, 0.7500}.

Cet article suppose que vous êtes expert en programmation et que vous avez une compréhension très basique des réseaux neuronaux. Pour consulter des informations de base sur les réseaux neuronaux, lisez l'article rédigé par mes soins et paru au mois de mai 2012, « Plongez dans les réseaux neuronaux », sur msdn.microsoft.com/magazine/hh975375. Le code du programme de démonstration illustré à la figure 1 est légèrement trop long pour être présenté dans cet article, c'est pourquoi je me concentrerai sur l'explication des parties essentielles de l'algorithme. Le code source complet du programme de démonstration est disponible sur archive.msdn.microsoft.com/mag201210TestRun.

Définition d'une classe de réseau neuronal

Le codage d'un réseau neuronal qui utilise la rétropropagation se prête bien à une approche orientée objet. La définition de classe utilisée dans le cadre du programme de démonstration se trouve à la figure 2.

Figure 2 Classe de réseau neuronal

class NeuralNetwork
{
  private int numInput;
  private int numHidden;
  private int numOutput;
  // 15 input, output, weight, bias, and other arrays here
  public NeuralNetwork(int numInput, 
    int numHidden, int numOutput) {...}
  public void UpdateWeights(double[] tValues, 
    double eta, double alpha) {...}
  public void SetWeights(double[] weights) {...}
  public double[] GetWeights() {...}
  public double[] ComputeOutputs(double[] xValues) {...}
  private static double SigmoidFunction(double x)
  {
    if (x < -45.0) return 0.0;
    else if (x > 45.0) return 1.0;
    else return 1.0 / (1.0 + Math.Exp(-x));
  }
  private static double HyperTanFunction(double x)
  {
    if (x < -10.0) return -1.0;
    else if (x > 10.0) return 1.0;
    else return Math.Tanh(x);
  }
}

Les champs Member, ainsi que numInput, numHidden et numOutput sont des caractéristiques qui définissent l'architecture d'un réseau neuronal. Outre un constructeur simple, la classe comporte quatre méthodes accessibles publiquement et deux méthodes d'assistance. La méthode UpdateWeights contient toute la logique de l'algorithme de rétropropagation. La méthode SetWeights accepte un tableau de valeurs de poids et de biais, et elle copie ces dernières de façon séquentielle dans les tableaux membres. La méthode GetWeights effectue l'opération inverse en copiant les poids et les biais dans un seul tableau et en renvoyant celui-ci. La méthode ComputeOutputs détermine les valeurs de sortie du réseau neuronal à l'aide des valeurs actuelles d'entrée, de poids et de biais.

La méthode SigmoidFunction est utilisée comme fonction d'activation de la couche d'entrée vers la couche cachée. Elle accepte une valeur réelle (type Double en C#) et retourne une valeur comprise entre 0.0 et 1.0. La méthode HyperTanFunction accepte également une valeur réelle, mais retourne une valeur comprise entre -1.0 et +1.0. Le langage C# a une fonction de tangente hyperbolique intégrée, Math.Tanh, mais si vous utilisez un langage qui n'a pas de fonction tanh native, vous devrez en coder une entièrement.

Configuration des tableaux

L'une des clés de la programmation d'un algorithme de rétropropagation pour un réseau neuronal est de comprendre totalement les tableaux utilisés pour stocker les valeurs de poids et de biais, stocker différents types de valeurs d'entrée et de sortie, stocker des valeurs provenant d'une itération précédente de l'algorithme et stocker des calculs temporaires. Le grand diagramme de la figure 3 contient toutes les informations que vous devez connaître pour comprendre la méthode de programmation de la rétropropagation. À la vue de la figure 3, vous vous direz probablement : « ce n'est pas la peine de continuer, c'est trop compliqué ». Mais ne baissez pas les bras. La rétropropagation est loin d'être simple, mais une fois ce diagramme intégré, vous serez capable d'implémenter la rétropropagation à l'aide de n'importe quel langage de programmation.

The Back-Propagation Algorithm
Figure 3 L'algorithme de rétropropagation

La figure 3 comporte des entrées et sorties sur les bords, mais elle présente également plusieurs valeurs locales d'entrée et de sortie à l'intérieur du diagramme. Ne sous-estimez pas la difficulté présentée par le codage d'un réseau neuronal, ni la nécessité d'avoir une signification et un nom clairs pour toutes ces entrées et sorties. D'après mon expérience, un diagramme similaire à celui de la figure 3 est absolument nécessaire.

 Parmi les 15 tableaux utilisés dans la définition du réseau neuronal illustrée à la figure 2, cinq concernent les couches des neurones d'entrée vers les neurones cachés et sont :

public class NeuralNetwork
{
  // Declare numInput, numHidden, numOutput
  private double[] inputs;
  private double[][] ihWeights;
  private double[] ihSums;
  private double[] ihBiases;
  private double[] ihOutputs;
...

Le premier tableau, nommé entrées, contient les valeurs d'entrée numériques. En règle générale, ces valeurs proviennent directement d'une source de données normalisée, par exemple un fichier texte. Le constructeur NeuralNetwork instancie les entrées de la façon suivante :

this.inputs = new double[numInput];

Le tableau ihWeights (valeurs de poids de la couche d'entrée vers la couche cachée) est un tableau bidimensionnel virtuel implémenté comme tableau de tableaux. Le premier index correspond au neurone d'entrée et le second, au neurone caché. Le tableau est instancié par le constructeur de la façon suivante :

this.ihWeights = Helpers.MakeMatrix(numInput, numHidden);

Ici, Helpers est une classe utilitaire de méthodes statiques qui permet de simplifier la classe de réseau neuronal :

public static double[][] MakeMatrix(int rows, int cols)
{
  double[][] result = new double[rows][];
  for (int i = 0; i < rows; ++i)
    result[i] = new double[cols];
  return result;
}

Le tableau ihSums est un tableau temporaire utilisé pour contenir un calcul intermédiaire dans la méthode ComputeOutputs. Ce tableau contient des valeurs qui deviendront les entrées locales des neurones cachés. Il est instancié de la façon suivante :

this.ihSums = new double[numHidden];

Le tableau ihBiases contient les valeurs de biais des neurones cachés. Les valeurs de poids du réseau neuronal sont des constantes appliquées en les multipliant par une valeur d'entrée locale. Les valeurs de biais sont ajoutées à une somme intermédiaire de façon à produire une valeur de sortie locale qui devient l'entrée locale pour la couche suivante. Le tableau ihBiases est instancié de la façon suivante :

this.ihBiases = new double[numHidden];

Le tableau ihOutputs contient les valeurs émises depuis les neurones de la couche cachée (qui deviennent les entrées de la couche de sortie).

Les quatre tableaux suivants de la classe NeuralNetwork contiennent des valeurs associées à la couche des neurones cachés vers les neurones de sortie :

private double[][] hoWeights;
private double[] hoSums;
private double[] hoBiases;
private double[] outputs;

Ces quatre tableaux sont instanciés dans le constructeur de la façon suivante :

this.hoWeights = Helpers.MakeMatrix(numHidden, numOutput);
this.hoSums = new double[numOutput];
this.hoBiases = new double[numOutput];
this.outputs = new double[numOutput];

La classe de réseau neuronal comporte six tableaux qui sont directement associés à l'algorithme de rétropropagation. Les deux premiers tableaux contiennent des valeurs nommées gradients des neurones de la couche de sortie et de la couche cachée. Un gradient est une valeur qui décrit indirectement à quel point et dans quel sens (positif ou négatif) les sorties locales sont en rapport avec les sorties cibles. Les valeurs de gradient permettent de calculer les valeurs deltas, qui sont ajoutées aux valeurs actuelles de poids et de biais afin de créer de nouveaux poids et biais plus intéressants. Il existe une valeur de gradient pour chaque neurone de la couche cachée et chaque neurone de la couche de sortie. Les tableaux sont déclarés de la façon suivante :

private double[] oGrads; // Output gradients
private double[] hGrads; // Hidden gradients

Les tableaux sont instanciés dans le constructeur de la façon suivante :

this.oGrads = new double[numOutput];
this.hGrads = new double[numHidden];

Les quatre tableaux finaux de la classe NeuralNetwork contiennent les deltas (et non les gradients) provenant de l'itération précédente de la boucle d'entraînement. Ces deltas précédents sont nécessaires si vous utilisez le mécanisme d'inertie afin d'éviter la non-convergence de la rétropropagation. Je considère l'inertie comme un élément essentiel, mais si vous décidez de ne pas l'implémenter, vous pouvez ignorer ces tableaux. Ils sont déclarés de la façon suivante :

private double[][] ihPrevWeightsDelta;  // For momentum
private double[] ihPrevBiasesDelta;
private double[][] hoPrevWeightsDelta;
private double[] hoPrevBiasesDelta;

Ces tableaux sont instanciés de la façon suivante :

ihPrevWeightsDelta = Helpers.MakeMatrix(numInput, numHidden);
ihPrevBiasesDelta = new double[numHidden];
hoPrevWeightsDelta = Helpers.MakeMatrix(numHidden, numOutput);
hoPrevBiasesDelta = new double[numOutput];

Calcul des sorties

Chaque itération de la boucle d'entraînement illustrée à la figure 1 est composée de deux parties. Dans la première partie, les sorties sont calculées à l'aide des entrées, poids et biais principaux actuels. Dans la seconde partie, la rétropropagation permet de modifier les poids et biais. Le diagramme de la figure 3 illustre les deux parties de ce processus d'entraînement.

De la gauche vers la droite, les entrées x0, x1 et x2 se voient attribuer les valeurs 1.0, 2.0 et 3.0. Ces valeurs d'entrée principales vont dans les neurones de la couche d'entrée et sont émises sans modification. Bien que les neurones de la couche d'entrée puissent modifier leur entrée, par exemple en normalisant les valeurs de façon à ce qu'elles soient comprises dans une plage donnée, ce processus est généralement effectué de façon externe. C'est la raison pour laquelle les diagrammes de réseau neuronal utilisent souvent des rectangles ou des carrés pour les neurones d'entrée afin d'indiquer qu'ils ne traitent pas les neurones dans le même sens que les neurones de la couche cachée et de la couche de sortie. En outre, cela a un impact sur la terminologie utilisée. Dans certains cas, le réseau neuronal illustré à la figure 3 serait qualifié de réseau à trois couches, mais étant donné que la couche d'entrée n'effectue aucun traitement, le réseau neuronal présenté est aussi parfois qualifié de réseau à deux couches.

Ensuite, chaque neurone de la couche cachée calcule une entrée locale et une sortie locale. Par exemple, le neurone caché inférieur, avec l'index [3], calcule sa somme temporaire de la façon suivante : (1.0)(0.4)+(2.0)(0.8)+(3.0)(1.2) = 5.6. La somme temporaire est le produit de la somme de ces trois entrées multiplié par le poids de la couche d'entrée vers la couche cachée. Les valeurs situées au-dessus de chaque flèche sont les poids. Ensuite, la valeur de biais, -7.0, est ajoutée à la somme temporaire afin de donner une valeur d'entrée locale de 5.6 + (-7.0) = -1.40. Ensuite, la fonction d'activation de la couche d'entrée vers la couche cachée est appliquée à cette valeur d'entrée intermédiaire afin de donner la valeur de sortie locale du neurone. Dans ce cas de figure, la fonction d'activation est la fonction sigmoïde. La sortie locale est donc : 1 / (1 + exp(-(-1.40))) = 0.20.

Les neurones de la couche de sortie calculent leur entrée et leur sortie de la même manière. Par exemple, à la figure 3, le neurone inférieur de la couche de sortie avec l'index [1] calcule sa somme temporaire de la façon suivante : (0.86)(1.4)+(0.17)(1.6)+(0.98)(1.8)+(0.20)(2.0) = 3.73. Le biais associé est ajouté afin de donner l'entrée locale : 3.73 + (-5.0) = -1.37. Et la fonction d'activation est appliquée pour donner la sortie principale : tanh(-1.37) = -0.88. Si vous examinez le code de ComputeOutputs, vous verrez que la méthode calcule les sorties exactement comme je viens de le décrire.

Rétropropagation

Bien que les mathématiques qui sous-tendent la théorie de la rétropropagation soient particulièrement compliquées, une fois que vous connaissez les résultats correspondants, l'implémentation de la rétropropagation n'est pas trop complexe. La rétropropagation commence de gauche à droite dans le diagramme illustré à la figure 3. La première étape consiste à calculer les valeurs de gradient pour chaque neurone de la couche de sortie. Rappelez-vous que le gradient est une valeur avec des informations sur la magnitude et le sens d'une erreur. Les gradients des neurones de la couche de sortie sont calculés différemment de ceux de la couche cachée.

Le gradient d'un neurone de la couche de sortie est égal à la valeur cible (souhaitée) moins la valeur de sortie calculée, multipliée par la dérivée du calcul pour la fonction d'activation de la couche de sortie évaluée à la valeur de sortie calculée. Par exemple, à la figure 3, la valeur du gradient du neurone inférieur de la couche de sortie, avec l'index [1], est calculée de la façon suivante :

(0.75 – (-0.88)) * (1 – (-0.88)) * (1 + (-0.88)) = 0.37   

La valeur souhaitée est 0.75. -0.88 est la valeur de sortie calculée lors du calcul de propagation vers l'avant. Je vous rappelle que, dans cet exemple, la fonction d'activation de la couche de sortie est la fonction tanh. La dérivée du calcul de tanh(x) est (1 - tanh(x)) * (1 + tanh(x)). L'analyse mathématique est légèrement complexe, mais le calcul du gradient d'un neurone de la couche de sortie est finalement donné par la formule décrite ici.

Le gradient d'un neurone de la couche cachée est égal à la dérivée du calcul de la fonction d'activation pour la couche cachée évaluée sur la sortie locale du neurone, multipliée par la somme du produit des sorties principales, multipliée par les poids associés de la couche cachée vers la couche de sortie. Par exemple, à la figure 3, le gradient du neurone inférieur de la couche cachée, avec l'index [3], est calculé de la façon suivante :

(0.20)(1 – 0.20) * [ (-0.76)(1.9) + (0.37)(2.0) ] = -0.03

Si nous appelons la fonction sigmoïde g(x), la dérivée du calcul de cette fonction est g(x) * (1 - g(x)). Je vous rappelle que cet exemple utilise la fonction sigmoïde pour la fonction d'activation de la couche d'entrée vers la couche cachée. Ici, la valeur 0.20 correspond à la sortie locale provenant du neurone. Les valeurs -0.76 et 0.37 sont les gradients des neurones de la couche de sortie, et les valeurs 1.9 et 2.0 sont les poids de la couche cachée vers la couche de sortie associés aux deux gradients de la couche de sortie.

Calcul des deltas de poids et de biais

Une fois tous les gradients de la couche de sortie et de la couche cachée calculés, l'étape suivante de l'algorithme de rétropropagation consiste à utiliser les valeurs de gradient pour calculer les valeurs deltas de chaque valeur de poids et de biais. Contrairement aux gradients, qui doivent être calculés de la droite vers la gauche, les valeurs deltas peuvent être calculées dans n'importe quel ordre. La valeur delta d'un poids ou d'un biais est égale à êta fois le gradient associé au poids ou au biais, multipliées par la valeur d'entrée associée au poids ou au biais. Par exemple, la valeur delta du poids de la couche d'entrée vers la couche cachée du neurone d'entrée [2] vers le neurone caché [3] est la suivante :

    delta i-h poids[2][3] = eta * gradient caché[3] * entrée[2]
    = 0.90 * (-0.11) * 3.0
    = -0.297

0.90 est la valeur êta qui contrôle la vitesse d'apprentissage de la rétropropagation. Des valeurs plus importantes d'êta produisent des changements de delta plus importants, avec le risque de dépasser la bonne réponse. La valeur -0.11 est le gradient du neurone caché [3]. La valeur 3.0 est la valeur d'entrée du neurone d'entrée [2]. En ce qui concerne le diagramme de la figure 3, si un poids est représenté sous forme de flèche d'un neurone à l'autre, pour calculer le delta d'un poids donné, vous utilisez la valeur de gradient du neurone vers lequel la flèche pointe sur la droite et la valeur d'entrée du neurone à partir duquel la flèche pointe, sur la gauche.

Lors du calcul des deltas pour les valeurs de biais, vous remarquerez que dans la mesure où les valeurs de biais sont simplement ajoutées à une somme intermédiaire, aucune valeur d'entrée ne leur est associée. Par conséquent, pour calculer le delta d'une valeur de biais, vous pouvez soit omettre complètement le terme de la valeur d'entrée, soit utiliser une valeur 1.0 factice à titre de documentation. Par exemple, à la figure 3, le biais inférieur de la couche cachée a la valeur -7.0. Le delta de cette valeur de biais est le suivant :

    0.90 * gradient du neurone pointé vers * 1.0
    = 0.90 * (-0.11) * 1.0
    = 0.099

Ajout d'un terme d'inertie

Une fois toutes les valeurs deltas de poids et de biais calculées, il est possible de mettre à jour chaque poids et biais en ajoutant simplement la valeur delta associée. Toutefois, l'expérience des réseaux neuronaux a prouvé qu'avec certains ensembles de données, l'algorithme de rétropropagation pouvait osciller, dépasser, puis rester inférieur à la valeur cible à plusieurs reprises, sans jamais converger vers un ensemble final d'estimations de poids et de biais. Pour limiter cette tendance, vous pouvez notamment ajouter à chaque nouveau poids et biais un terme supplémentaire nommé inertie. L'inertie d'un poids (ou biais) est une simple valeur peu élevée (par exemple, 0.4 dans le programme de démonstration) multipliée par la valeur du delta précédent pour le poids. L'utilisation de l'inertie ajoute un peu de complexité à l'algorithme de rétropropagation parce que les valeurs des deltas précédents doivent être stockées. Les mathématiques qui permettent à cette technique d'éviter l'oscillation sont subtiles, mais le résultat est simple.

Pour résumer, la première étape de mise à jour d'un poids (ou biais) à l'aide de la rétropropagation consiste à calculer les gradients de tous les neurones de la couche de sortie. La deuxième étape consiste à calculer les gradients de tous les neurones de la couche cachée. La troisième étape consiste à calculer les deltas de tous les poids à l'aide d'êta, le taux d'apprentissage. La quatrième étape consiste à ajouter les deltas à chaque poids. La cinquième étape consiste à ajouter un terme d'inertie à chaque poids.  

Codage avec Visual Studio 2012

L'explication de la rétropropagation proposée dans cet article, associée à l'exemple de code, devrait vous fournir une quantité d'informations suffisante pour que vous soyez en mesure de comprendre et de coder l'algorithme de rétropropagation. La rétropropagation est simplement l'une des quelques techniques permettant d'estimer les valeurs optimales de poids et de biais pour un ensemble de données. Comparée à des solutions alternatives, telles que les algorithmes d'optimisation de masse des particules et d'optimisation évolutionnaire, la rétropropagation a tendance à être plus rapide. Toutefois, la rétropropagation présente quelques inconvénients. Elle ne peut pas être utilisée avec les réseaux neuronaux qui utilisent des fonctions d'activation non dérivables. La recherche des valeurs adaptées aux paramètres de taux d'apprentissage et d'inertie est plus un art qu'une science et elle peut prendre du temps.

Cet article n'aborde pas plusieurs sujets importants, notamment le traitement de plusieurs éléments de données cibles. J'expliquerai ce concept et d'autres techniques de réseau neuronal dans de futurs articles.

Lors du codage du programme de démonstration pour cet article, j'ai utilisé la version bêta de Visual Studio 2012. Bien que de nombreuses fonctionnalités nouvelles de Visual Studio 2012 soient liées aux applications Windows 8, je voulais voir comment cette version gérait les anciennes applications de console. J'ai été agréablement surpris de ne pas être désagréablement surpris par les nouvelles fonctionnalités de Visual Studio 2012. Ma transition vers Visual Studio 2012 s'est déroulée sans accroc. Bien que je n'aie pas utilisé la nouvelle fonctionnalité Async dans Visual Studio 2012, elle aurait pu m'être utile lors du calcul de toutes les valeurs deltas pour chaque poids et biais. J'ai testé la nouvelle fonctionnalité Hiérarchie d'appels et je l'ai trouvée utile et intuitive. Mes impressions initiales de Visual Studio 2012 ont été positives et j'ai l'intention de faire la transition vers cette version dès que possible.

Le Dr. James McCaffrey travaille pour Volt Information Sciences Inc., où il gère la formation technique d'ingénieurs logiciels travaillant sur le Campus Microsoft à Redmond (État de Washington). Il a collaboré à plusieurs produits Microsoft, comme Internet Explorer et MSN Search. Il est l'auteur de « NET Test Automation Recipes » (Apress, 2006) et vous pouvez le contacter à l'adresse jammc@microsoft.com.

Merci à l'expert technique suivant d'avoir relu cet article : Dan Liebling