• Aucun résultat trouvé

6.6.3 ´ Evaluation r´etrograde

´

Evaluer (6.114) de fac¸on r´etrograde (de la droite vers la gauche) est parti-culi`erement ´economique en flops, car chaque r´esultat interm´ediaire est un vecteur de mˆeme dimension que b (c’est `a dire dim v), tandis qu’une ´evaluation progres-sive (de la gauche vers la droite) produirait des r´esultats interm´ediaires de mˆemes dimensions que C (c’est `a dire dim x× dimv). Plus dimx est grand, plus il de-vient ´economique de choisir l’´evaluation r´etrograde. R´esoudre (6.114) de fac¸on r´etrograde implique de calculer la r´ecurrence

dk−1= Akdk, k= N,··· ,1, (6.118) qui remonte le “temps”, `a partir de la condition terminale

La valeur du gradient de f(·) en x0est finalement donn´ee par ∂ f

∂ x(x0) = Cd0, (6.120) ce qui revient `a dire qu’elle est contenue dans les dim x premiers ´el´ements de d0. Le vecteur dk a la mˆeme dimension que vket est appel´e son vecteur adjoint (ou vecteur dual). La r´ecurrence (6.118) est mise en œuvre dans un code adjoint, d´eduit du code direct par dualisation, comme expliqu´e ci-dessous. Voir la section 6.7.2 pour un exemple d´etaill´e.

6.6.3.1 Dualisation d’une instruction d’affectation

Examinons

Ak=∂ ΦΦΦ

T k

∂ v (vk−1) (6.121) plus en d´etail. Rappelons que

[ΦΦΦk(vk−1)]µ(k)= φk(vk−1), (6.122) et

[ΦΦΦk(vk−1)]i= vi(k− 1), ∀i 6= µ(k), (6.123) o`u vi(k−1) est la i-`eme composante de vk−1. Ceci a pour cons´equence que Ak s’ob-tient en remplac¸ant la µ(k)-`eme colonne de la matrice identit´e Idim vpar le vecteur

∂ φk ∂ v(vk−1) pour obtenir Ak=            1 0 ··· ∂ φk ∂ v1(vk−1) 0 0 . .. 0 ... ... .. . 0 1 ... ... .. . ... 0 ∂ φk ∂ vµ(k)(vk−1) 0 0 0 0 ... 1            . (6.124)

La structure de Ak r´ev´el´ee par (6.124) a des cons´equences directes sur les instruc-tions d’affectation `a inclure dans le code adjoint pour mettre en œuvre (6.118).

La µ(k)-`eme composante de la diagonale principale de Akest la seule pour la-quelle le un de la matrice identit´e a disparu, ce qui explique pourquoi la µ(k)-`eme composante de dk−1requiert un traitement sp´ecial. Soit di(k− 1) la i-`eme compo-sante de dk−1. `A cause de (6.124), la r´ecurrence (6.118) ´equivaut `a

di(k− 1) = di(k) +∂ φk ∂ vi

(vk−1)dµ(k)(k), ∀i 6= µ(k), (6.125) dµ(k)(k− 1) = ∂ φk

∂ vµ(k)(vk−1)dµ(k)(k). (6.126) Pour calculer d0, il n’est pas n´ecessaire de stocker les valeurs successives prises par le vecteur dual d, et l’indexation de d par le “temps” peut donc ˆetre ´evit´ee. Les (pseudo) instructions adjointes pour

vµ(k):= φk({vi| i ∈ Ik}); seront alors, dans cet ordre

for all i∈ Ik, i6= µ(k), do di:= di+∂ φk

∂ vi(vk−1)dµ(k); dµ(k):= ∂ φk

∂ vµ(k)(vk−1)dµ(k);

Remarque 6.11.Si φkd´epend non lin´eairement de certaines variables du code direct, alors le code adjoint fera intervenir les valeurs prises par ces variables, qui devront donc ˆetre stock´ees lors de l’ex´ecution du code direct avant l’ex´ecution du code ad-joint. Ces exigences de stockage sont une limitation de l’´evaluation r´etrograde.  Exemple 6.12.Supposons que le code direct contienne l’instruction d’affectation

cost:= cost+(y-ym)2; de sorte que φk= cost+(y-ym)2.

Soient dcost, dy et dymles variables duales de cost, y et ym. La dualisation de cette instruction produit les (pseudo) instructions suivantes pour le code adjoint

dy:= dy +∂ φk

∂ y dcost= dy + 2(y-ym)dcost; dym:= dym+∂ φk

∂ ym dcost= dym− 2(y - ym) dcost; dcost:= ∂ φk

∂ cost dcost= dcost; % inutile

Une seule instruction du code direct s’est donc traduite par plusieurs instructions du

code adjoint. 

6.6.3.2 Ordre de dualisation

Rappelons que le rˆole du temps est tenu par le passage d’une instruction d’af-fectation `a la suivante. Puisque le code adjoint est ex´ecut´e en temps r´etrograde, les groupes d’instructions duales associ´es `a chacune des instructions d’affectation du code direct seront ex´ecut´es dans l’ordre inverse de l’ex´ecution des instructions d’af-fectation correspondantes du code direct.

Quand le code direct comporte des boucles, inverser le sens du temps revient `a inverser le sens de variation de leurs compteurs d’it´erations ainsi que l’ordre des

instructions dans chacune des boucles. En ce qui concerne les branchements condi-tionnels, si le code direct contient

if (C) then (code A) else (code B); alors le code adjoint doit contenir

if (C) then (adjoint de A) else (adjoint de B); et la valeur vraie ou fausse prise par la condition C pendant l’ex´ecution du code direct doit ˆetre m´emoris´ee pour que le code adjoint sache quelle branche suivre.

6.6.3.3 Initialisation du code adjoint

La condition terminale (6.119) avec b donn´e par (6.117) signifie que toutes les variables duales doivent ˆetre initialis´ees `a z´ero, sauf celle associ´ee `a la valeur de

f(x0), qui doit ˆetre initialis´ee `a un.

Remarque 6.12.v, d et Ak ne sont pas m´emoris´es en tant que tels. Seules les va-riables directes et duales interviennent. On am´eliore la lisibilit´e du code adjoint en utilisant une convention syst´ematique pour nommer les variables duales, par exemple en ajoutant un d en tˆete du nom de la variable dualis´ee comme dans

l’exemple 6.12. 

6.6.3.4 En r´esum´e

La proc´edure de diff´erentiation automatique via l’usage d’un code adjoint est r´esum´ee par la figure 6.2.

f (x0) x0

d0 dN

Une exécution du code direct

Une exécution du code adjoint dans d0

Gradient

(utilise des informations du code direct)

La m´ethode `a base de code adjoint ´evite les erreurs de m´ethode dues aux ap-proximations par diff´erences finies. La g´en´eration du code adjoint `a partir du source du code direct est syst´ematique et peut ˆetre automatis´ee.

Le volume de calcul requis pour ´evaluer la fonction f(·) et son gradient est ty-piquement de l’ordre de trois fois celui requis par la seule ´evaluation de la fonction quelle que soit la dimension dex (`a comparer avec l’approche `a base de diff´erences finies, pour laquelle l’´evaluation de f(·) doit ˆetre r´ep´et´ee plus de dimx fois). La m´ethode `a base de code adjoint est donc particuli`erement appropri´ee quand

— dim x est tr`es grand, comme dans certains probl`emes de traitement d’images ou d’optimisation de formes,

— de nombreuses ´evaluations de gradients sont n´ecessaires, comme c’est sou-vent le cas en optimisation,

— l’´evaluation de f(·) est longue ou coˆuteuse.

Par contre, cette m´ethode ne peut ˆetre appliqu´ee que si le source du code direct est disponible et diff´erentiable. Une mise en œuvre `a la main demande du soin, car une seule erreur de codage peut rendre le r´esultat invalide. (Il existe des techniques de v´erification partielle, qui exploitent le fait que le produit scalaire du vecteur dual avec la solution des ´equations d’´etat lin´earis´ees doit rester constant le long de la tra-jectoire de l’´etat.) Finalement, l’ex´ecution du code adjoint requiert la connaissance des valeurs prises par certaines variables lors de l’ex´ecution du code direct (les va-riables qui interviennent de fac¸on non lin´eaire dans des instructions d’affectation du code direct). Il faut donc stocker ces valeurs, ce qui peut poser des probl`emes de taille de m´emoire.