[PYTHON] Wenn Sie ein Mann sind, halten Sie einfach die Klappe und sagen Sie ihm, er soll mit einem Stock aufstehen

Vor kurzem bin ich süchtig danach, das Lernen zu stärken. Immerhin ist es ein Mann, der beim Lernen der Verstärkung einen Stock aushalten will. Daher werde ich nach dem letzten Mal den CartPole </ font> von OpenAI Gym vorstellen.

Vorheriger Artikel Ich möchte mit verbessertem Lernen einen Berg besteigen

Was ist die SARSA-Lernmethode?

Was das im vorherigen Artikel erwähnte Q-Lernen betrifft, möchte ich diesmal eine Methode namens SARSA verwenden. Lassen Sie uns überprüfen. Aktualisierung des Zustandsverhaltenswerts Q beim Bestärkungslernen,

\begin{aligned}Q\left( s_{t},a_{t}\right) \\ \leftarrow Q\left( s_{t},a_{t}\right) \\ +\alpha \left( G_{t}-Q\left( s_{t},a_{t}\right) \right) \end{aligned}

Wird für jeden Zustandsübergang durchgeführt. Der Unterschied zwischen SARSA- und Q-Lernen besteht darin, wie dieses $ G_ {t} $ bestimmt wird.

Für ** Q-Lernen ** </ font> $G_{t}=r_{t+1}+\gamma\max_{a\in At}[Q(s_{t+1},a)]$

Für ** SARSA ** </ font> $G_{t}=r_{t+1}+\gamma Q(s_{t+1},a_{t+1}^{\pi})$

Hier gibt $ a_ {t + 1} ^ {\ pi} $ die Aktion an, wenn die nächste Aktion gemäß der Richtlinie im Status $ s_ {t + 1} $ ausgewählt wird. Was wir aus dem Obigen sehen können, ist, dass Q-Lernen max verwendet, um den Wert zu aktualisieren, das heißt, es ist eine ** optimistische ** Lernmethode, die unter Verwendung des maximalen Zustandswerts aktualisiert wird, der erhalten werden kann. Im Gegensatz dazu berücksichtigt SARSA die folgenden Aktionen, wodurch es eine ** realistischere ** Methode zur Bestimmung von Strategien darstellt. Dieses Mal werden wir auch diese vergleichen.

CartPole-Regeln

スクリーンショット 2020-09-14 18.07.29.png Wenn Sie diesen Stick lange stehen lassen (200 Schritte), wird er gelöscht. Es sind vier Zustände angegeben: ** die Position des Wagens, die Geschwindigkeit des Wagens, der Winkel der Stange und die Winkelgeschwindigkeit der Stange **. Die Aktionen beschränken sich darauf, den Wagen nach links zu schieben: 0 und nach rechts zu schieben: 1. Der Winkel der Stange ist um 12 Grad oder mehr geneigt, oder die Ausdauer beträgt 200 Schritte.

Implementierung

Importieren Sie zunächst die Bibliothek.

import gym
from gym import logger as gymlogger
gymlogger.set_level(40) #error only
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
import math
import glob
import io
import base64

Definiert eine Klasse SARSA, die das Lernen implementiert.

class SARSA:
    def __init__(self, env):
        self.env = env
        self.env_low = self.env.observation_space.low #Mindestzustand
        self.env_high = self.env.observation_space.high #Maximalwert angeben
        
        tmp = [7,7,7,7] #Teilen Sie den Staat in 7 Staaten
        self.env_dx = [0,0,0,0]
        self.env_dx[0] = (self.env_high[0] - self.env_low[0]) / tmp[0]
        self.env_dx[1] = (self.env_high[1] - self.env_low[1]) / tmp[1]
        self.env_dx[2] = (self.env_high[2] - self.env_low[2]) / tmp[2]
        self.env_dx[3] = (self.env_high[3] - self.env_low[3]) / tmp[3]
        
        self.q_table = np.zeros((tmp[0],tmp[1],tmp[2],tmp[3],2)) #Initialisierung der Zustandswertfunktion
        
    def get_status(self, _observation): #Diskriminierungszustand
        
        s1 = int((_observation[0] - self.env_low[0])/self.env_dx[0]) #Lassen Sie sich in einen der sieben Staaten fallen
        
        if _observation[1] < -1.5: #Klassifizieren Sie selbst
          s2 = 0
        elif -1.5 <= _observation[1] < - 1:
          s2 = 1
        elif -1 <= _observation[1] < -0.5:
          s2 = 2
        elif -0.5 <= _observation[1] < 0.5:
          s2 = 3
        elif 0.5 <= _observation[1] < 1.5:
          s2 = 4
        elif 1.5 <= _observation[1] < 2:
          s2 = 5
        elif 2 <= _observation[1]:
          s2 = 6
        
        s3 = int((_observation[2] - self.env_low[2])/self.env_dx[2]) #Lassen Sie sich in einen der sieben Staaten fallen
        
        if _observation[3] < -1: #Klassifizieren Sie selbst
          s4 = 0
        elif -1 <= _observation[3] < -0.7:
          s4 = 1
        elif -0.7 <= _observation[3] < -0.6:
          s4 = 2
        elif -0.6 <= _observation[3] < -0.5:
          s4 = 3
        elif -0.5 <= _observation[3] < -0.4:
          s4 = 4
        elif -0.4 <= _observation[3] < -0.4:
          s4 = 5
        else:
          s4 = 6
          
        return s1, s2, s3, s4
    
    def policy(self, s, epi): #Wählen Sie eine Aktion im Status s aus
        
        epsilon = 0.5 * (1 / (epi + 1))
        
        if np.random.random() <= epsilon:
            return np.random.randint(2) #Wählen Sie nach dem Zufallsprinzip
        else:
            s1, s2, s3, s4 = self.get_status(s)
            return np.argmax(self.q_table[s1][s2][s3][s4]) #Wählen Sie die Aktion mit dem höchsten Aktionswert aus
    
    def learn(self, time = 200, alpha = 0.5, gamma = 0.99): #Lerne so oft wie möglich
        
        log = [] #Notieren Sie die Gesamtbelohnung für jede Episode
        t_log = [] #Notieren Sie die Anzahl der Schritte pro Episode
        
        for j in range(time+1):
            t = 0 #Anzahl der Schritte
            total = 0 #Gesamtbelohnung
            s = self.env.reset()
            done = False
            
            while not done:
                t += 1
                a = self.policy(s, j)
                next_s, reward, done, _ = self.env.step(a)
                
                reward = t/10 #Je länger Sie aushalten, desto mehr Belohnungen erhalten Sie
                
                if done:
                  if t < 195:
                    reward -= 1000 #Strafen für Nichterhaltung
                  else:
                    reward = 1000 #Geben Sie mehr Belohnungen für den Erfolg

                total += reward
                
                
                s1, s2, s3, s4 = self.get_status(next_s)
                G = reward + gamma * self.q_table[s1][s2][s3][s4][self.policy(next_s, j)] #Berechnung der kumulierten Belohnung
                
                s1, s2, s3, s4 = self.get_status(s)
                self.q_table[s1][s2][s3][s4][a] += alpha*(G - self.q_table[s1][s2][s3][s4][a]) #Q Update
                s = next_s

            t_log.append(t)
            log.append(total)
            
            if j %1000 == 0:
              print(str(j) + " ===total reward=== : " + str(total))
            
        return plt.plot(t_log)

    def show(self): #Lernergebnisse anzeigen
        s = self.env.reset()
        img = self.env.render()
        done = False
        t = 0
        while not done:
          t += 1
          a = self.policy(s, 10000)
          s, _, done, _ = self.env.step(a)
          self.env.render()
                
        print(t)
        self.env.reset()
        self.env.close()

Problempunkt

Hier bin ich gestolpert. Bei init bereite ich mich darauf vor, jeden der vier Zustände mit env_dx zu zerstreuen, aber ich habe hier ein Problem. Wenn Sie sich die Referenz genau ansehen, スクリーンショット 2020-09-14 18.34.59.png Der variable Bereich des Geschwindigkeitswertes ist ** inf **. Ja, ** es ist unendlich! **

In diesem Fall wird auch der Wert von env_dx unendlich und die Streuung kontinuierlicher Werte funktioniert nicht. Deshalb,

from random import random
env.step(random.randint(2))

Wir haben viele Male gearbeitet und Schwankungen in der Geschwindigkeit des Wagens und dann in der Winkelgeschwindigkeit der Stange beobachtet. Dann,

if _observation[1] < -1.5: #Die Geschwindigkeit des Wagens
          s2 = 0
        elif -1.5 <= _observation[1] < - 1:
          s2 = 1
        elif -1 <= _observation[1] < -0.5:
          s2 = 2
        elif -0.5 <= _observation[1] < 0.5:
          s2 = 3
        elif 0.5 <= _observation[1] < 1.5:
          s2 = 4
        elif 1.5 <= _observation[1] < 2:
          s2 = 5
        elif 2 <= _observation[1]:
          s2 = 6

        if _observation[3] < -1: #Polwinkelgeschwindigkeit
          s4 = 0
        elif -1 <= _observation[3] < -0.7:
          s4 = 1
        elif -0.7 <= _observation[3] < -0.6:
          s4 = 2
        elif -0.6 <= _observation[3] < -0.5:
          s4 = 3
        elif -0.5 <= _observation[3] < -0.4:
          s4 = 4
        elif -0.4 <= _observation[3] < -0.4:
          s4 = 5
        else:
          s4 = 6

Mir wurde klar, dass ich es so klassifizieren konnte.

Lernen

Lerne so. Es ist ungefähr 3000 Mal und ich kann es mir leisten.

env = gym.make('CartPole-v0')
agent = SARSA(env)
agent.learn(time = 3000)

Die Änderung der Anzahl der Schritte ist wie folgt. スクリーンショット 2020-09-14 18.44.03.png

Lassen Sie uns nun die Animation mit `agent.show ()` überprüfen. 棒を立てる.gif

Es ist ziemlich stabil und hat eine große Nachhaltigkeit. Ich bin froh, ein ** Mann ** zu sein.

Q Lernen gegen SARSA

Vergleichen wir Q-Learning und SARSA in dieser Umgebung. G im Q-Lernen

G = reward + gamma * max(self.q_table[s1][s2][s3][s4])

Machen. Wenn ich versuche, damit zu lernen, スクリーンショット 2020-09-14 18.48.59.png Die Stabilität der Konvergenz scheint bei SARSA besser zu sein. Wenn Sie ein Mann sind, betrachten Sie die Realität wie SARSA. Ja.

Impressionen

In diesem Umfeld habe ich mich gefragt, ob die Streuung von Staaten der schwierigste Teil ist. Es scheint, dass DQN geboren wurde, um dieses Problem zu lösen. Nächstes Mal werde ich versuchen, einen DQN zu erstellen. wir sehen uns!