[PYTHON] DQN mit TensorFlow implementiert (ich wollte ...)

Nachdem ich die folgenden Artikel gelesen hatte, war ich beeindruckt, dass DQN (Deep Q-Network) interessant zu sein scheint. Das kürzlich besprochene über Alpha-Go ist auch eine Erweiterung von DQN ... oder? (Ich verstehe nicht) Geschichte von DQN + Deep Q-Network in Chainer geschrieben DQN (Deep Q Network) Lernen mit invertiertem Pendel Spielen mit maschinellem Lernen mit Chainer: Können Sie das Lernen von Zusatzspielen mit Chainer verbessern?

Deshalb habe ich versucht, es mit TensorFlow zu implementieren ... (-_-;)? ?? ?? Ich bin mir nicht sicher. Nein, das Problem ist, dass ich es versuche, ohne die Theorie und Formeln zu verstehen. Ich denke, es gibt zu wenige Beispiele für TensorFlow. Vorerst habe ich versucht, es nachzuahmen, daher würde ich es begrüßen, wenn Sie Kommentare abgeben könnten, wenn es Missverständnisse oder Korrekturen gibt. "Dieser Bereich ist korrekt" und "Dieser Bereich ist in Ordnung" sind ebenfalls sehr hilfreich.

Andere Websites, auf die verwiesen wird: Deep-Q learning Pong with Tensorflow and PyGame Ich habe wahrscheinlich auf den Quellcode in der oberen Hälfte dieser Seite verwiesen.

Implementierungsdetails

Betrachten Sie das folgende Spiel.

Umgebung

TensorFlow 0.7 Ubuntu 14.04 GCE vCPU x8-Instanz

Implementierung

Ich werde den Quellcode unten einfügen, aber ich werde den Teil erklären.

Diagrammerstellung

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_HIDDEN1], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.matmul(x_ph, weights) + biases

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.matmul(hidden1, weights) + biases

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

Es gibt zwei versteckte Ebenen, und die Anzahl der Einheiten beträgt 100 bzw. 100. Die Nummer dieser Seite ist angemessen. (Ich versuche es, während ich damit spiele) Geben Sie nur eine Zahl ein, die die aktuelle Position angibt. Es gibt zwei Ausgänge, die erwarteten Belohnungen für +1 und +2 (glaube ich). Ich habe viele variable Initialisierungen gesehen, die mit Null initialisiert wurden, aber nicht funktionierten, also zufällige Initialisierung. (Gibt es ein Problem?) Die Aktivierungsfunktion funktioniert nicht gut, wenn ich relu verwende, und wenn ich sie ohne die Aktivierungsfunktion verbinde, funktioniert sie ein wenig mit Matomo, so dass es keine bleibt. (Gibt es ein Problem?)

Verlustberechnung

def loss(y, y_ph):
    return tf.reduce_mean(tf.nn.l2_loss((y - y_ph)))

Die Verlustberechnung scheint quadratisch und halbiert zu sein. Implementieren Sie sie daher mit der entsprechenden API.

Der Teil, um tatsächlich zu trainieren

def getNextPositionReward(choice_position):

    if choice_position % 8 == 0:
        next_position_reward = -1.
    elif choice_position % 2 == 0:
        next_position_reward = 1.
    else:
        next_position_reward = 0.

    return next_position_reward

Eine Funktion, die eine Strafe zurückgibt, wenn der nächste Platz ein Vielfaches von 8 ist, und eine Belohnung, wenn es ein Vielfaches von 2 ist.

def getNextPosition(position, action_reward1, action_reward2):

    if random.random() < RANDOM_FACTOR:
        if random.randint(0, 1) == 0:
            next_position = position + 1
        else:
            next_position = position + 2
    else:
        if action_reward1 > action_reward2:
            next_position = position + 1
        else:
            next_position = position + 2

    return next_position

Der Teil, der die beiden Belohnungen vergleicht und überlegt, ob er +1 oder +2 vorrücken soll. Zum Zeitpunkt des Trainings versuche ich, ein bestimmtes zufälliges Element einzugeben und fortzufahren.

    for i in range(REPEAT_TIMES):
        position = 0.
        position_history = []
        reward_history = []

        while(True):
            if position >= GOAL:
                break

            choice1_position = position + 1.
            choice2_position = position + 2.

            next_position1_reward = getNextPositionReward(choice1_position)
            next_position2_reward = getNextPositionReward(choice2_position)

            reward1 = sess.run(y, feed_dict={x_ph: [[choice1_position]]})[0]
            reward2 = sess.run(y, feed_dict={x_ph: [[choice2_position]]})[0]

            action_reward1 = next_position1_reward + GAMMA * np.max(reward1)
            action_reward2 = next_position2_reward + GAMMA * np.max(reward2)

            position_history.append([position])
            reward_history.append([action_reward1, action_reward2])

            position = getNextPosition(position, action_reward1, action_reward2)

        sess.run(train_step, feed_dict={x_ph: position_history, y_ph: reward_history})

Schulungsteil (Auszug). Es gibt zwei Möglichkeiten: Vergleichen Sie die Belohnungen und wählen Sie die mit der höheren Belohnung aus. Die Belohnung ist die Summe der Maximalwerte von "der Belohnung (sicher), die an der nächsten Position erhalten wird" und "dem vorhergesagten Wert der Belohnung, die (wahrscheinlich) danach erhalten wird". Stellen Sie außerdem eine Liste der beiden Belohnungen und Ihre aktuelle Position für überwachtes Lernen zusammen. Dies wird ungefähr 1000 Mal wiederholt. ⇒ Ich mache mir darüber Sorgen. Ich glaube, ich mache einen großen Fehler.

Ergebnis

Werfen wir einen Blick auf die Flugbahn, wie sie sich nach dem Training tatsächlich bewegt hat.

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

Es gibt nur eine gerade Zahl zurück. Ich trete perfekt auf ein Vielfaches von 8! Ich habe das Gefühl, positive Belohnungen zu erhalten, aber ich habe nicht das Gefühl, negative zu vermeiden. Als ich verschiedene Dinge ausprobiert habe, wie zum Beispiel den negativen Wert der Belohnung zu erhöhen, scheint der obige Wert unterschiedlich zu sein, so dass es den Anschein hat, dass der Wert kein fester Wert ist, aber er hat sich nicht ideal bewegt ... ・ ・. Der Verlust ist übrigens konvergiert.

Quellcode (alle)

import tensorflow as tf
import numpy as np
import random

# definition
NUM_IMPUT = 1
NUM_HIDDEN1 = 100
NUM_HIDDEN2 = 100
NUM_OUTPUT = 2
LEARNING_RATE = 0.1
REPEAT_TIMES = 100
GOAL = 100
LOG_DIR = "tf_log"
GAMMA = 0.8
stddev = 0.01
RANDOM_FACTOR = 0.1

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_HIDDEN1], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.matmul(x_ph, weights) + biases

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.matmul(hidden1, weights) + biases

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

def loss(y, y_ph):
    return tf.reduce_mean(tf.nn.l2_loss((y - y_ph)))

def optimize(loss):
    optimizer = tf.train.AdamOptimizer(LEARNING_RATE)
    train_step = optimizer.minimize(loss)
    return train_step

def getNextPositionReward(choice_position):

    if choice_position % 8 == 0:
        next_position_reward = -1.
    elif choice_position % 2 == 0:
        next_position_reward = 1.
    else:
        next_position_reward = 0.

    return next_position_reward

def getNextPosition(position, action_reward1, action_reward2):

    if random.random() < RANDOM_FACTOR:
        if random.randint(0, 1) == 0:
            next_position = position + 1
        else:
            next_position = position + 2
    else:
        if action_reward1 > action_reward2:
            next_position = position + 1
        else:
            next_position = position + 2

    return next_position

if __name__ == "__main__":

    x_ph = tf.placeholder(tf.float32, [None, NUM_IMPUT])
    y_ph = tf.placeholder(tf.float32, [None, NUM_OUTPUT])

    y = inference(x_ph)
    loss = loss(y, y_ph)
    tf.scalar_summary("Loss", loss)
    train_step = optimize(loss)

    sess = tf.Session()
    summary_op = tf.merge_all_summaries()
    init = tf.initialize_all_variables()
    sess.run(init)
    summary_writer = tf.train.SummaryWriter(LOG_DIR, graph_def=sess.graph_def)

    for i in range(REPEAT_TIMES):
        position = 0.
        position_history = []
        reward_history = []

        while(True):
            if position >= GOAL:
                break

            choice1_position = position + 1.
            choice2_position = position + 2.

            next_position1_reward = getNextPositionReward(choice1_position)
            next_position2_reward = getNextPositionReward(choice2_position)

            reward1 = sess.run(y, feed_dict={x_ph: [[choice1_position]]})[0]
            reward2 = sess.run(y, feed_dict={x_ph: [[choice2_position]]})[0]

            action_reward1 = next_position1_reward + GAMMA * np.max(reward1)
            action_reward2 = next_position2_reward + GAMMA * np.max(reward2)

            position_history.append([position])
            reward_history.append([action_reward1, action_reward2])

            position = getNextPosition(position, action_reward1, action_reward2)

        sess.run(train_step, feed_dict={x_ph: position_history, y_ph: reward_history})
        summary_str = sess.run(summary_op, feed_dict={x_ph: position_history, y_ph: reward_history})
        summary_writer.add_summary(summary_str, i)
        if i % 10 == 0:
            print "Count: " + str(i)

    # TEST
    position = 0
    position_history = []
    while(True):
        if position >= GOAL:
                break

        position_history.append(position)

        rewards = sess.run(y, feed_dict={x_ph: [[position]]})[0]
        choice = np.argmax(rewards)
        if choice == 0:
            position += 1
        else:
            position += 2

    print position_history

Ja wirklich

Wir freuen uns auf Ihren Rat und Ihre Nutzlosigkeit.

27.04.2016 Nachtrag

dsanno gab uns in den Kommentaren einige Ratschläge. Vielen Dank. Ich werde das versuchen.

Teil 1

Bei dieser Problemeinstellung gibt es keine versteckte Ebene. Ich denke, dass Sie mit nur einer Ebene von embedded_lookup mit 100 Eingabewerten (ein heißer Vektor, der Ihren aktuellen Standort darstellt) und 2 Ausgabewerten lernen können.

Ich sehe ich sehe··· Ich verstehe Embedding_lookup immer noch nicht, also lasse ich es beiseite und mache die Eingabe zu einem One-Hot-Vektor und versuche es ohne versteckte Ebene.

def inference(x_ph):

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(x_ph, weights) + biases

Unten finden Sie eine Funktion zum Erstellen eines One-Hot-Vektors.

def onehot(idx):
    idx = int(idx)
    array = np.zeros(GOAL)
    array[idx] = 1.
    return array

Ergebnis

[0, 2, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 39, 41, 42, 44, 46, 47, 49, 50, 52, 53, 54, 55, 57, 58, 60, 62, 63, 65, 66, 68, 70, 71, 73, 74, 76, 78, 79, 81, 82, 84, 86, 88, 90, 92, 94, 95, 97, 98, 99]

Es ist so ähnlich. Es ist nicht perfekt, aber ich habe das Gefühl, ich versuche, Vielfache von 8 zu vermeiden, während ich so viel wie möglich auf Vielfache von 2 trete.

Teil 2

Mit ReLu gibt es keine Obergrenze für die Ausgabe und es scheint inkompatibel zu sein. Machen Sie also tanh oder relu6 mit einer Obergrenze zu einer Aktivierungsfunktion

Ich habe es mit 100.100 versteckten Ebeneneinheiten versucht, während ich eine Eingabe beibehalten habe. Dies unterscheidet sich nicht wesentlich von der Funktion ohne Aktivierung.

Ergebnis

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

Teil 3

Wenn Sie davon ausgehen können, dass die Lösung periodisch ist, verwenden Sie tf.sin für die Aktivierungsfunktion (verwenden Sie beispielsweise sin für die erste Stufe und relu für die zweite Stufe). Ich habe es mit 100.100 versteckten Ebeneneinheiten versucht, während ich eine Eingabe beibehalten habe.

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.zeros([NUM_IMPUT, NUM_HIDDEN1], dtype=tf.float32), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.sin(tf.matmul(x_ph, weights) + biases)

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

Ergebnis

[0, 2, 4, 6, 8, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 29, 30, 31, 33, 34, 36, 38, 39, 41, 43, 44, 46, 47, 49, 50, 51, 53, 55, 57, 58, 60, 62, 63, 64, 66, 68, 69, 71, 73, 74, 76, 78, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 94, 95, 97, 98]

Ich trete auf die ersten 8, aber ich habe das Gefühl, auch hier mein Bestes zu geben.

Ein wenig korrigiert und die Anzahl der versteckten Ebeneneinheiten auf 500.100 angepasst.

Ergebnis

[0, 2, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 46, 47, 49, 50, 52, 54, 55, 57, 58, 60, 62, 63, 65, 66, 68, 70, 71, 73, 74, 76, 78, 79, 81, 82, 84, 86, 87, 89, 90, 92, 94, 95, 97, 98]

Ist es perfekt Ich habe überhaupt nicht daran gedacht, sin () zu benutzen. Nochmals vielen Dank, dsanno.

Impressionen

Als ich von künstlicher Intelligenz hörte, hatte ich die Illusion, dass ich, wenn ich es vorerst tat, selbst an alles denken würde, aber mir wurde klar, dass die Eigenschaften der Eingabedaten und des Erstellers richtig darüber nachdenken mussten. ..

Recommended Posts

DQN mit TensorFlow implementiert (ich wollte ...)
Ich wollte ABC159 mit Python lösen
Ich möchte mich mit Backpropagation (tf.custom_gradient) (Tensorflow) selbst verwenden.
Ich wollte mit boto3 mehrere objekte in s3 löschen
Hash-Kette wollte ich vermeiden (2)
Ich wollte cGAN zu ACGAN weiterentwickeln
So führen Sie TensorFlow 1.0-Code in 2.0 aus
Hash-Kette wollte ich vermeiden (1)
Ich wollte so etwas wie Elixirs Pipe in Python machen
Ich habe versucht, Autoencoder mit TensorFlow zu implementieren
Ich habe versucht, Permutation in Python zu implementieren
Ich möchte in der Einschlussnotation drucken
Ich habe versucht, AutoEncoder mit TensorFlow zu visualisieren
Ich habe versucht, PLSA in Python 2 zu implementieren
Ich wollte ABC160 mit Python lösen
Ich habe versucht, Text mit TensorFlow zu klassifizieren
Ich habe versucht, Couseras logistische Regression in Python zu implementieren
Ich habe versucht, ADALINE in Python zu implementieren
Ich möchte Matplotlib in PySimpleGUI einbetten
Ich wollte ABC172 mit Python lösen
Ich wollte ein Jupyter-Notebook mit Docker in einer Pip-Umgebung (Opticspy) verwenden.
Ich habe das VGG16-Modell mit Keras implementiert und versucht, CIFAR10 zu identifizieren
Ich habe versucht, Robinsons Bayesian Spam Filter mit Python zu implementieren
Ich möchte Datetime.now in Djangos Test reparieren
Ich wollte den NOMURA Contest 2020 mit Python lösen
Ich habe DCGAN implementiert und versucht, Äpfel zu generieren
i-Town Page Scraping: Ich wollte den Platz von Wise-Kun einnehmen
Python: Ich konnte in Lambda rekursieren
Ich möchte mit Python ein Fenster erstellen
Ich habe versucht, Keras in TFv1.1 zu integrieren
Ich wollte mit der Bezier-Kurve spielen
So führen Sie CNN in 1 Systemnotation mit Tensorflow 2 aus
Geschrieben "Einführung in die Effektüberprüfung" in Python
Ich möchte DB-Informationen in einer Liste speichern
Ich möchte verschachtelte Dicts in Python zusammenführen
Ich habe CycleGAN (1) implementiert.
Ich habe versucht, TOPIC MODEL in Python zu implementieren
Ich habe versucht, die inverse Gammafunktion in Python zu implementieren
[Ich möchte Bilder mit Tensorflow klassifizieren] (2) Lassen Sie uns Bilder klassifizieren
Ich habe ResNet implementiert!
Ich habe versucht, eine selektive Sortierung in Python zu implementieren
Ich möchte den Fortschritt in Python anzeigen!
Ich habe ein ○ ✕ Spiel mit TensorFlow gemacht
Ich wollte nur Pythons Pickle-Modul verstehen
Ich habe versucht, die Suche nach Breitenpriorität mit Python zu implementieren (Warteschlange, selbst erstelltes Zeichnen).
Ich möchte in Python schreiben! (1) Überprüfung des Codeformats
Ich habe versucht, die in Python installierten Pakete grafisch darzustellen
Ich möchte eine Variable in einen Python-String einbetten
Ich möchte Timeout einfach in Python implementieren
Ich möchte, dass DQN Puniki einen Homerun macht
Ich wollte auch Typhinweise mit numpy überprüfen
Ich möchte mit einem Knopf am Kolben übergehen
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Verfahren zur Installation von TensorFlow in einer Fischschalenumgebung (Anaconda 4.0.0)
Auch mit JavaScript möchte ich Python `range ()` sehen!
Ich habe ein Skript erstellt, um ein Snippet in README.md einzufügen
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Ich wollte die Python-Bibliothek von MATLAB verwenden
Ich möchte eine Datei mit Python zufällig testen
Ich habe versucht, Drakues Poker in Python zu implementieren