Was ist also A3C? Die A3C-Berechnung wurde kürzlich von Googles DeepMind-Bündel entladen, und es machte einen Spritzer durch… im Grunde genommen veraltetes DQN. Sie war schneller, einfacher, zunehmend energischer und bereit, mit der Standardbatterie der Profound RL-Unternehmen viel bessere Ergebnisse zu erzielen. Insgesamt konnte es in konsistenten, ebenso diskreten Aktivitätsräumen arbeiten. Angesichts dessen wurde es zum Sprung in die Deep RL-Berechnung für neue Testprobleme mit komplexen Zustands- und Aktivitätsräumen. Um der Wahrheit die Ehre zu geben, hat OpenAI gerade eine Version von A3C als ihren “allgemeinen Starter-Spezialisten” für die Arbeit mit ihrer neuen (und extrem unterschiedlichen) Gruppe von Universumssituationen entlassen.

Die 3 ab A3C

Einmalig ein bisschen Spielraum Entertainer Pundit ist ein ernstzunehmendes Stück. Wie wäre es, wenn wir damit beginnen, den Namen zu entladen, und von da an die Mechanik der Berechnung selbst entladen.

Nicht übereinstimmend: Ganz und gar nicht wie DQN, wo ein einsamer Operator, der von einem einsamen neuronalen System angesprochen wird, mit einer einsamen Situation zusammenarbeitet, verwendet A3C verschiedene Manifestationen des oben Gesagten, um sich umso produktiver anzupassen. Bei A3C gibt es ein weltweites System und verschiedene spezialisierte Operatoren, die jeweils ihre eigene Anordnung von Systemparametern haben. Jeder dieser Operatoren verbindet sich gleichzeitig mit seinem eigenen Duplikat der Erde, während verschiedene Spezialisten mit ihrer Umgebung kommunizieren. Die Erklärung dafür, dass dies besser funktioniert als ein einziger Spezialist (über die Beschleunigung der Ausführung von mehr Arbeit hinaus), ist, dass die Erfahrung jedes Operators frei von der Erfahrung der anderen ist. In diesem Sinne stellt sich heraus, dass die allgemeine Erfahrung, die für die Vorbereitung zugänglich ist, nach und nach sortiert wird.

Unterhalter Pandit: Bisher konzentrierte sich dieses Arrangement auf Wertschätzungsstrategien, z.B. Q-Learning, oder auf Techniken des Annäherungszyklus, z.B. Strategy Slope. Der Bildschirm-Charakter Pundit konsolidiert die Vorteile der beiden Methoden. Aufgrund von A3C bewertet unser System sowohl eine Wertkapazität V(s) (wie groß ein bestimmter Zustand sein soll) als auch eine Strategie π(s) (viele Aktivitätswahrscheinlichkeiten ergeben sich). Dabei handelt es sich jeweils um unabhängige, vollständig miteinander verbundene Schichten, die sich am höchsten Punkt des Systems befinden. Im Grunde nutzt der Betreiber den Wertmaßstab (der Pandit), um die Strategie (der Unterhalter) geschickter zu aktualisieren als herkömmliche Anordnungsneigungsstrategien.

Implementierung des Algorithmus

Während der Zeit, die für die Strukturierung dieser Verwendung der A3C-Berechnung aufgewendet wurde, habe ich als Referenz die Qualitätsausführungen von DennyBritz und OpenAI verwendet. Die beiden schreibe ich gründlich vor, für den Fall, dass Sie Optionen im Gegensatz zu meinem Code hier sehen möchten. Jedes hier eingefügte Segment wird außerhalb jeder relevanten Verbindung zu dem vorliegenden Thema zu Unterrichtszwecken genommen und läuft nicht allein. Um die vollständige, nützliche A3C-Ausführung anzusehen und auszuführen, sehen Sie sich meinen Github-Tresor an.

Das allgemeine Diagramm des Code Engineering ist:

AC_Netzwerk – Diese Klasse enthält alle Tensorflow-Operationen zur Herstellung der Systeme selbst.

Specialist – Diese Klasse enthält ein Duplikat von AC_Network, eine Domain-Klasse, ebenso wie alle Gründe für die Zusammenarbeit mit der Natur und die Auffrischung des weltweiten Systems.

Code auf erhöhter Ebene für den Aufbau und Parallelbetrieb der Specialist-Vorkommen.

Die A3C-Berechnung beginnt mit der Entwicklung des weltweiten Systems. Dieses System wird aus Faltungsschichten bestehen, um räumliche Bedingungen zu verarbeiten, gefolgt von einer LSTM-Schicht, um flüchtige Bedingungen zu verarbeiten, und schließlich aus Schichten für die Wert- und Strategieausbeute. Nachfolgend ist der Modellcode für den Aufbau der Systemkarte selbst aufgeführt.

Klasse AC_Netzwerk():

    def __init__(self,s_size,a_size,scope,trainer):

        mit tf.variable_scope(Geltungsbereich):

            #Eingabe- und visuelle Kodierungsebenen

            self.inputs = tf.platzhalter(shape=[Keine,s_size],dtype=tf.float32)

            self.imageIn = tf.reshape(self.inputs,shape=[-1,84,84,1])

            self.conv1 = schlank.conv2d(aktivierung_fn=tf.nn.elu,

                eingänge=selbst.imageIn,num_ausgänge=16,

                kernel_size=[8,8],stride=[4,4],padding=’VALID’)

            self.conv2 = schlank.conv2d(aktivierung_fn=tf.nn.elu,

                eingaben=selbst.conv1,num_ausgänge=32,

                kernel_size=[4,4],stride=[2,2],padding=’VALID’)

            versteckt = slim.fully_connected(slim.flatten(self.conv2),256,activation_fn=tf.nn.elu)

            #Wiederkehrendes Netzwerk für zeitliche Abhängigkeiten

            lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(256,state_is_tuple=True)

            c_init = np.Nullen((1, lstm_cell.state_size.c), np.float32)

            h_init = np.Nullen((1, lstm_cell.state_size.h), np.float32)

            self.state_init = [c_init, h_init]

            c_in = tf.Platzhalter(tf.float32, [1, lstm_cell.state_size.c])

            h_in = tf.Platzhalter(tf.float32, [1, lstm_cell.state_size.h])

            self.state_in = (c_in, h_in)

            rnn_in = tf.expand_dims(versteckt, [0])

            Schritt_Größe = tf.form(selbst.imageIn)[:1]

            Zustand_in = tf.nn.rnn_Zelle.LSTMStateTupel(c_in, h_in)

            lstm_outputs, lstm_state = tf.nn.dynamic_rnn(

                lstm_Zelle, rnn_in, Anfangszustand=Zustand_in, Sequenz_Länge=Schritt_Größe,

                time_major=Falsch)

            lstm_c, lstm_h = lstm_Zustand

            self.state_out = (lstm_c[:1, :], lstm_h[:1, :])

            rnn_out = tf.remhape(lstm_outputs, [-1, 256])

            #Output-Schichten für Richtlinien- und Wertschätzungen

            self.policy = slim.fully_connected(rnn_out,a_size,

                Aktivierung_fn=tf.nn.softmax,

                weights_initializer=normalisierte_Spalten_initializer(0.01),

                biases_initializer=Keine)

            self.value = slim.fully_connected(rnn_out,1,

                aktivierung_fn=keine,

                weights_initializer=normalisierte_Spalten_initializer(1.0),

                biases_initializer=Keine)

Als nächstes werden viele Arbeiteroperatoren, jeder mit seinem eigenen System und Zustand, hergestellt. Jeder dieser Operatoren wird auf einem anderen Prozessor-String ausgeführt, so dass es nicht mehr Operatoren geben sollte, als Strings auf Ihrer CPU vorhanden sind.

mit tf.device(“/cpu:0”):

    master_network = AC_Network(s_size,a_size,’global’,None) # Globales Netzwerk erzeugen

    num_workers = multiprocessing.cpu_count() # Arbeiter auf die Anzahl der verfügbaren CPU-Threads setzen

    Arbeitnehmer = []

    # Arbeiterklassen erstellen

    für i im Bereich(num_workers):

        workers.append(Worker(DoomGame(),i,s_size,a_size,trainer,saver,model_path))

mit tf.Session() als sess:

    coord = tf.train.coordinator()

    wenn load_model == Wahr:

        drucken Sie ‘Modell laden…’.

        ckpt = tf.train.get_checkpoint_state(model_path)

        saver.restore(sess,ckpt.model_checkpoint_path)

    sonst:

        sess.run(tf.global_variables_initializer())

    # Hier geschieht die asynchrone Magie.

    # Starten Sie den “Arbeits”-Prozess für jeden Arbeiter in einer separaten Bedrohung.

    Arbeiter_Gewinde = []

    für Arbeiter in Arbeiter:

        arbeiter_arbeit = lambda: arbeiter.arbeit(max_episode_länge,gamma,master_netzwerk,sess,koord)

        t = Gewindeschneiden.thread(target=(worker_work))

        t.start()

        worker_threads.append(t)

    coord.join(Arbeiter_Fäden)

Jeder Arbeiter beginnt damit, seine Systemparameter auf die des weltweiten Systems einzustellen. Wir können dies tun, indem wir eine Tensorflow-Operation entwickeln, die jeden Faktor im Nachbarschafts-Spezialistensystem auf den gleichen variablen Anreiz im weltweiten System einstellt.

Jeder Spezialist assoziiert zu diesem Zeitpunkt mit seinem ganz eigenen Duplikat der Natur und sammelt Verständnis. Jeder hält einen Überblick über die Erfahrungstupel (Wahrnehmung, Aktivität, Entlohnung, Erledigung, Wertschätzung), der durch die Kommunikation mit der Erde ständig ergänzt wird.

lass Worker():

      ….

      ….

      ….

      def work(self,max_episode_length,gamma,global_AC,sess,coord):

        episode_count = 0

        Gesamt_Schritt_Zahl = 0

        drucken Sie “Berufsanfänger ” + str(self.number)

        mit sess.as_default(), sess.graph.as_default():                

            und nicht coord.should_stop():

                sess.run(self.update_local_ops)

                episode_buffer = []

                episode_values = []

                episode_frames = []

                episode_belohnung = 0

                episode_step_count = 0

                d = Falsch

                selbst.env.neue_episode()

                s = self.env.get_state().screen_buffer

                episode_frames.append(s)

                s = Prozess_Frame(s)

                rnn_Zustand = self.local_AC.state_init

                während self.env.env.is_episode_finished() == Falsch:

                    #Ergreifen Sie eine Maßnahme unter Verwendung von Wahrscheinlichkeiten aus der Ausgabe des Policy-Netzwerks.

                    a_dist,v,rnn_state = sess.run([self.local_AC.policy,self.local_AC.value,self.local_AC.state_out],

                        feed_dict={self.local_AC.inputs:[s],

                        self.local_AC.state_in[0]:rnn_state[0],

                        self.local_AC.state_in[1]:rnn_state[1]})

                    a = np.zufällige.Auswahl(a_dist[0],p=a_dist[0])

                    a = np.argmax(a_dist == a)

                    r = self.env.make_action(self.actions[a]) / 100.0

                    d = self.env.is_episode_beendet()

                    wenn d == Falsch:

                        s1 = self.env.get_state().screen_buffer

                        episode_frames.append(s1)

                        s1 = Prozess_Rahmen(s1)

                    sonst:

                        s1 = s

                    episode_buffer.append([s,a,r,s1,d,v[0,0]])

                    episode_values.append(v[0,0])

                    episode_belohnung += r

                    s = s1 

                    Gesamt_Schritte += 1

                    episoden_schritt_zählung += 1

                    #Spezifisch für VizDoom. Wir schlafen das Spiel für eine bestimmte Zeit.

                    wenn self.sleep_time>0:

                        schlafen(selbst.schlaf_zeit)

                    # Wenn die Episode noch nicht beendet ist, aber der Erfahrungspuffer voll ist, dann

                    # einen Aktualisierungsschritt unter Verwendung dieses Erfahrungsrollouts durchführen.

                    if len(episode_buffer) == 30 und d != Wahr und episode_step_count != max_episode_length – 1:

                        # Da wir nicht wissen, was die wahre endgültige Rückkehr ist, “bootstrappen” wir von unserer aktuellen

                        # Werteinschätzung.

                        v1 = sess.run(self.local_AC.value,

                            feed_dict={self.local_AC.inputs:[s],

                            self.local_AC.state_in[0]:rnn_state[0],

                            self.local_AC.state_in[1]:rnn_state[1]})[0,0]

                        v_l,p_l,e_l,e_l,g_n,v_n = selbst.train(global_AC,episode_buffer,sess,gamma,v1)

                        episode_buffer = []

                        sess.run(self.update_local_ops)

                    wenn d == Wahr:

                        Pause

                self.episode_rewards.append(episode_reward)

                self.episode_lengths.append(episode_step_count)

                self.episode_mean_values.append(np.mean(episode_values))

                # Aktualisieren Sie das Netzwerk unter Verwendung des Erfahrungspuffers am Ende der Episode.

                v_l,p_l,e_l,e_l,g_n,v_n = selbst.train(global_AC,episode_buffer,sess,gamma,0.0)

Wenn die Erfahrungshistorie des Arbeiters enorm genug ist, nutzen wir sie, um über eine begrenzte Rendite und etwas Spielraum zu entscheiden, und nutzen diese, um den Wert zu berechnen und Unglücksfälle anzugehen. Zusätzlich stellen wir eine Entropie (H) des Ansatzes fest. Diese vergleichen wir mit der Streuung der Aktivitätswahrscheinlichkeiten. Für den unwahrscheinlichen Fall, dass die Strategie Aktivitäten mit mäßig vergleichbaren Wahrscheinlichkeiten ergibt, wird die Entropie zu diesem Zeitpunkt hoch sein, für den unwahrscheinlichen Fall jedoch, dass das Arrangement eine einsame Aktivität mit einer enormen Wahrscheinlichkeit empfiehlt, wird die Entropie zu diesem Zeitpunkt niedrig sein. Wir nutzen die Entropie als Methode zur Verbesserung der Untersuchung, indem wir darauf drängen, dass das Modell in Bezug auf die Sicherheit der richtigen Aktivität traditionalistisch ist.

Wertverlust: L = Σ(R – V(s))²

Verlust von Policen: L = -Log(π(s)) * A(s) – β*H(π)

Ein Arbeiter an diesem Punkt nutzt diese Unglücksfälle aus, um Winkel bezüglich seiner Systemparameter zu ermitteln. Jeder dieser Winkel wird in der Regel gekürzt, um übermäßig enorme Parameteraktualisierungen zu antizipieren, die den Ansatz destabilisieren können.

Ein Spezialist an diesem Punkt nutzt die Neigungen, um die weltweiten Systemparameter zu aktualisieren. In diesem Sinne wird das weltweite System ständig von jedem einzelnen Spezialisten aufgefrischt, wenn er mit seinem Zustand zusammenarbeitet.

Klasse AC_Netzwerk():

    def __init__(self,s_size,a_size,scope,trainer):

        ….

        ….

        ….

        wenn Geltungsbereich != ‘global’:

            self.actions = tf.platzhalter(shape=[Keine],dtype=tf.int32)

            self.actions_onehot = tf.one_hot(self.actions,a_size,dtype=tf.float32)

            self.target_v = tf.platzhalter(shape=[Keine],dtype=tf.float32)

            self.advantages = tf.platzhalter(shape=[Keine],dtype=tf.float32)

            self.responsible_outputs = tf.reduce_sum(self.policy * self.actions_onehot, [1])

            #Verlust-Funktionen

            Selbstwert_Verlust = 0,5 * tf.reduce_sum(tf.square(selbst.target_v – tf.remhape(selbst.wert,[-1])))

            self.entropy = – tf.reduce_sum(self.policy * tf.log(self.policy))

            self.policy_loss = -tf.reduce_sum(tf.log(self.responsible_outputs)*self.advantages)

            Selbst.verlust = 0,5 * Selbst.wert_Verlust + Selbst.politik_Verlust – Selbst.entropie * 0,01

            #Erhalten von Gradienten aus dem lokalen Netz unter Verwendung lokaler Verluste

            local_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, Umfang)

            self.gradients = tf.gradients(self.loss,local_vars)

            self.var_norms = tf.global_norm(local_vars)

            grads,self.grad_norms = tf.clip_by_global_norm(self.gradients,40.0)

            #Lokale Gradienten auf globales Netzwerk anwenden

            global_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, ‘global’)

            self.apply_grads = Ausbilder.apply_gradients(zip(grads,global_vars))

Klasse Worker():

      ….

      ….

      ….

      def train(self,global_AC,rollout,sess,gamma,bootstrap_value):

        Ausrollen = np.array(ausrollen)

        Beobachtungen = Einführung[:,0]

        Aktionen = Einführung[:,1]

        Belohnungen = Einführung[:,2]

        next_observations = Einführung[:,3]

        Werte = Rollout[:,5]

        # Hier nehmen wir die Belohnungen und Werte aus der Einführung und verwenden sie, um

        # den Vorteil und die diskontierten Renditen generieren.

        # Die Vorteilsfunktion verwendet die “Verallgemeinerte Vorteilsschätzung”.

        self.rewards_plus = np.asarray(rewards.tolist() + [bootstrap_value])

        diskontierte_Belohnungen = Rabatt(selbst.belohnungen_plus,gamma)[:-1]

        self.value_plus = np.asarray(values.tolist() + [bootstrap_value])

        Vorteile = Belohnungen + Gamma * Eigenwert_plus[1:] – Eigenwert_plus[:-1]

        Vorteile = Rabatt(Vorteile,Gamma)

        # Aktualisieren Sie das globale Netzwerk mit Gradienten aus Verlust

        # Erzeugen Sie Netzwerkstatistiken zum periodischen Speichern

        rnn_Zustand = self.local_AC.state_init

        feed_dict = {self.local_AC.target_v:discounted_rewards,

            self.local_AC.inputs:np.vstack(Beobachtungen),

            self.local_AC.actions:Aktionen,

            self.local_AC.advantages:vorteile:vorteile,

            self.local_AC.state_in[0]:rnn_state[0],

            self.local_AC.state_in[1]:rnn_state[1]}

        v_l,p_l,e_l,e_l,g_n,v_n,_ = sess.run([self.local_AC.value_loss,

            self.local_AC.policy_loss,

            self.local_AC.entropie,

            self.local_AC.grad_norms,

            self.local_AC.var_norms,

            self.local_AC.apply_grads],

            feed_dict=feed_dict)

        zurückgeben v_l / len(ausrollen),p_l / len(ausrollen),e_l / len(ausrollen), g_n,v_n

Wenn eine wirksame Aktualisierung des weltweiten Systems vorgenommen wird, wird das gesamte Verfahren wieder aufpoliert! Der Arbeiter setzt zu diesem Zeitpunkt seine eigenen Systemparameter auf die des weltweiten Systems zurück, und die Prozedur beginnt von neuem.