Exemple pas à pas de différenciation automatique en mode inverse

27

Je ne sais pas si cette question appartient ici, mais elle est étroitement liée aux méthodes de gradient en optimisation, qui semble être sur le sujet ici. Quoi qu'il en soit, n'hésitez pas à migrer si vous pensez qu'une autre communauté a une meilleure expertise dans le sujet.

En bref, je cherche un exemple étape par étape de différenciation automatique en mode inverse . Il n'y a pas beaucoup de littérature sur le sujet et l'implémentation existante (comme celle de TensorFlow ) est difficile à comprendre sans connaître la théorie qui la sous-tend. Je serais donc très reconnaissant si quelqu'un pouvait montrer en détail ce que nous transmettons , comment nous le traitons et ce que nous retirons du graphique de calcul.

Quelques questions avec lesquelles j'ai le plus de difficulté:

  • graines - pourquoi en avons-nous besoin?
  • règles de différenciation inversée - Je sais comment faire la différenciation vers l'avant, mais comment allons-nous en arrière? Par exemple, dans l'exemple de cette section , comment savons-nous que ?w2¯=w3¯w1
  • travaillons-nous uniquement avec des symboles ou passons-nous par des valeurs réelles ? Par exemple, dans le même exemple , les symboles ou valeurs et sont-ils?¯ w iwiwi¯
ami
la source
"L'apprentissage automatique avec Scikit-Learn et TensorFlow" L'annexe D donne une très bonne explication à mon avis. Je le recommande.
Agustin Barrachina

Réponses:

37

Disons que nous avons l'expression z=x1x2+sin(x1) et que nous voulons trouver des dérivées dzdx1 etdzdx2 . L'AD en mode inverse divise cette tâche en 2 parties, à savoir les passes avant et arrière.

Passe avant

Tout d'abord, nous décomposons notre expression complexe en un ensemble d'expressions primitives, c'est-à-dire des expressions consistant au plus en un seul appel de fonction. Notez que je renomme également les variables d'entrée et de sortie pour des raisons de cohérence, bien que ce ne soit pas nécessaire:

w1=x1
w2=x2
w3=w1w2
w4=sin(w1)
w5=w3+w4
z=w5

L'avantage de cette représentation est que les règles de différenciation pour chaque expression distincte sont déjà connues. Par exemple, nous savons que la dérivée du sin est cos , et donc dw4dw1=cos(w1). Nous utiliserons ce fait en passe inverse ci-dessous.

Essentiellement, la transmission directe consiste à évaluer chacune de ces expressions et à enregistrer les résultats. Disons que nos entrées sont: x1=2 et x2=3 . Ensuite nous avons:

w1=x1=2
w2=x2=3
w3=w1w2=6
w4=sin(w1) =0.9
w5=w3+w4=6.9
z=w5=6.9

Passe arrière

C'est là que la magie commence, et cela commence par la règle de la chaîne . Dans sa forme de base, la règle de chaîne stipule que si vous avez la variable t(u(v)) qui dépend de u qui, à son tour, dépend de v , alors:

dtdv=dtdududv

ou, si t dépend de v via plusieurs chemins / variables ui , par exemple:

u1=f(v)
u2=g(v)
t=h(u1,u2)

alors (voir la preuve ici ):

tv=jetujeujev

En termes de graphe d'expression, si nous avons un nœud final z et des nœuds d'entrée wje , et le chemin de z à wje passe par les nœuds intermédiaires wp (c'est-à-dire z=g(wp)wp=F(wje) ), on peut trouver la dérivée zwje as

zwje=ppunerents(je)zwpwpwje

En d'autres termes, pour calculer la dérivée de la variable de sortie z rapport à toute variable intermédiaire ou d'entrée wje , il suffit de connaître les dérivées de ses parents et la formule pour calculer la dérivée de l'expression primitive wp=F(wje) .

La passe inverse commence à la fin (c'est-à-dire zz ) et se propage en arrière vers toutes les dépendances. Nous avons ici (expression pour "graine"):

zz=1

Cela peut être lu comme «un changement de z entraîne exactement le même changement de z », ce qui est assez évident.

On sait alors que z=w5 et ainsi:

zw5=1

w5 dépend linéairement dew3 etw4 , doncw5w3=1etw5w4=1. En utilisant la règle de chaîne, nous trouvons:

zw3=zw5w5w3=1×1=1
zw4=zw5w5w4=1×1=1

D'après la définition w3=w1w2 et les règles des dérivées partielles, nous constatons que w3w2=w1. Ainsi:

zw2=zw3w3w2=1×w1=w1

Ce qui, comme nous le savons déjà par la passe avant, est:

zw2=w1=2

Enfin, w1 contribue à z via w3 et w4 . Encore une fois, à partir des règles des dérivées partielles, nous savons que w3w1=w2etw4w1=cos(w1). Ainsi:

zw1=zw3w3w1+zw4w4w1=w2+cos(w1)

Et encore une fois, étant donné les entrées connues, nous pouvons le calculer:

zw1=w2+cos(w1)=3+cos(2) =2,58

w1w2X1X2

zX1=2,58
dzdx2=2

Et c'est tout!


Cette description ne concerne que les entrées scalaires, c'est-à-dire les nombres, mais en fait, elle peut également être appliquée à des tableaux multidimensionnels tels que des vecteurs et des matrices. Deux choses que l'on doit garder à l'esprit lors de la différenciation des expressions avec de tels objets:

  1. Les dérivés peuvent avoir une dimensionnalité beaucoup plus élevée que les entrées ou les sorties, par exemple le dérivé du vecteur par rapport au vecteur est une matrice et le dérivé de la matrice par rapport à la matrice est un tableau à 4 dimensions (parfois appelé tenseur). Dans de nombreux cas, ces dérivés sont très rares.
  2. y=f(x)xyyiyjxkdyidxjyixj

zw1=w2+cos(w1)=X2+cos(X1)

ami
la source
1
Question / réponse très utile. Merci. Juste une petite critique: vous semblez vous déplacer sur une structure arborescente sans expliquer (c'est là que vous commencez à parler de parents, etc.)
MadHatter
1
De plus, cela ne fera pas de mal de clarifier pourquoi nous avons besoin de graines.
MadHatter
zz=1
Merci! J'ai remarqué quand vous devez définir plus d'une "graine", généralement on choisit 1 et 0. Je voudrais savoir pourquoi. Je veux dire, on prend le "quotient" d'un différentiel par rapport à lui-même, donc "1" est au moins intuitivement justifié. Mais qu'en est-il de 0? Et si on devait cueillir plus de 2 graines?
MadHatter
1
Pour autant que je sache, plus d'une graine est utilisée uniquement en mode direct AD. Dans ce cas, vous définissez la valeur de départ à 1 pour une variable d'entrée que vous souhaitez différencier et la valeur de départ à 0 pour toutes les autres variables d'entrée afin qu'elles ne contribuent pas à la valeur de sortie. En mode inverse, vous définissez la valeur de départ sur une variable de sortie et vous n'avez normalement qu'une seule variable de sortie. Je suppose que vous pouvez construire un pipeline AD en mode inverse avec plusieurs variables de sortie et les définir toutes, sauf une sur 0, pour obtenir le même effet qu'en mode direct, mais je n'ai jamais étudié cette option.
ffriend