···190190/ $S$: l'ensemble des états possibles de l'environnement
191191/ $rho_0: S -> [0, 1]$: la distribution de probabilité de l'état initial de l'environnement. Si l'on initialise l'environnement de manière uniformément aléatoire, $rho_0$ est une équiprobabilité#footnote[i.e. $card rho_0(S) = 1$]
192192/ $M: S times A -> S$: le moteur de simulation physique, qui applique l'action à un état de l'environnement et envoie le nouvel état de l'environnement
193193-/ $cal(P): S -> A$: une politique
194194-/ $cal(P)^*: S -> A$: la meilleure politique possible, celle que l'on cherche à approcher
193193+/ $Pi: S -> A$: une politique
194194+/ $Pi^*: S -> A$: la meilleure politique possible, celle que l'on cherche à approcher
195195/ $R: S -> RR^+$: sa fonction de récompense // d'une politique $p$
196196/ $Q_p: S times A -> [0, 1]$: sa distribution de probabilité, qu'on suppose Markovienne (elle ne dépend que de l'état dans lequel on est). $Q_p (s_t, a_t)$ est la probabilité que $p$ choisisse $a_t$ _quand on est dans l'état_ $s_t$ ($s_t$ est l'état *pré*-action, et non post-action)
197197-/ $Q$ et $Q^*$: $Q_cal(P)$ et $Q_(cal(P)^*)$, pour alléger les notations
198198-// $R$: $R_cal(P)$
197197+/ $Q$ et $Q^*$: $Q_Pi$ et $Q_(Pi^*)$, pour alléger les notations
198198+// $R$: $R_Pi$
199199200200On suppose $A$ et $S$ dénombrables#footnote[En pratique, $bb(R)$ est discrétisé dans les simulateurs numérique, donc cette hypothèse ne pose pas de problèmes à l'application de la théorie au domaine de la robotique].
201201···210210211211212212213213-$M$ et $cal(P)$ forment en fait tout se qui se passe pendant un pas de temps, c'est cette boucle que l'on répète pour soit entraîner l'agent (si l'on met $cal(P)$ à jour à chaque tour de boucle) ou l'utiliser:
213213+$M$ et $Pi$ forment en fait tout se qui se passe pendant un pas de temps, c'est cette boucle que l'on répète pour soit entraîner l'agent (si l'on met $Pi$ à jour à chaque tour de boucle) ou l'utiliser:
214214215215#diagram(
216216 node((0, 0), $s_t$),
217217 edge(corner: right, label-pos: 2 / 8, label-side: left)[choix de l'action],
218218- edge("->", corner: right, label-pos: 3 / 8, label-side: left)[$cal(P)$],
218218+ edge("->", corner: right, label-pos: 3 / 8, label-side: left)[$Pi$],
219219 node((1, -1))[$a_t$],
220220 edge("->", corner: right, label-pos: 5 / 8, label-side: left)[$M$],
221221 edge(corner: right, label-pos: 6 / 8, label-side: left)[simulation],
···223223 edge((2, 0), (2, .75), (0, .75), (0, 0), "-->", label-side: left)[itération],
224224)
225225226226-Quand on "déroule" $cal(P)$ en en partant d'un certain état initial $s_0$, on obtient une suite d'états et d'actions:
226226+Quand on "déroule" $Pi$ en en partant d'un certain état initial $s_0$, on obtient une suite d'états et d'actions:
227227228228#diagram(
229229 $
···236236237237$
238238 cases(
239239- a_t & = cal(P)(s_t),
239239+ a_t & = Pi(s_t),
240240 s_(t+1) & = M(s_t, a_t),
241241 )
242242$
···415415 caption: [Boucle d'entraînement],
416416 node((0, 0))[$s_t$],
417417 edge("-"),
418418- node(name: <policy>, (0, -1))[$cal(P)$],
418418+ node(name: <policy>, (0, -1))[$Pi$],
419419 edge("->", corner: right),
420420 node((1, -2))[$a_t$],
421421 edge("->", corner: right)[$M$],
422422 node(name: <final>, (2, 0))[$s_(t+1)$],
423423 edge(<final>, (0, 0), "-->", label-side: left)[itération],
424424- // edge("d,d,l,l,l,u,u,u", <policy>, "->", label-pos: 33%, label-side: left, align(center, [$Q_cal(P)(s_(t+1), argmax_(a in A) A_(cal(P), R)(s_(t+1), a)) <- A_(cal(P), R) (dots)$ \ Mise à jour]))
425425- // edge("d,d,l,l,l,u,u,u", <policy>, "->", label-pos: 37%, label-side: left, align(center)[$argmax_(a in A) A_(cal(P), R)(s_(t+1), a)$ \ mise à jour de $cal(P)$])
424424+ // edge("d,d,l,l,l,u,u,u", <policy>, "->", label-pos: 33%, label-side: left, align(center, [$Q_Pi(s_(t+1), argmax_(a in A) A_(Pi, R)(s_(t+1), a)) <- A_(Pi, R) (dots)$ \ Mise à jour]))
425425+ // edge("d,d,l,l,l,u,u,u", <policy>, "->", label-pos: 37%, label-side: left, align(center)[$argmax_(a in A) A_(Pi, R)(s_(t+1), a)$ \ mise à jour de $Pi$])
426426 edge("d,l,l,l,u,u", <policy>, "->", label-pos: 33%, label-side: left, align(
427427 center,
428428 )[
429429- // mise à jour de $cal(P)$ \
430430- $Q_cal(P)(s_(t+1), a_(t+1)^*) <- A_(cal(P), R)(s_(t+1), a_(t+1)^*)$
429429+ // mise à jour de $Pi$ \
430430+ $Q_Pi(s_(t+1), a_(t+1)^*) <- A_(Pi, R)(s_(t+1), a_(t+1)^*)$
431431 ]),
432432) <policy-update-loop>
433433434434Avec
435435436436$
437437- a_(t+1)^* & := argmax_(a in A) A_(cal(P), R)(s_(t+1), a) \
437437+ a_(t+1)^* & := argmax_(a in A) A_(Pi, R)(s_(t+1), a) \
438438$
439439440440-Mais, en pratique, des erreurs d'approximations peuvent rendre $A_(cal(P), R)(s_(t+1), a_(t+1)^*)$ négatif, ce qui empêche de s'en servir pour définir une valeur de $Q_(cal(P))$ @trpo
440440+Mais, en pratique, des erreurs d'approximations peuvent rendre $A_(Pi, R)(s_(t+1), a_(t+1)^*)$ négatif, ce qui empêche de s'en servir pour définir une valeur de $Q_(Pi)$ @trpo
441441442442443443Le _surrogate advantage_ détermine la performance d'une politique par rapport à une autre
···479479480480481481482482-Pour évaluer cette distance, on regarde la plus grande des distances entre des paires de distributions de probabilité de politiques $Q_cal(P)$ et $Q_cal(P)'$ pour $s in S$ fixé @trpo
482482+Pour évaluer cette distance, on regarde la plus grande des distances entre des paires de distributions de probabilité de politiques $Q_Pi$ et $Q_Pi'$ pour $s in S$ fixé @trpo
483483484484$
485485- max_(s in S) D_"KL" (Q_cal(P)' (s, dot) || Q_cal(P) (s, dot)) < delta
485485+ max_(s in S) D_"KL" (Q_Pi' (s, dot) || Q_Pi (s, dot)) < delta
486486$
487487488488···519519520520==== Région de confiance
521521522522-Cette contrainte définit un ensemble réduit de $cal(P)'$ acceptables comme nouvelle politique, aussi appelé une _trust region_ (région de confiance), d'où la méthode d'optimisation tire son nom @trpo.
522522+Cette contrainte définit un ensemble réduit de $Pi'$ acceptables comme nouvelle politique, aussi appelé une _trust region_ (région de confiance), d'où la méthode d'optimisation tire son nom @trpo.
523523524524#let ddot = [ #sym.dot #h(-1em / 16) #sym.dot ]
525525···540540541541542542$
543543- argmax_(cal(P)') & exp_((s, a) in cal(S)) L(s, a, cal(P), cal(P'), R) \
543543+ argmax_(Pi') & exp_((s, a) in cal(S)) L(s, a, Pi, Pi', R) \
544544 "s.c." & top
545545$
546546···549549_PPO-Penalty_ soustrait une divergence K-L pondérée à l'avantage:
550550551551$
552552- L(s, a, cal(P), cal(P'), R) = (Q_cal(P) (s, a)) / (Q_cal(P') (s, a)) A_(cal(P), R) (s, a) - beta D_"KL" (cal(P) || cal(P'))
552552+ L(s, a, Pi, Pi', R) = (Q_Pi (s, a)) / (Q_Pi' (s, a)) A_(Pi, R) (s, a) - beta D_"KL" (Pi || Pi')
553553$
554554555555Avec $beta$ ajusté automatiquement pour être dans la même échelle que l'autre terme de la soustraction.
···560560561561562562$
563563- L(s, a, cal(P), cal(P'), R) = min(
564564- & (Q_cal(P)' (s, a)) / (Q_cal(P) (s, a)) A_(cal(P)', R)(s, a), quad \
563563+ L(s, a, Pi, Pi', R) = min(
564564+ & (Q_Pi' (s, a)) / (Q_Pi (s, a)) A_(Pi', R)(s, a), quad \
565565 &op("clip")(
566566- (Q_cal(P)' (s, a)) / (Q_cal(P) (s, a)),
566566+ (Q_Pi' (s, a)) / (Q_Pi (s, a)),
567567 1 - epsilon,
568568 1 + epsilon
569569- ) A_(cal(P)', R)(s, a)
569569+ ) A_(Pi', R)(s, a)
570570 )
571571$
572572···580580 )
581581$
582582583583-La complexité de l'expression, et la présence d'un $min$ au lieu de simplement un $op("clip")$ est dûe au fait que l'avantage $A_(cal(P)', R) (s, a)$ peut être négatif. L'expression se simplifie en séparant les cas (cf @proof-ppo-clip-simplify)
583583+La complexité de l'expression, et la présence d'un $min$ au lieu de simplement un $op("clip")$ est dûe au fait que l'avantage $A_(Pi', R) (s, a)$ peut être négatif. L'expression se simplifie en séparant les cas (cf @proof-ppo-clip-simplify)
584584585585#let named_point = (
586586 x,
···606606607607#dontbreak[
608608609609- / Si l'avantage est positif: $a$ est un meilleur choix que $cal(P)(s)$.
609609+ / Si l'avantage est positif: $a$ est un meilleur choix que $Pi(s)$.
610610611611 #equation_and_diagram(
612612 $
613613- L(s, a, cal(P), cal(P)', R) = min(
614614- (Q_cal(P)' (s, a)) / (Q_cal(P) (s, a)),
613613+ L(s, a, Pi, Pi', R) = min(
614614+ (Q_Pi' (s, a)) / (Q_Pi (s, a)),
615615 quad 1 + epsilon
616616- ) A_(cal(P)', R)(s, a)
616616+ ) A_(Pi', R)(s, a)
617617 $,
618618 diagram(
619619 spacing: (2.7em, 2em),
620620- node((-1, 0))[$cal(P)'$],
620620+ node((-1, 0))[$Pi'$],
621621 edge((-1, 0), "->", (3, 0), stroke: luma(150)),
622622 edge((-1, 0), "-|", (1, 0), extrude: (1, -1, 0)),
623623 named_point(1, 0, shape: "|")[$1+epsilon$],
624624- named_point(0, 0)[$cal(P)$],
624624+ named_point(0, 0)[$Pi$],
625625 named_point(1.5, 0, color: red, side: left)[$times$],
626626 named_point(0.5, 0, color: olive, side: left)[$checkmark$],
627627 ),
628628 )
629629630630- / Si l'avantage est négatif: choisir $a$ est pire que garder $cal(P)(s)$.
630630+ / Si l'avantage est négatif: choisir $a$ est pire que garder $Pi(s)$.
631631632632 #equation_and_diagram(
633633 $
634634- L(s, a, cal(P), cal(P)', R) = max(
634634+ L(s, a, Pi, Pi', R) = max(
635635 1 - epsilon, quad
636636- (Q_cal(P)' (s, a)) / (Q_cal(P) (s, a))
637637- ) A_(cal(P)', R)(s, a)
636636+ (Q_Pi' (s, a)) / (Q_Pi (s, a))
637637+ ) A_(Pi', R)(s, a)
638638 $,
639639 diagram(
640640 spacing: (2.7em, 2em),
641641- node((3, 0))[$cal(P)'$],
641641+ node((3, 0))[$Pi'$],
642642 edge((-1, 0), "<-", (3, 0), stroke: luma(150)),
643643 edge((1, 0), "|-", (3, 0), extrude: (1, -1, 0)),
644644 named_point(1, 0, shape: "|")[$1-epsilon$],
645645- named_point(2, 0)[$cal(P)$],
645645+ named_point(2, 0)[$Pi$],
646646 named_point(0, 0, color: red, side: left)[$times$],
647647 named_point(1.5, 0, color: olive, side: left)[$checkmark$],
648648 ),
···655655// 1. Mise à jour de la politique:
656656//
657657// $
658658-// cal(P') = argmax_p 1/T sum_(t=1)^T L(s, a, cal(P), p, R)
658658+// Pi' = argmax_p 1/T sum_(t=1)^T L(s, a, Pi, p, R)
659659// $
660660661661
+9-9
rapport/gz-unitree.typ
···1521522. L'interaction avec les canaux DDS du SDK d'Unitree
1531533. Les données et méthodes internes au plugin
154154155155-En plus de cela, il y a bien évidemment la politique de contrôle $cal(P)$, qui interagit via les canaux DDS avec le robot (qu'il soit réel, ou simulé)
155155+En plus de cela, il y a bien évidemment la politique de contrôle $Pi$, qui interagit via les canaux DDS avec le robot (qu'il soit réel, ou simulé)
156156157157#let legend = (
158158 ..descriptions,
···243243 node(name: <cmdbuf>, (2, 3), subtitled("Commands buffer", `cmdbuf`))
244244 group((<lowstate>, <lowcmd>, <statebuf>, <cmdbuf>, <gzclock>, <gzimu>))[Plugin internals]
245245246246- node(name: <policy>, (0, -1), $cal(P)$)
246246+ node(name: <policy>, (0, -1), $Pi$)
247247248248 for e in edges.pos() {
249249 e
···388388389389=== Réception des commandes <receive-lowcmd>
390390391391-Lorsqu'un message, publié par $cal(P)$ (1A) et contenant des ordres pour les moteurs, arrive sur `rt/lowcmd`, `::CmdHandler` est appelé (2, 3), et modifie un _buffer_ (4) contenant la dernière commande reçue.
391391+Lorsqu'un message, publié par $Pi$ (1A) et contenant des ordres pour les moteurs, arrive sur `rt/lowcmd`, `::CmdHandler` est appelé (2, 3), et modifie un _buffer_ (4) contenant la dernière commande reçue.
392392393393394394Ensuite, Gazebo démarre un nouveau pas de simulation. Avant de faire ce pas, il appelle la méthode `::PreUpdate` sur notre plugin, qui vient chercher la commande stockée dans le _buffer_ (1B), et applique cette commande sur le modèle du robot, animé par le simulateur.
···579579580580Avant de démarrer un nouveau pas de simulation, la méthode `::PreUpdate` vient mettre à jour l'état du robot simulé en modifiant le _State buffer_ interne au plugin (1A).
581581582582-Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $cal(P)$ (4), qui (on le suppose) possède une subscription sur `rt/lowstate`
582582+Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $Pi$ (4), qui (on le suppose) possède une subscription sur `rt/lowstate`
583583584584585585#let transparent = luma(0).opacify(0%)
···613613614614- La boucle de simulation de Gazebo (fréquence d'appel de `::PreUpdate`),
615615- La boucle du `ChannelPublisher` (fréquence d'appel de `::LowStateWriter`), et
616616-- La boucle de réception de $cal(P)$ (à quelle fréquence $cal(P)$ est-elle capable de reçevoir des messages)
616616+- La boucle de réception de $Pi$ (à quelle fréquence $Pi$ est-elle capable de reçevoir des messages)
617617618618619619Similairement à la réception de commandes:
620620621621/ Si `::PreUpdate` est plus fréquente: On perdra des états intermédiaires, la résolution temporelle de l'évolution de l'état du robot disponible pour (ou acceptable par#footnote[
622622- En fonction de si `::LowStateWriter` est plus fréquente que $cal(P)$ (dans ce cas là, c'est ce qui est acceptable par $cal(P)$ qui est limitant) ou inversement (dans ce cas, c'est ce que la boucle du publisher met à disposition de $cal(P)$ qui est limitant)
623623- ]) $cal(P)$ sera moins grande
624624-/ Si `::PreUpdate` est moins fréquente: $cal(P)$ reçevra plusieurs fois le même état, ce qui sera représentatif du fait que la simulation n'a pas encore avancé.
622622+ En fonction de si `::LowStateWriter` est plus fréquente que $Pi$ (dans ce cas là, c'est ce qui est acceptable par $Pi$ qui est limitant) ou inversement (dans ce cas, c'est ce que la boucle du publisher met à disposition de $Pi$ qui est limitant)
623623+ ]) $Pi$ sera moins grande
624624+/ Si `::PreUpdate` est moins fréquente: $Pi$ reçevra plusieurs fois le même état, ce qui sera représentatif du fait que la simulation n'a pas encore avancé.
625625626626627627== Désynchronisations
···632632633633/ Bleu: Simulation, qui doit englober l'entièreté d'un cycle
634634/ Rouge: `ChannelPublisher`
635635-/ Rose: Politique $cal(P)$
635635+/ Rose: Politique $Pi$
636636/ Vert: Mise à jour de l'IMU
637637/ Orange: Mise à jour du tick de simulation
638638
rapport/main.pdf
This is a binary file and will not be displayed.
+4-4
rapport/proofs.typ
···105105 &= eta(p, r) quad qed
106106$
107107108108-== Simplification de l'expression de $L(s, a, cal(P), cal(P)', R)$ dans PPO-Clip <proof-ppo-clip-simplify>
108108+== Simplification de l'expression de $L(s, a, Pi, Pi', R)$ dans PPO-Clip <proof-ppo-clip-simplify>
109109110110#let clip = $op("clip")$
111111112112-Soit $(s, a) in S times A$, et $cal(P)'$ une politique. Posons $alpha &:= A_(cal(P)', R) (s, a)$, $q slash q' &:= Q_cal(P) (s, a) slash Q_cal(P)' (s, a)$ .
112112+Soit $(s, a) in S times A$, et $Pi'$ une politique. Posons $alpha &:= A_(Pi', R) (s, a)$, $q slash q' &:= Q_Pi (s, a) slash Q_Pi' (s, a)$ .
113113114114#let why = explanation => $\ & quad quad #[car #explanation]$
115115···128128 [
129129130130 $
131131- &L(s, a, cal(P), cal(P'), R) \
131131+ &L(s, a, Pi, Pi', R) \
132132 &= min(q/q' alpha, quad clip(q/q', thick 1-epsilon, thick 1+epsilon) alpha) \
133133 &= min(q/q', quad clip(q/q', thick 1-epsilon, thick 1+epsilon)) alpha why(alpha > 0) \
134134 $
···136136 [
137137138138 $
139139- &L(s, a, cal(P), cal(P'), R) \
139139+ &L(s, a, Pi, Pi', R) \
140140 &= min(q/q' alpha, quad clip(q/q', thick 1-epsilon, thick 1+epsilon) alpha) \
141141 &= max(q/q', quad clip(q/q', thick 1-epsilon, thick 1+epsilon)) alpha why(alpha < 0) \
142142 $
+3-3
rapport/sdk2-study.typ
···177177Le fonctionnement d'un bridge est au final assez similaire, quelque soit le simulateur pour lequel on l'écrit: il s'agit d'envoyer l'état du robot au simulateur, et de réagir quand le simulateur envoie des ordres de commandes.
178178179179#figure(caption: "Fonctionnement usuel du SDK", diagram({
180180- node((0, 0), $cal(P)$)
180180+ node((0, 0), $Pi$)
181181 node((1, 0), "SDK")
182182 node((2, 0), "Robot")
183183···195195196196197197#figure(caption: [Fonctionnement via _unitree\_mujoco_ du SDK], diagram({
198198- node((0, 0), $cal(P)$)
198198+ node((0, 0), $Pi$)
199199 node((1, 0), "SDK")
200200 node((2, 0))[`unitree_mujoco`]
201201 node((3, 0), "Mujoco")
···218218219219220220#figure(caption: [Fonctionnement via _gz-unitree_ du SDK], diagram({
221221- node((0, 0), $cal(P)$)
221221+ node((0, 0), $Pi$)
222222 node((1, 0), "SDK")
223223 node((2, 0))[`gz-unitree`]
224224 node((3, 0), text(fill: blue)[Gazebo])