In [1]:
# -*- coding: utf-8 -*-
import random
import gym
import numpy as np
from collections import deque
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras import backend as K


Using TensorFlow backend.

In [2]:
#EPISODES = 5000
EPISODES = 100

class DQNAgent:
    def __init__(self, state_size, action_size):
        self.state_size = state_size
        self.action_size = action_size
        self.memory = deque(maxlen=2000)
        self.gamma = 0.95    # discount rate
        self.epsilon = 1.0  # exploration rate
        self.epsilon_min = 0.01
        self.epsilon_decay = 0.99
        self.learning_rate = 0.001
        self.model = self._build_model()
        self.target_model = self._build_model()
        self.update_target_model()

    def _huber_loss(self, target, prediction):
        # sqrt(1+error^2)-1
        error = prediction - target
        return K.mean(K.sqrt(1+K.square(error))-1, axis=-1)

    def _build_model(self):
        # Neural Net for Deep-Q learning Model
        model = Sequential()
        model.add(Dense(24, input_dim=self.state_size, activation='relu'))
        model.add(Dense(24, activation='relu'))
        model.add(Dense(self.action_size, activation='linear'))
        model.compile(loss=self._huber_loss,
                      optimizer=Adam(lr=self.learning_rate))
        return model

    def update_target_model(self):
        # copy weights from model to target_model
        self.target_model.set_weights(self.model.get_weights())

    def remember(self, state, action, reward, next_state, done):
        self.memory.append((state, action, reward, next_state, done))

    def act(self, state):
        if np.random.rand() <= self.epsilon:
            return random.randrange(self.action_size)
        act_values = self.model.predict(state)
        return np.argmax(act_values[0])  # returns action

    def replay(self, batch_size):
        minibatch = random.sample(self.memory, batch_size)
        for state, action, reward, next_state, done in minibatch:
            target = self.model.predict(state)
            if done:
                target[0][action] = reward
            else:
                # a = self.model.predict(next_state)[0]
                t = self.target_model.predict(next_state)[0]
                target[0][action] = reward + self.gamma * np.amax(t)
                # target[0][action] = reward + self.gamma * t[np.argmax(a)]
            self.model.fit(state, target, nb_epoch=1, verbose=0)
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay

    def load(self, name):
        self.model.load_weights(name)

    def save(self, name):
        self.model.save_weights(name)

In [3]:
if __name__ == "__main__":
    env = gym.make('CartPole-v1')
    state_size = env.observation_space.shape[0]
    action_size = env.action_space.n
    agent = DQNAgent(state_size, action_size)
    # agent.load("./save/cartpole-ddqn.h5")
    done = False
    batch_size = 32

    for e in range(EPISODES):
        state = env.reset()
        state = np.reshape(state, [1, state_size])
        for time in range(500):
            # env.render()
            action = agent.act(state)
            debug = False
            if debug:
                print(action)
            next_state, reward, done, _ = env.step(action)
            reward = reward if not done else -10
            debug=False
            if debug:
                print('next_state')
                print(next_state)
                print(state_size)
            next_state = np.reshape(next_state, [1, state_size])
            if debug:
                print('reshaped next_state')
                print(next_state)
                print('=========')
            agent.remember(state, action, reward, next_state, done)
            state = next_state
            if done:
                agent.update_target_model()
                print("episode: {}/{}, score: {}, e: {:.2}"
                      .format(e, EPISODES, time, agent.epsilon))
                break
            if len(agent.memory) > batch_size:
                agent.replay(batch_size)
        # if e % 10 == 0:
        #     agent.save("./save/cartpole-ddqn.h5")


WARN: gym.spaces.Box autodetected dtype as <class 'numpy.float32'>. Please provide explicit dtype.
episode: 0/100, score: 15, e: 1.0
episode: 1/100, score: 9, e: 1.0
episode: 2/100, score: 11, e: 0.95
episode: 3/100, score: 27, e: 0.72
episode: 4/100, score: 28, e: 0.55
episode: 5/100, score: 8, e: 0.5
episode: 6/100, score: 22, e: 0.4
episode: 7/100, score: 16, e: 0.34
episode: 8/100, score: 21, e: 0.28
episode: 9/100, score: 8, e: 0.26
episode: 10/100, score: 9, e: 0.24
episode: 11/100, score: 9, e: 0.21
episode: 12/100, score: 10, e: 0.19
episode: 13/100, score: 16, e: 0.17
episode: 14/100, score: 21, e: 0.13
episode: 15/100, score: 28, e: 0.1
episode: 16/100, score: 26, e: 0.078
episode: 17/100, score: 37, e: 0.054
episode: 18/100, score: 24, e: 0.042
episode: 19/100, score: 16, e: 0.036
episode: 20/100, score: 27, e: 0.027
episode: 21/100, score: 42, e: 0.018
episode: 22/100, score: 10, e: 0.016
episode: 23/100, score: 10, e: 0.015
episode: 24/100, score: 9, e: 0.013
episode: 25/100, score: 11, e: 0.012
episode: 26/100, score: 8, e: 0.011
episode: 27/100, score: 8, e: 0.01
episode: 28/100, score: 9, e: 0.0099
episode: 29/100, score: 9, e: 0.0099
episode: 30/100, score: 8, e: 0.0099
episode: 31/100, score: 49, e: 0.0099
episode: 32/100, score: 37, e: 0.0099
episode: 33/100, score: 25, e: 0.0099
episode: 34/100, score: 9, e: 0.0099
episode: 35/100, score: 45, e: 0.0099
episode: 36/100, score: 53, e: 0.0099
episode: 37/100, score: 67, e: 0.0099
episode: 38/100, score: 50, e: 0.0099
episode: 39/100, score: 129, e: 0.0099
episode: 40/100, score: 65, e: 0.0099
episode: 41/100, score: 66, e: 0.0099
episode: 42/100, score: 54, e: 0.0099
episode: 43/100, score: 51, e: 0.0099
episode: 44/100, score: 52, e: 0.0099
episode: 45/100, score: 108, e: 0.0099
episode: 46/100, score: 102, e: 0.0099
episode: 47/100, score: 58, e: 0.0099
episode: 48/100, score: 117, e: 0.0099
episode: 49/100, score: 102, e: 0.0099
episode: 50/100, score: 61, e: 0.0099
episode: 51/100, score: 124, e: 0.0099
episode: 52/100, score: 93, e: 0.0099
episode: 53/100, score: 116, e: 0.0099
episode: 54/100, score: 70, e: 0.0099
episode: 55/100, score: 85, e: 0.0099
episode: 56/100, score: 93, e: 0.0099
episode: 57/100, score: 56, e: 0.0099
episode: 58/100, score: 70, e: 0.0099
episode: 59/100, score: 130, e: 0.0099
episode: 60/100, score: 97, e: 0.0099
episode: 61/100, score: 99, e: 0.0099
episode: 62/100, score: 190, e: 0.0099
episode: 63/100, score: 137, e: 0.0099
episode: 64/100, score: 156, e: 0.0099
episode: 65/100, score: 95, e: 0.0099
episode: 66/100, score: 70, e: 0.0099
episode: 67/100, score: 84, e: 0.0099
episode: 68/100, score: 75, e: 0.0099
episode: 69/100, score: 118, e: 0.0099
episode: 70/100, score: 81, e: 0.0099
episode: 71/100, score: 136, e: 0.0099
episode: 72/100, score: 134, e: 0.0099
episode: 73/100, score: 98, e: 0.0099
episode: 74/100, score: 112, e: 0.0099
episode: 75/100, score: 71, e: 0.0099
episode: 76/100, score: 95, e: 0.0099
episode: 77/100, score: 104, e: 0.0099
episode: 78/100, score: 109, e: 0.0099
episode: 79/100, score: 93, e: 0.0099
episode: 80/100, score: 81, e: 0.0099
episode: 81/100, score: 123, e: 0.0099
episode: 82/100, score: 245, e: 0.0099
episode: 83/100, score: 149, e: 0.0099
episode: 84/100, score: 107, e: 0.0099
episode: 85/100, score: 192, e: 0.0099
episode: 86/100, score: 499, e: 0.0099
episode: 87/100, score: 246, e: 0.0099
episode: 88/100, score: 143, e: 0.0099
episode: 89/100, score: 235, e: 0.0099
episode: 90/100, score: 169, e: 0.0099
episode: 91/100, score: 134, e: 0.0099
episode: 92/100, score: 169, e: 0.0099
episode: 93/100, score: 192, e: 0.0099
episode: 94/100, score: 174, e: 0.0099
episode: 95/100, score: 63, e: 0.0099
episode: 96/100, score: 206, e: 0.0099
episode: 97/100, score: 259, e: 0.0099
episode: 98/100, score: 20, e: 0.0099
episode: 99/100, score: 162, e: 0.0099