Différenciation automatique - Automatic differentiation

En mathématiques et de calcul formel , la différentiation automatique ( AD ), également appelée différenciation algorithmique , la différenciation de calcul , auto-différenciation , ou simplement autodiff , est un ensemble de techniques pour évaluer la dérivée d'une fonction spécifiée par un programme informatique. AD exploite le fait que tout programme informatique, aussi compliqué soit-il, exécute une séquence d'opérations arithmétiques élémentaires (addition, soustraction, multiplication, division, etc.) et de fonctions élémentaires (exp, log, sin, cos, etc.). En appliquant à plusieurs reprises la règle de la chaîne à ces opérations, des dérivées d'ordre arbitraire peuvent être calculées automatiquement, avec précision à la précision de travail, et en utilisant au plus un petit facteur constant plus d'opérations arithmétiques que le programme original.

Figure 1 : Comment la différenciation automatique se rapporte à la différenciation symbolique

La différenciation automatique est distincte de la différenciation symbolique et de la différenciation numérique (la méthode des différences finies). La différenciation symbolique peut conduire à un code inefficace et se heurte à la difficulté de convertir un programme informatique en une seule expression, tandis que la différenciation numérique peut introduire des erreurs d'arrondi dans le processus de discrétisation et d'annulation. Les deux méthodes classiques ont des problèmes avec le calcul des dérivées plus élevées, où la complexité et les erreurs augmentent. Enfin, les deux méthodes classiques sont lentes à calculer les dérivées partielles d'une fonction par rapport à de nombreuses entrées, comme cela est nécessaire pour les algorithmes d' optimisation basés sur le gradient . La différenciation automatique résout tous ces problèmes.

La règle de la chaîne, l'accumulation avant et arrière

La décomposition des différentiels fournie par la règle de la chaîne est fondamentale pour l'AD . Pour la composition simple

la règle de la chaîne donne

Habituellement, deux modes distincts d'AD sont présentés, l'accumulation directe (ou mode direct ) et l'accumulation inverse (ou mode inverse ). L'accumulation directe spécifie que l'on parcourt la règle de la chaîne de l'intérieur vers l'extérieur (c'est-à-dire d'abord calculer puis et enfin ), tandis que l'accumulation inverse a la traversée de l'extérieur vers l'intérieur (d'abord calculer puis et enfin ). Plus succinctement,

  1. l'accumulation en avant calcule la relation récursive : avec , et,
  2. l'accumulation inverse calcule la relation récursive : avec .

Accumulation à terme

Figure 2 : Exemple d'accumulation à terme avec graphe de calcul

Dans l'accumulation directe AD, on fixe d'abord la variable indépendante par rapport à laquelle la différenciation est effectuée et on calcule la dérivée de chaque sous- expression de manière récursive. Dans un calcul sur papier, cela implique de substituer à plusieurs reprises la dérivée des fonctions internes dans la règle de la chaîne :

Cela peut être généralisé à plusieurs variables en tant que produit matriciel de Jacobiens .

Par rapport à l'accumulation inverse, l'accumulation avant est naturelle et facile à mettre en œuvre car le flux d'informations dérivées coïncide avec l'ordre d'évaluation. Chaque variable w est augmentée avec son dérivé W (stocké en tant que valeur numérique, et non pas une expression symbolique),

comme indiqué par le point. Les dérivées sont ensuite calculées en synchronisation avec les étapes d'évaluation et combinées avec d'autres dérivées via la règle de la chaîne.

A titre d'exemple, considérons la fonction :

Pour plus de clarté, les sous-expressions individuelles ont été étiquetées avec les variables w i .

Le choix de la variable indépendante à laquelle est effectuée la différenciation affecte les semences des valeurs W 1 et W 2 . Compte tenu de l'intérêt pour la dérivée de cette fonction par rapport à x 1 , les valeurs de départ doivent être définies sur :

Avec les valeurs de départ définies, les valeurs se propagent à l'aide de la règle de chaîne comme indiqué. La figure 2 montre une représentation graphique de ce processus sous forme de graphique informatique.

Opérations pour calculer la valeur Opérations pour calculer la dérivée
(planter)
(planter)

Pour calculer le gradient de cet exemple de fonction, qui nécessite les dérivées de f par rapport non seulement à x 1 mais également à x 2 , un balayage supplémentaire est effectué sur le graphe de calcul en utilisant les valeurs de départ .

La complexité de calcul d'un balayage d'accumulation vers l'avant est proportionnelle à la complexité du code d'origine.

L'accumulation directe est plus efficace que l'accumulation inverse pour les fonctions f  : R nR m avec mn car seuls n balayages sont nécessaires, contre m balayages pour l'accumulation inverse.

Cumul inversé

Figure 3 : Exemple d'accumulation inversée avec graphe de calcul

Dans l'accumulation inverse AD, la variable dépendante à différencier est fixe et la dérivée est calculée par rapport à chaque sous- expression de manière récursive. Dans un calcul sur papier, la dérivée des fonctions externes est substituée à plusieurs reprises dans la règle de la chaîne :

En accumulation inverse, la quantité d'intérêt est l' adjointe , notée par une barre ( ) ; c'est une dérivée d'une variable dépendante choisie par rapport à une sous-expression w :

L'accumulation inverse traverse la règle de la chaîne de l'extérieur vers l'intérieur, ou dans le cas du graphique de calcul de la figure 3, de haut en bas. L'exemple de fonction est à valeur scalaire, et il n'y a donc qu'une seule graine pour le calcul de la dérivée, et un seul balayage du graphique de calcul est nécessaire pour calculer le gradient (à deux composants). Ce n'est que la moitié du travail par rapport à l'accumulation directe, mais l'accumulation inverse nécessite le stockage des variables intermédiaires w i ainsi que les instructions qui les ont produites dans une structure de données connue sous le nom de liste de Wengert (ou "bande"), qui peut consomment beaucoup de mémoire si le graphe de calcul est grand. Cela peut être atténué dans une certaine mesure en stockant uniquement un sous-ensemble des variables intermédiaires, puis en reconstruisant les variables de travail nécessaires en répétant les évaluations, une technique connue sous le nom de rematérialisation . Le point de contrôle est également utilisé pour enregistrer les états intermédiaires.

Les opérations de calcul de la dérivée par accumulation inversée sont présentées dans le tableau ci-dessous (notez l'ordre inversé) :

Opérations pour calculer la dérivée

Le graphique de flux de données d'un calcul peut être manipulé pour calculer le gradient de son calcul d'origine. Ceci est fait en ajoutant un nœud adjoint pour chaque nœud primaire, connecté par des arêtes adjointes qui sont parallèles aux arêtes primaires mais s'écoulent dans la direction opposée. Les nœuds du graphe adjoint représentent la multiplication par les dérivées des fonctions calculées par les nœuds du primal. Par exemple, l'addition dans le primal provoque un déploiement dans l'adjoint ; l'épanouissement dans le primal provoque l'addition dans l'adjoint ; une fonction unaire y = f  ( x ) dans les causes primaires = ȳ f  ′( x ) dans l'adjoint ; etc.

L' accumulation inverse est plus efficace que l' accumulation proposées pour cette fonction f  : R nR m avec m « n que seulement m balayages sont nécessaires, par rapport à n balayages pour l' accumulation de l' avant.

Le mode inverse AD a été publié pour la première fois en 1976 par Seppo Linnainmaa .

La rétropropagation des erreurs dans les perceptrons multicouches, une technique utilisée en apprentissage automatique , est un cas particulier de l'AD en mode inverse.

Au-delà de l'accumulation avant et arrière

L'accumulation directe et inverse ne sont que deux manières (extrêmes) de franchir la règle de la chaîne. Le problème du calcul d'un Jacobien complet de f  : R nR m avec un nombre minimum d'opérations arithmétiques est connu sous le nom de problème d' accumulation Jacobienne optimale (OJA), qui est NP-complet . Au centre de cette preuve se trouve l'idée que des dépendances algébriques peuvent exister entre les partiels locaux qui étiquettent les arêtes du graphe. En particulier, deux étiquettes de bord ou plus peuvent être reconnues comme égales. La complexité du problème est encore ouverte si l'on suppose que toutes les étiquettes d'arêtes sont uniques et algébriquement indépendantes.

Différenciation automatique à l'aide de nombres doubles

La différenciation automatique en mode direct est accomplie en augmentant l' algèbre des nombres réels et en obtenant une nouvelle arithmétique . Un composant supplémentaire est ajouté à chaque nombre pour représenter la dérivée d'une fonction au nombre, et tous les opérateurs arithmétiques sont étendus pour l'algèbre augmentée. L'algèbre augmentée est l'algèbre des nombres duels .

Remplacez chaque nombre par le nombre , où est un nombre réel, mais est un nombre abstrait avec la propriété (un infinitésimal ; voir Lisser l'analyse infinitésimale ). En utilisant seulement ceci, l'arithmétique régulière donne

et de même pour la soustraction et la division.

Maintenant, les polynômes peuvent être calculés dans cette arithmétique augmentée. Si , alors

où désigne la dérivée de par rapport à son premier argument, et , appelé germe , peut être choisi arbitrairement.

La nouvelle arithmétique se compose de paires ordonnées , d'éléments écrits , avec une arithmétique ordinaire sur la première composante, et une arithmétique de différenciation de premier ordre sur la seconde composante, comme décrit ci-dessus. L'extension des résultats ci-dessus sur les polynômes aux

fonctions analytiques donne une liste de l'arithmétique de base et de quelques fonctions standard pour la nouvelle arithmétique :
et en général pour la fonction primitive ,
où et sont les dérivées de par rapport à ses premier et deuxième arguments, respectivement.

Lorsqu'une opération arithmétique de base binaire est appliquée à des arguments mixtes (la paire et le nombre réel), le nombre réel est d'abord élevé à . La dérivée d'une fonction au point est maintenant trouvée en calculant en utilisant l'arithmétique ci-dessus, ce qui donne comme résultat.

Arguments et fonctions vectoriels

Les fonctions multivariées peuvent être traitées avec la même efficacité et les mêmes mécanismes que les fonctions univariées en adoptant un opérateur dérivé directionnel. Autrement dit, s'il suffit de calculer , la dérivée directionnelle de à dans la direction , cela peut être calculé en utilisant la même arithmétique que ci-dessus. Si tous les éléments de sont souhaités, des évaluations de fonction sont nécessaires. Notez que dans de nombreuses applications d'optimisation, la dérivée directionnelle est en effet suffisante.

Ordre élevé et nombreuses variables

L'arithmétique ci-dessus peut être généralisée pour calculer les dérivées de second ordre et supérieures de fonctions multivariées. Cependant, les règles arithmétiques se compliquent rapidement : la complexité est quadratique au plus haut degré de dérivée. Au lieu de cela, l' algèbre polynomiale de Taylor tronquée peut être utilisée. L'arithmétique résultante, définie sur des nombres doubles généralisés, permet un calcul efficace en utilisant des fonctions comme s'il s'agissait d'un type de données. Une fois que le polynôme de Taylor d'une fonction est connu, les dérivées sont facilement extraites.

Mise en œuvre

L'AD en mode direct est implémentée par une interprétation non standard du programme dans laquelle les nombres réels sont remplacés par des nombres doubles, les constantes sont élevées à des nombres doubles avec un coefficient epsilon nul et les primitives numériques sont élevées pour fonctionner sur des nombres doubles. Cette interprétation non standard est généralement implémentée à l'aide de l'une des deux stratégies suivantes : transformation du code source ou surcharge d'opérateur .

Transformation de code source (SCT)

Figure 4 : Exemple de la façon dont la transformation du code source pourrait fonctionner

Le code source d'une fonction est remplacé par un code source généré automatiquement qui comprend des instructions de calcul des dérivées entrelacées avec les instructions d'origine.

La transformation du code source peut être implémentée pour tous les langages de programmation, et il est également plus facile pour le compilateur d'optimiser le temps de compilation. Cependant, la mise en œuvre de l'outil AD lui-même est plus difficile.

Surcharge de l'opérateur (OO)

Figure 5 : Exemple de comment la surcharge d'opérateur pourrait fonctionner

La surcharge d'opérateurs est une possibilité pour le code source écrit dans un langage le supportant. Les objets pour les nombres réels et les opérations mathématiques élémentaires doivent être surchargés pour prendre en charge l'arithmétique augmentée décrite ci-dessus. Cela ne nécessite aucun changement dans la forme ou la séquence d'opérations dans le code source d'origine pour que la fonction soit différenciée, mais nécessite souvent des modifications des types de données de base pour les nombres et les vecteurs afin de prendre en charge la surcharge et implique souvent également l'insertion d'opérations de marquage spéciales.

La surcharge de l'opérateur pour l'accumulation avant est facile à mettre en œuvre, et également possible pour l'accumulation inverse. Cependant, les compilateurs actuels sont à la traîne dans l'optimisation du code par rapport à l'accumulation en avant.

La surcharge d'opérateurs, pour l'accumulation directe et inverse, peut être bien adaptée aux applications où les objets sont des vecteurs de nombres réels plutôt que des scalaires. En effet, la bande comporte alors des opérations vectorielles ; cela peut faciliter des implémentations efficaces en termes de calcul où chaque opération vectorielle effectue de nombreuses opérations scalaires. Des techniques de différenciation algorithmique adjointe vectorielle (AAD vectorielle) peuvent être utilisées, par exemple, pour différencier des valeurs calculées par simulation Monte-Carlo.

Les bibliothèques Adept et Stan sont des exemples d'implémentations surchargées d'opérateurs de la différenciation automatique en C++ .

Voir également

Remarques

Les références

Lectures complémentaires

Liens externes