[PYTHON] Fordern Sie DQN (Modoki) mit Chainer heraus ✕ Öffnen Sie AI Gym!

Einführung

Ich habe ein Programm zur Lösung der klassischen Steuerung von OpenAI Gym mit Deep Q Network, allgemein bekannt als DQN, erstellt, das Deep Learning und intensives Lernen kombiniert. Dieses Mal möchte ich die Implementierung vorstellen.

Über DQN selbst

Der Artikel ist sehr einfach zu verstehen und ich habe ihn unter Bezugnahme auf die hier vorgestellten Artikel und den GitHub-Code implementiert. Wenn Sie die Theorie des verstärkenden Lernens und des DQN kennenlernen möchten, lesen Sie bitte hier.

DQN "Modoki"?

Wie Sie unter dem Namen Deep Q Network sehen können, approximiert DQN das Q-Lernen, das eines der Verstärkungslernen ist, funktional mit einem mehrschichtigen neuronalen Netz. Darüber hinaus scheint es, dass es nur nach Einbeziehung der folgenden drei Methoden als DQN bezeichnet werden kann.

  1. Experience Replay
  2. Fixed Target Q-Network
  3. Belohnungsausschnitt

Die Methode, die ich dieses Mal implementiert habe, war nur 1 und 2, und ich habe die Belohnung von 3 nicht abgeschnitten. Um genau zu sein, ist es nicht DQN. Also habe ich mich für DQN "Modoki" entschieden.

Über OpenAI Gym

Eine Open Source-Plattform, die es einfach macht, eine Umgebung für verbessertes Lernen zu erstellen. Es ist eine Python-Bibliothek

$ pip install gym

Einfach zu installieren mit. Weitere Informationen finden Sie auf der offiziellen Website.

Implementierung

Jetzt möchte ich den implementierten Code vorstellen. Ein Teil des hier gezeigten Codes ist weggelassen. Überprüfen Sie daher das Ganze von hier.

neurales Netzwerk

Ich habe es mit Chainer implementiert. 100 Einheiten haben 3 Schichten und die Aktivierungsfunktion ist Leaky ReLU.

class Neuralnet(Chain):

    def __init__(self, n_in, n_out):
        super(Neuralnet, self).__init__(
            L1 = L.Linear(n_in, 100),
            L2 = L.Linear(100, 100),
            L3 = L.Linear(100, 100),
            Q_value = L.Linear(100, n_out, initialW=np.zeros((n_out, 100), dtype=np.float32))
        )

    def Q_func(self, x):
        h = F.leaky_relu(self.L1(x))
        h = F.leaky_relu(self.L2(h))
        h = F.leaky_relu(self.L3(h))
        h = self.Q_value(h)
        return h

Agent

Implementierung des Agententeiles des erweiterten Lernens.

Parametereinstellungen

Es definiert die Parameter für die Durchführung des Verstärkungslernens. Das früher eingeführte neuronale Netzwerk wird auch gemäß der Anzahl der Lesezustände und der Anzahl der Aktionen definiert. Erstellen Sie für das Q-Netzwerk mit festem Ziel eine ausführliche Kopie der erstellten Q-Funktion. Mit anderen Worten gibt es zwei Q-Funktionen. Anfangs fiel es mir schwer, diesen Teil zu verstehen ...

class Agent():

    def __init__(self, n_st, n_act, seed):
        self.n_act = n_act
        self.model = Neuralnet(n_st, n_act)
        self.target_model = copy.deepcopy(self.model)
        self.optimizer = optimizers.Adam()
        self.optimizer.setup(self.model)
        self.memory = deque()
        self.loss = 0
        self.step = 0
 self.gamma = 0,99 # Diskontsatz
 self.mem_size = 1000 #Experience Anzahl der Erfahrungen, an die Sie sich bei der Wiedergabe erinnern sollten
 self.batch_size = 100 # Mini-Batch-Größe für Experience Replay
 self.train_freq = 10 # Trainingsintervall für neuronale Netze
 self.target_update_freq = 20 # Zielnetzwerk-Synchronisationsintervall
        # ε-greedy
 self.epsilon = 1 # Anfangswert von ε
 self.epsilon_decay = 0,005 # Abklingwert von ε
 self.epsilon_min = 0 #Mindestwert von ε
 self.exploration = 1000 # Anzahl der Schritte, bis ε zu verfallen beginnt (diesmal bis sich Speicher angesammelt hat)

Ansammlung von Erfahrungen

Für Experience Replay

  1. Zustand: st
  2. Aktion: handeln
  3. Belohnung: r
  4. Nächster Status: st_dash
  5. Ende der Episode: ep_end

Die fünf Elemente von werden als Erfahrung abgehört und im Speicher gespeichert. Wenn es die zu Beginn definierte Speichergröße überschreitet, wird es in einem Tokoroten-Stil von dem zuerst eingegebenen verworfen. Anfangs war Memory nur eine Liste, aber ich habe gehört, dass es eine Deque gibt, die Anhänge und Pops an beiden Enden binden kann, also habe ich diese verwendet.

def stock_experience(self, st, act, r, st_dash, ep_end):
    self.memory.append((st, act, r, st_dash, ep_end))
    if len(self.memory) > self.mem_size:
        self.memory.popleft()

Experience Replay

Dies ist der Implementierungsteil von Experience Replay, einer der wichtigsten Techniken in DQN. Mische den gespeicherten Speicher, schneide ihn in der definierten Mini-Batch-Größe aus und lerne.

def suffle_memory(self):
    mem = np.array(self.memory)
    return np.random.permutation(mem)

def parse_batch(self, batch):
    st, act, r, st_dash, ep_end = [], [], [], [], []
    for i in xrange(self.batch_size):
        st.append(batch[i][0])
        act.append(batch[i][1])
        r.append(batch[i][2])
        st_dash.append(batch[i][3])
        ep_end.append(batch[i][4])
    st = np.array(st, dtype=np.float32)
    act = np.array(act, dtype=np.int8)
    r = np.array(r, dtype=np.float32)
    st_dash = np.array(st_dash, dtype=np.float32)
    ep_end = np.array(ep_end, dtype=np.bool)
    return st, act, r, st_dash, ep_end

def experience_replay(self):
    mem = self.suffle_memory()
    perm = np.array(xrange(len(mem)))
    for start in perm[::self.batch_size]:
        index = perm[start:start+self.batch_size]
        batch = mem[index]
        st, act, r, st_d, ep_end = self.parse_batch(batch)
        self.model.zerograds()
        loss = self.forward(st, act, r, st_d, ep_end)
        loss.backward()
        self.optimizer.update()

Q-Funktion Update-Teil

Dies ist der Aktualisierungsteil der Q-Funktion unter Verwendung des neuronalen Netzwerks. Es ist wichtig, die kopierte Q-Funktion (self.target_model.Q_func) in dem Teil zu verwenden, der den maximalen Q-Wert im nächsten Zustand berechnet (st_dash).

def forward(self, st, act, r, st_dash, ep_end):
    s = Variable(st)
    s_dash = Variable(st_dash)
    Q = self.model.Q_func(s)
    tmp = self.target_model.Q_func(s_dash)
    tmp = list(map(np.max, tmp.data))
    max_Q_dash = np.asanyarray(tmp, dtype=np.float32)
    target = np.asanyarray(copy.deepcopy(Q.data), dtype=np.float32)
    for i in xrange(self.batch_size):
        target[i, act[i]] = r[i] + (self.gamma * max_Q_dash[i]) * (not ep_end[i])
    loss = F.mean_squared_error(Q, Variable(target))
    return loss

Bei der Berechnung des Verlusts scheint es, dass das Lernen schneller sein wird, wenn die Differenz zwischen dem Q-Wert und dem Ziel auf -1 zu 1 gekürzt wird, aber ich konnte es nicht implementieren, weil ich die Theorie aufgrund mangelnder Studien nicht verstehen konnte (es tut mir leid ...

Aktion zurückgeben

Dies ist der Teil, der die auszuführende Aktion zurückgibt, wenn sie gemäß der erlernten Q-Funktion eingegeben wird. Die Methode der Aktionsauswahl verwendet ε-gierig.

def get_action(self, st):
    if np.random.rand() < self.epsilon:
        return np.random.randint(0, self.n_act)
    else:
        s = Variable(st)
        Q = self.model.Q_func(s)
        Q = Q.data[0]
        a = np.argmax(Q)
        return np.asarray(a, dtype=np.int8)

Vorauslernen

Dies ist der Teil, um mit dem Lernen fortzufahren, wenn genügend Speicher angesammelt ist. Der Schritt wird jedes Mal angekreuzt und die Q-Funktion für das Ziel wird in regelmäßigen Abständen synchronisiert. Nach Abschluss der Suche nimmt ε mit jedem Schritt ab.

def reduce_epsilon(self):
    if self.epsilon > self.epsilon_min and self.exploration < self.step:
        self.epsilon -= self.epsilon_decay

def train(self):
    if len(self.memory) >= self.mem_size:
        if self.step % self.train_freq == 0:
            self.experience_replay()
            self.reduce_epsilon()
        if self.step % self.target_update_freq == 0:
            self.target_model = copy.deepcopy(self.model)
    self.step += 1

Ausführungsteil

Ich habe versucht, es so zu gestalten, dass bei Eingabe des Umgebungsnamens des Classic-Steuerelements die Anzahl der Status und die Anzahl der Aktionen ohne Erlaubnis beurteilt werden Es ist vielleicht etwas chaotisch und schwer zu verstehen geworden ^^;

def main(env_name):
    env = gym.make(env_name)
    view_path = "./video/" + env_name

    n_st = env.observation_space.shape[0]
    if type(env.action_space) == gym.spaces.discrete.Discrete:
        # CartPole-v0, Acrobot-v0, MountainCar-v0
        n_act = env.action_space.n
        action_list = range(0, n_act)
    elif type(env.action_space) == gym.spaces.box.Box:
        # Pendulum-v0
        action_list = [np.array([a]) for a in [-2.0, 2.0]]
        n_act = len(action_list)

    agent = Agent(n_st, n_act, seed)

    env.monitor.start(view_path, video_callable=None, force=True, seed=seed)
    for i_episode in xrange(1000):
        observation = env.reset()
        for t in xrange(200):
            env.render()
            state = observation.astype(np.float32).reshape((1,n_st))
            act_i = agent.get_action(state)
            action = action_list[act_i]
            observation, reward, ep_end, _ = env.step(action)
            state_dash = observation.astype(np.float32).reshape((1,n_st))
            agent.stock_experience(state, act_i, reward, state_dash, ep_end)
            agent.train()
            if ep_end:
                break
    env.monitor.close()

Ausführungsergebnis

Ich habe die Ergebnisse in OpenAI Gym hochgeladen

Ich denke, Acrobot und Pendel sind ziemlich gute Ergebnisse, aber Cart Pole ist subtil. Es scheint, dass die Ergebnisse in Abhängigkeit von der Aktualisierungsfrequenz der Q-Funktion für das Ziel, der Größe der ε-Dämpfung und der Optimierungsmethode variieren werden. interessant!

abschließend

Ich möchte es in Zukunft mit Atari-Spielen versuchen. Zu diesem Zeitpunkt scheint es notwendig zu sein, die Belohnung abzuschneiden. Sollte ich Normalisierung und DropOut in Betracht ziehen?

Recommended Posts

Fordern Sie DQN (Modoki) mit Chainer heraus ✕ Öffnen Sie AI Gym!
Löse OpenAI Gym Copy-v0 mit Sarsa
Öffnen Sie AI Gym, um mit PD-gesteuertem Cart Pole zu lernen
Seq2Seq (1) mit Chainer
Erstellen Sie eine Open AI Gym-Umgebung mit Bash unter Windows 10
Verwenden Sie Tensorboard mit Chainer
Verstärkungslernen in kürzester Zeit mit Keras mit OpenAI Gym