Deep Reinforcement Learning: Wie man Spinnen das Laufen beibringt


Heute werde ich Ihnen erzählen, wie ich Verstärkungs-Deep-Learning-Algorithmen zur Steuerung eines Roboters angewendet habe. Kurz gesagt, ich erkläre Ihnen, wie Sie eine "Black Box mit neuronalen Netzen" erstellen, die die Roboterarchitektur am Eingang akzeptiert und einen Algorithmus ausgibt, der sie am Ausgang steuern kann.


Der Kern der Lösung ist der Advantage Actor Critic (A2C) -Algorithmus mit Advantage- Scores durch die Generalized Advantage Estimation (GAE).


Im Endeffekt Mathematik, eine TensorFlow-Implementierung und viele Demos, auf welche Art von Laufalgorithmen es ankam.


Inhalt:


- Herausforderung
- Warum Reinforcement Learning?
- Erklärung des Verstärkungslernens
- politisches Gefälle
- Diagonale Gaußsche Politik
- Reduzieren Sie die Varianz durch Hinzufügen von Kritik
- Fallstricke

- Fazit


Herausforderung


In diesem Artikel bringen wir dem Roboter das Gehen in der MuJoCo-Simulation bei. Wir überspringen die Beschreibung des Schritts mit der Erstellung eines Modells des Roboters und der Python-Schnittstelle zur Umgebung, weil da ist nichts interessantes. Um dies zu verstehen, schauen Sie sich einfach die Demos in MuJoCo selbst und die Quellen der MuJoCo-Umgebungen in Gym OpenAI an .


Am Eingang hat der Agent viele Zahlen von MuJoCo: relative Positionen, Drehwinkel, Geschwindigkeit, Beschleunigung von Körperteilen des Roboters usw. Insgesamt liegt die Größenordnung bei ~ 800 Features. Wir verwenden den Deep Learning-Ansatz und werden nicht verstehen, was sie tatsächlich bedeuten. Die Hauptsache ist, dass in diesem Satz von Zahlen genügend Informationen vorhanden sind, damit der Agent verstehen kann, was mit ihm geschieht.


Am Ausgang erwarten wir 18 Zahlen - die Anzahl der Freiheitsgrade des Roboters, dh die Drehwinkel der Scharniere, an denen die Gliedmaßen befestigt sind.


Schließlich ist es das Ziel des Agenten, die Gesamtbelohnung für die Episode zu maximieren. Wir beenden die Episode, wenn der Roboter abstürzt oder wenn 3000 Schritte vergangen sind (15 Sekunden). Bei jedem Schritt wird der Agent gemäß der folgenden Formel belohnt:

\ newcommand {\ E} {\ mathop {\ mathbb {E}} \ newcommand {\ R} {\ mathop {\ mathbb {R}}} r_t = \ Delta x * 1000 + 0,5

\ newcommand {\ E} {\ mathop {\ mathbb {E}} \ newcommand {\ R} {\ mathop {\ mathbb {R}}} r_t = \ Delta x * 1000 + 0,5

Das heißt Das Ziel des Agenten erhöht seine Koordinate x und nicht bis zum Ende der Episode fallen.


Die Aufgabe ist also gestellt: die Funktion zu finden  pi: R800 bis R18 wofür die Belohnung für die Folge die größte sein wird . Das klingt nicht sehr richtig? :) Mal sehen, wie Deep Reinforcement Learning diese Aufgabe übernimmt .


Warum Reinforcement Learning?


Moderne Ansätze zur Lösung des Bewegungsproblems von Laufrobotern bestehen aus klassischen Roboterpraktiken aus den Abschnitten optimale Steuerung und Bahnoptimierung: LQR, QP, konvexe Optimierung. Lesen Sie mehr: Boston Dynamics-Teambeitrag auf Atlas .


Diese Techniken stellen eine Art „Hardcoding“ dar, da viele Details der Aufgabe direkt in den Steuerungsalgorithmus eingegeben werden müssen. Sie enthalten keine Lernsysteme - die Optimierung erfolgt „vor Ort“.


Andererseits erfordert Reinforcement Learning (im Folgenden RL) keine Hypothesen im Algorithmus, wodurch die Lösung des Problems allgemeiner und skalierbarer wird.


Erklärung des Verstärkungslernens



Quelle


In dem RL-Problem betrachten wir die Interaktion des Agenten und der Umgebung als eine Folge von Paaren (Zustand, Belohnung) und die Übergänge zwischen ihnen - Aktion .

(s0) xrightarrowa0(s1,r1) xrightarrowa1... xrightarrowan1(sn,rn)

Definieren Sie die Terminologie:


  •  pi(at|st) - Politik , Verhaltensstrategie des Agenten, bedingte Wahrscheinlichkeit,
  • at sim pi( cdot|st) - Aktion wird als Zufallsvariable aus der Verteilung betrachtet  pi ,
    Wir könnten Politik als eine Funktion betrachten  pi:States toActions , aber wir wollen Agentenaktionen stochastisch machen, was die Erkundung erleichtert. Das heißt Mit einiger Wahrscheinlichkeit tun wir nicht ganz die Aktionen, die der Agent auswählt.
  •  tau - Vom Agenten verfolgte Flugbahn, Sequenz (s1,s2,...,sn) .

Der Agent hat die Aufgabe, die erwartete Rendite zu maximieren:

J( pi)= E tau sim pi[R( tau)]= E tau sim pi left[ sumnt=0rt right]

Nun können wir das RL-Problem formulieren und finden:

 pi=arg mathopmax piJ( pi)

wo  pi Ist die optimale Politik.


Lesen Sie mehr im Material von OpenAI: OpenAI Spinning Up .


Gradient der Politik


Es ist bemerkenswert, dass eine rigorose Darstellung des RL-Problems als Optimierungsproblem uns die Möglichkeit gibt, die bereits bekannten Optimierungsmethoden, beispielsweise Gradientenabstieg, anzuwenden. Stellen Sie sich vor, wie cool es wäre, wenn wir den erwarteten Renditegradienten nach Modellparametern berechnen könnten:  nabla thetaJ( pi theta) . In diesem Fall wäre die Regel zur Aktualisierung der Waage einfach:

 theta= thetaold+ alpha nabla thetaJ( pi theta)

Dies ist genau die Idee aller Methoden mit politischem Gefälle . Der strikte Abschluss dieses Gefälles ist etwas hardcore. Wir werden es hier nicht schreiben, sondern einen Link zu dem wunderbaren Material von OpenAI hinterlassen. Der Farbverlauf sieht folgendermaßen aus:

 nabla thetaJ( pi theta)= E tau sim pi theta left[ sumTt=0 nabla theta log pi theta(at|st)R( tau) right]

Der Verlust unseres Modells wird also so aussehen:

loss= log( pi theta(at|st))R( tau)

Daran erinnern R( tau)= sumTt=0rt und  pi theta(at|st) - Dies ist die Ausgabe unseres Modells zu dem Zeitpunkt, als sie in war st . Das Minus erschien aufgrund der Tatsache, dass wir maximieren wollen J . Während des Trainings werden wir den Gradienten von Chargen berücksichtigen und diese addieren, um die Varianz (Datenrauschen aufgrund einer stochastischen Umgebung) zu verringern.


Dies ist ein Arbeitsalgorithmus namens REINFORCE . Und er weiß, wie man Lösungen für einfache Umgebungen findet. Zum Beispiel "CartPole-v1" .


Betrachten Sie den Agent-Code:


class ActorNetworkDiscrete: def __init__(self): self.state_ph = tf.placeholder(tf.float32, shape=[None, observation_space]) l1 = tf.layers.dense(self.state_ph, units=20, activation=tf.nn.relu) output_linear = tf.layers.dense(l1, units=action_space) output = tf.nn.softmax(output_linear) self.action_op = tf.squeeze(tf.multinomial(logits=output_linear,num_samples=1), axis=1) # Training output_log = tf.nn.log_softmax(output_linear) self.weight_ph = tf.placeholder(shape=[None], dtype=tf.float32) self.action_ph = tf.placeholder(shape=[None], dtype=tf.int32) action_one_hot = tf.one_hot(self.action_ph, action_space) responsible_output_log = tf.reduce_sum(output_log * action_one_hot, axis=1) self.loss = -tf.reduce_mean(responsible_output_log * self.weight_ph) optimizer = tf.train.AdamOptimizer(learning_rate=actor_learning_rate) self.update_op = optimizer.minimize(self.loss) actor = ActorNetworkDiscrete() 

Wir haben ein kleines Perceptron dieser Architektur: (observation_space, 10, action_space) [für CartPole ist dies (4, 10, 2)]. Mit tf.multinomial können Sie eine zufällig gewichtete Aktion auswählen. Um eine Aktion zu erhalten, müssen Sie Folgendes aufrufen:


 action = sess.run(actor.action_op, feed_dict={actor.state_ph: observation}) 

Und so werden wir ihn trainieren:


 batch_generator = generate_batch(environments, batch_size=batch_size) for epoch in tqdm_notebook(range(epochs_number)): batch = next(batch_generator) # Remainder: batch item consists of [state, action, total reward] # Train actor _, actor_loss = sess.run([actor.update_op, actor.loss], feed_dict={actor.state_ph: batch[:, 0], actor.action_ph: batch[:, 1], actor.weight_ph: batch[:, 2]}) 

Der Stapelgenerator führt den Agenten in der Umgebung aus und sammelt Daten für das Training. Elemente der Charge sind Tupel dieser Art: (st,at,R( tau)) .


Das Schreiben eines guten Generators ist eine separate Aufgabe, bei der die Hauptschwierigkeit die relativ hohen Kosten für den Aufruf von sess.run () im Vergleich zu einem einzelnen Simulationsschritt (sogar MuJoCo) sind. Um die Arbeit zu beschleunigen, können Sie die Tatsache ausnutzen, dass neuronale Netzwerke stapelweise ausgeführt werden und viele parallele Umgebungen verwenden. Selbst wenn Sie sie nacheinander in einem Thread starten, wird die Beschleunigung im Vergleich zu einer einzelnen Umgebung erheblich sein.


Generatorcode mit DummyVecEnv aus OpenAI-Baselines
 # Vectorized environments with gym-like interface from baselines.common.vec_env.subproc_vec_env import SubprocVecEnv from baselines.common.vec_env.dummy_vec_env import DummyVecEnv def make_env(env_id, seed): def _f(): env = gym.make(env_name) env.reset() # Desync environments for i in range(int(200 * seed // environments_count)): env.step(env.action_space.sample()) return env return _f envs = [make_env(env_name, seed) for seed in range(environments_count)] # Can be switched to SubprocVecEnv to parallelize on cores # (for computationally heavy envs) envs = DummyVecEnv(envs) # Source: # https://github.com/openai/spinningup/blob/master/spinup/algos/ppo/core.py def discount_cumsum(x, coef): """ magic from rllab for computing discounted cumulative sums of vectors. input: vector x, [x0, x1, x2] output: [x0 + discount * x1 + discount^2 * x2, x1 + discount * x2, x2] """ return scipy.signal.lfilter([1], [1, float(-coef)], x[::-1], axis=0)[::-1] def generate_batch(envs, batch_size, replay_buffer_size): envs_number = envs.num_envs observations = [[0 for i in range(observation_space)] for i in range(envs_number)] # [state, action, discounted reward-to-go] replay_buffer = np.empty((0,3), np.float32) # [state, action, reward] rollout lists for every environment instance rollouts = [np.empty((0, 3)) for i in range(envs_number)] while True: history = {'reward': [], 'max_action': []} replay_buffer = replay_buffer[batch_size:] # Main sampling cycle while len(replay_buffer) < replay_buffer_size: # Here policy acts in environments. Note that it chooses actions for all # environments in one batch, therefore expensive sess.run is called once. actions = sess.run(actor.action_op, feed_dict={actor.state_ph: observations}) observations_old = observations observations, rewards, dones, _ = envs.step(actions) history['max_action'].append(np.abs(actions).max()) time_point = np.array(list(zip(observations_old, actions, rewards))) for i in range(envs_number): # Regular python-like append rollouts[i] = np.append(rollouts[i], [time_point[i]], axis=0) # Process done==True environments if dones.all(): print('WARNING: envs are in sync!! This makes sampling inefficient!') done_indexes = np.arange(envs_number)[dones] for i in done_indexes: rewards_trajectory = rollouts[i][:, 2].copy() history['reward'].append(rewards_trajectory.sum()) rollouts[i][:, 2] = discount_cumsum(rewards_trajectory, coef=discount_factor) replay_buffer = np.append(replay_buffer, rollouts[i], axis=0) rollouts[i] = np.empty((0, 3)) # Shuffle before yield to become closer to iid np.random.shuffle(replay_buffer) # Truncate replay_buffer to get the most relevant feedback from environment replay_buffer = replay_buffer[:replay_buffer_size] yield replay_buffer[:batch_size], history # Make a test yield a = generate_batch(envs, 8, 64) # Makes them of equal lenght for i in range(10): next(a) next(a)[0] 

Der resultierende Agent kann in Umgebungen mit einem begrenzten Aktionsraum spielen . Dieses Format ist für unsere Aufgabe nicht geeignet. Der Agent, der den Roboter steuert, muss einen Vektor ausgeben  Rn wo n - die Anzahl der Freiheitsgrade. ( oder Sie können den Aktionsbereich in Lücken aufteilen und eine Aufgabe mit einer diskreten Ausgabe erhalten )


Diagonale Gaußsche Politik


Die Essenz des Ansatzes der diagonalen Gaußschen Politik besteht darin, dass das Modell Parameter der n-dimensionalen Normalverteilung erzeugt, nämlich  mu theta - mat. Warten und  sigma theta - Standardabweichung. Sobald der Agent eine Aktion ausführen muss, werden diese Parameter vom Modell abgefragt und eine Zufallsvariable aus dieser Verteilung entnommen. Also haben wir den Agenten verlassen  Rn und machte es stochastisch. Das Wichtigste ist, dass wir berechnen können, wenn wir die Verteilungsklasse am Ausgang festgelegt haben  log( pi theta(at|st)) und daher politische Gefälle.


Hinweis: Kann repariert werden  sigma theta als Hyperparameter, wodurch die Ausgabeabmessung verringert wird. Die Praxis zeigt, dass dies nicht viel schadet, sondern im Gegenteil das Lernen stabilisiert.


Lesen Sie mehr über die stochastische Politik .


Agent Code:


 epsilon = 1e-8 def gaussian_loglikelihood(x, mu, log_std): pre_sum = -0.5 * (((x - mu) / (tf.exp(log_std) + epsilon))**2 + 2 * log_std + np.log(2 * np.pi)) return tf.reduce_sum(pre_sum, axis=1) class ActorNetworkContinuous: def __init__(self): self.state_ph = tf.placeholder(tf.float32, shape=[None, observation_space]) l1 = tf.layers.dense(self.state_ph, units=100, activation=tf.nn.tanh) l2 = tf.layers.dense(l1, units=50, activation=tf.nn.tanh) l3 = tf.layers.dense(l2, units=25, activation=tf.nn.tanh) mu = tf.layers.dense(l3, units=action_space) log_std = tf.get_variable(name='log_std', initializer=-0.5 * np.ones(action_space, std = tf.exp(log_std) self.action_op = mu + tf.random.normal(shape=tf.shape(mu)) * std # Training self.weight_ph = tf.placeholder(shape=[None], dtype=tf.float32) self.action_ph = tf.placeholder(shape=[None, action_space], dtype=tf.float32) action_logprob = gaussian_loglikelihood(self.action_ph, mu, log_std) self.loss = -tf.reduce_mean(action_logprob * self.weight_ph) optimizer = tf.train.AdamOptimizer(learning_rate=actor_learning_rate) self.update_op = optimizer.minimize(self.loss) 

Der Trainingsteil ist nicht anders.


Jetzt können wir endlich sehen, wie REINFORCE unsere Aufgabe bewältigen wird. Das Ziel des Agenten ist es, sich nach rechts zu bewegen.



Langsam aber sicher schleichend auf sein Ziel zu.


Belohnung für unterwegs


Beachten Sie, dass unser Farbverlauf zusätzliche Elemente enthält. Nämlich für jeden Schritt t Wenn wir den Gradienten des Logarithmus abwägen, verwenden wir die Gesamtbelohnung für die gesamte Flugbahn . Bewertung der Handlungen des Agenten anhand seiner Leistungen aus der Vergangenheit. Hört sich falsch an, nicht wahr? Deshalb das

 nabla thetaJ( pi theta)= E tau sim pi theta left[ sumTt=0 nabla theta log pi theta(at|st) sumTt=0rt right]

wird dies werden

 nabla thetaJ( pi theta)= E tau sim pi theta left[ sumTt=0 nabla theta log pi theta(at|st) sumTt=trt right]

Finde 10 Unterschiede :)


Während die Anwesenheit dieser Mitglieder nichts mathematisch verderbt, macht es viel Lärm für uns. Während des Trainings achtet der Agent nur auf die Belohnungen, die er nach einer bestimmten Aktion erhalten hat .


Aufgrund dieser Verbesserung ist die durchschnittliche Belohnung gestiegen. Einer der erhaltenen Agenten lernte, die Vorderbeine zu verwenden, um sein Ziel zu erreichen:



Reduzieren Sie die Varianz durch Hinzufügen von Kritik


Das Wesentliche weiterer Verbesserungen ist die Reduzierung des Rauschens (Varianz), das durch die stochastischen Übergänge zwischen den Zuständen des Mediums entsteht.


Auf diese Weise können wir ein Modell hinzufügen , das die durchschnittliche Anzahl der vom Agenten erhaltenen Belohnungen ausgehend vom Status vorhersagt s bis zum Ende der Flugbahn, d.h. Wertfunktion.

V pi(s)= E tau sim pi left[R( tau)|s0=s right] textWertefunktion

Q pi(s,a)= E tau sim pi left[R( tau)|s0=s,a0=a right] textAktionswertfunktion

A pi(s,a)=Q pi(s,a)V pi(s) textVorteilsfunktion

Die Wertfunktion zeigt die erwartete Rendite an, wenn unsere Richtlinie das Spiel ab einem bestimmten Status startet. Das Gleiche gilt für die Q-Funktion. Beheben Sie einfach die allererste Aktion.


Kritik hinzufügen


So sieht der Farbverlauf bei Verwendung von Prämie für unterwegs aus:

 nabla theta log pi theta(at|st) sumTt=trt

Nun ist der Koeffizient für den Gradienten des Logarithmus nichts weiter als ein Beispiel für die Wertefunktion.

 sumTt=trt simV pi(st)

Wir wägen den Logarithmusgradienten mit einer Stichprobe aus einer bestimmten Flugbahn ab, was nicht gut ist. Wir können die Wertefunktion mit einem Modell, zum Beispiel einem neuronalen Netzwerk, approximieren und den erforderlichen Wert von diesem abfragen, wodurch die Varianz verringert wird. Wir werden dieses Modell als Kritiker bezeichnen und es parallel zur Politik untersuchen. Somit kann die Gradientenformel wie folgt geschrieben werden:

 nabla theta log pi theta(at|st) sumTt=trt ungefähr nabla theta log pi theta(at|st)V pi( tau)

Wir haben die Varianz reduziert, aber gleichzeitig eine Verzerrung in unseren Algorithmus eingeführt, da neuronale Netze Approximationsfehler verursachen können. Aber der Kompromiss in dieser Situation ist gut. Solche Situationen beim maschinellen Lernen werden als Bias-Varianz-Kompromiss bezeichnet .


Der Kritiker wird die Wert-Funktions-Regression für in der Umgebung gesammelte Belohnungsproben lehren. Als Fehlerfunktion nehmen wir MSE. Das heißt Verlust sieht so aus:

loss=(V pi psi(st) sumTt=trt)2

Kritischer Code:


 class CriticNetwork: def __init__(self): self.state_ph = tf.placeholder(tf.float32, shape=[None, observation_space]) l1 = tf.layers.dense(self.state_ph, units=100, activation=tf.nn.tanh) l2 = tf.layers.dense(l1, units=50, activation=tf.nn.tanh) l3 = tf.layers.dense(l2, units=25, activation=tf.nn.tanh) output = tf.layers.dense(l3, units=1) self.value_op = tf.squeeze(output, axis=-1) # Training self.value_ph = tf.placeholder(shape=[None], dtype=tf.float32) self.loss = tf.losses.mean_squared_error(self.value_ph, self.value_op) optimizer = tf.train.AdamOptimizer(learning_rate=critic_learning_rate) self.update_op = optimizer.minimize(self.loss) 

Der Trainingszyklus sieht jetzt so aus:


 batch_generator = generate_batch(envs, batch_size=batch_size) for epoch in tqdm_notebook(range(epochs_number)): batch = next(batch_generator) # Remainder: batch item consists of [state, action, value, reward-to-go] # Train actor _, actor_loss = sess.run([actor.update_op, actor.loss], feed_dict={actor.state_ph: batch[:, 0], actor.action_ph: batch[:, 1], actor.weight_ph: batch[:, 2]}) # Train critic for j in range(10): _, critic_loss = sess.run([critic.update_op, critic.loss], feed_dict={critic.state_ph: batch[:, 0], critic.value_ph: batch[:, 3]}) 

Jetzt enthält die Charge einen anderen Wert, den der Kritiker im Generator berechnet hat.
Das heißt Die Art der Charge ist: (st,at,V pi psi(st), sumTt=trt) .


In diesem Zyklus beschränkt uns nichts darauf, den Kritiker auf Konvergenz zu trainieren. Wir führen daher mehrere Schritte des Gradientenabfalls durch, wodurch die Approximation der Wertefunktion verbessert und die Verzerrung verringert wird. Dieser Ansatz erfordert jedoch eine große Chargengröße, um eine Umschulung zu vermeiden. Eine ähnliche Aussage zur Lernpolitik trifft nicht zu. Es sollte sofortiges Feedback von der Lernumgebung erhalten, da wir uns sonst möglicherweise in einer Situation befinden, in der wir die Richtlinien für Maßnahmen festlegen, die noch nicht durchgeführt wurden. Algorithmen mit dieser Eigenschaft werden als On-Policy bezeichnet .


Baselines in Politikverläufen


Es kann gezeigt werden, dass es im Verlauf zulässig ist, eine breite Klasse anderer nützlicher Funktionen abzulegen t . Solche Funktionen werden als Baselines bezeichnet . ( Schlussfolgerung aus dieser Tatsache ) Die folgenden Funktionen eignen sich gut als Baselines:



Quelle: GAE-Papier .


Unterschiedliche Baselines ergeben je nach Aufgabe unterschiedliche Ergebnisse. Der größte Gewinn wird in der Regel durch die Advantage-Funktion und ihre Näherungen erzielt.


Dahinter steckt sogar eine kleine Intuition. Wenn wir Advantage verwenden, wird der Agent mit einer Geldstrafe belegt, je nachdem, wie viel besser oder schlechter der Durchschnitt ist, den der Agent für die von ihm durchgeführte Aktion hält. Und je besser der Agent in der Umwelt spielt, desto höher werden seine Standards . Der ideale Agent spielt gut und bewertet alle seine Aktionen mit einem Vorteil von 0 und hat daher einen Gradienten von 0.


Vorteilsbewertung durch Wertfunktion


Erinnern Sie sich an die Definition von Vorteil:

A pi(s,a)=Q pi(s,a)V pi(s) textVorteilsfunktion

Es ist nicht klar, wie man eine solche Funktion explizit lernt. Ein Trick wird zur Rettung kommen, der die Berechnung der Advantage-Funktion auf die Berechnung der Value-Funktion reduziert.


Definieren  deltaVt=rt+V(st+1)V(st) - Residuum der zeitlichen Differenz ( TD-Residuum ). Es ist nicht schwer zu folgern, dass sich eine solche Funktion dem Vorteil annähert:

 E left[ deltaVt right]= E left[rt+V(st+1)V(st) right]= E left[Q(st,at)V(st) right]=A(st,at)

Solch eine konzeptionell komplexe Änderung führt zu einer nicht so großen Änderung des Codes. Anstatt nun die Wertfunktion zu bewerten, legt der Kritiker eine Vorteilsbewertung für die Richtlinienschulung vor.


Der resultierende Algorithmus heißt Advantage Actor-Critic .


 def estimate_advantage(states, rewards): values = sess.run(critic.value_op, feed_dict={critic.state_ph: states}) deltas = rewards - values deltas = deltas + np.append(values[1:], np.array([0])) return deltas, values 

Die erhaltenen Wirkstoffe lassen sich bei sicherem Gang und synchronem Einsatz der Gliedmaßen beobachten:



Verallgemeinerte Vorteilsschätzung


Ein relativ neuer Artikel (2018), " Hochdimensionale kontinuierliche Steuerung unter Verwendung einer verallgemeinerten Vorteilsschätzung ", bietet eine noch effizientere Bewertung des Vorteils durch die Wertfunktion . Es reduziert die Varianz noch mehr:

AGAE( gamma, lambda)t= sum l=0infty( gamma lambda)l deltaVt+l

wo:


  •  deltaVt=rt+V(st+1)V(st) - TD-Rest,
  •  gamma - Abzinsungsfaktor (Hyperparameter),
  •  lambda - Hyperparameter.

Die Interpretation ist in der Publikation selbst zu finden.


Implementierung:


 def discount_cumsum(x, coef): # Source: # https://github.com/openai/spinningup/blob/master/spinup/algos/ppo/core.py """ magic from rllab for computing discounted cumulative sums of vectors. input: vector x, [x0, x1, x2] output: [x0 + discount * x1 + discount^2 * x2, x1 + discount * x2, x2] """ return scipy.signal.lfilter([1], [1, float(-coef)], x[::-1], axis=0)[::-1] def estimate_advantage(states, rewards): values = sess.run(critic.value_op, feed_dict={critic.state_ph: states}) deltas = rewards - values deltas = deltas + discount_factor * np.append(values[1:], np.array([0])) advantage = discount_cumsum(deltas, coef=lambda_factor * discount_factor) return advantage, values 

Bei Verwendung einer kleinen Stapelgröße hat sich der Algorithmus einigen lokalen Optima angenähert. Hier benutzt der Agent eine Pfote als Spazierstock und der Rest drückt ab:



Dabei kam der Agent nicht zum Einsatz von Sprüngen, sondern fingerte einfach schnell mit Gliedmaßen. Und Sie können auch sehen, wie er sich verhält, wenn er zögert, dreht er sich um und rennt weiter:



Als bester Agent steht er ganz am Anfang des Artikels. Stabiles Springen, bei dem sich alle Gliedmaßen von der Oberfläche lösen. Die entwickelte Fähigkeit zum Auswuchten ermöglicht es dem Agenten, die Flugbahn mit voller Geschwindigkeit zu korrigieren, wenn ein Fehler gemacht wurde:



Fallstricke


Maschinelles Lernen ist berühmt für die Dimension des Fehlerraums, der gemacht werden kann und einen völlig nicht funktionierenden Algorithmus liefert. Aber RL bringt das Problem auf eine ganz neue Ebene.



Quelle


Hier sind einige der Schwierigkeiten aufgeführt, die während der Entwicklung aufgetreten sind.


  1. Der Algorithmus reagiert überraschend empfindlich auf Hyperparameter. Die Qualität des Lernens änderte sich, als die Lernrate von 3e-4 auf 1e-4 geändert wurde. Und das Bild hat sich grundlegend geändert - von einem völlig nicht konvergenten Algorithmus zu dem Besten, das im Video enthalten ist.
  2. Die Größe der Charge ist keineswegs dieselbe wie in anderen Bereichen von DL. Wenn Sie es sich bei der Bildklassifizierung leisten können, die Größe des 32-256-Stapels zu wählen, und das Ergebnis sich durch die Erhöhung nicht besonders ändert, ist es besser, für unsere Aufgabe ein paar Tausend, 3000 Arbeiten in Anspruch zu nehmen.
  3. Lernen ist besser, mehrmals zu laufen, manchmal mit zufälligen Samen ist kein Glück.
  4. Das Lernen in einem so komplexen Umfeld nimmt viel Zeit in Anspruch und der Fortschritt ist nicht einheitlich. Beispielsweise hat der beste Algorithmus 8 Stunden lang gelernt, von denen 3 ein schlechteres Ergebnis zeigten als eine zufällige Basislinie. Daher ist es beim Testen der Algorithmen besser, mit einem kleinen zu beginnen, wie in Spielzeugumgebungen aus dem Fitnessstudio.
  5. Ein guter Ansatz zum Auffinden von Hyperparametern und Modellarchitekturen besteht darin, sich verwandte Artikel und Implementierungen anzusehen. (Hauptsache nicht umbilden)

In diesem Artikel erfahren Sie mehr über die Nuancen von Deep RL: Deep Reinforcement Learning funktioniert noch nicht .


Fazit


Der resultierende Algorithmus löst das Problem überzeugend. Funktion gefunden  pi: R800 bis R18 , agil und sicher den Roboter steuern.


Eine logische Fortsetzung wird die Untersuchung enger Verwandter von A2C-, PPO- und TRPO-Algorithmen sein. Sie verbessern die Probeneffizienz , d.h. Konvergenzzeit des Algorithmus, und sie sind in der Lage, komplexere Probleme zu lösen. Es war PPO + Automatic Domain Randomization, das kürzlich den Rubik's Cube auf einem Roboter zusammengebaut hat .


Hier finden Sie den Code aus dem Artikel: Repository .


Ich hoffe, Ihnen hat der Artikel gefallen und Sie waren inspiriert von dem, was Deep Reinforcement Learning heute leisten kann.


Vielen Dank für Ihre Aufmerksamkeit!


Nützliche Links:



Vielen Dank an Pinkotter , Vambala , Andrey_Probochkin , Pollyfom und Suriknik für die Unterstützung bei dem Projekt.
Insbesondere Vambala und andrey_probochkin für die Schaffung einer coolen MuJoCo-Umgebung.

Source: https://habr.com/ru/post/de483078/


All Articles