From fddcb879037a95c41adf21768c1375a70e1e6b24 Mon Sep 17 00:00:00 2001 From: Rododindron <35739489+Rododindron@users.noreply.github.com> Date: Sun, 11 Mar 2018 23:21:02 +0100 Subject: [PATCH] Add files via upload --- RandomBird/FlappyAgent.py | 34 +++++++-- RandomBird/dqn_3_1.dqf | Bin 0 -> 85952 bytes RandomBird/q_learning.py | 150 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 RandomBird/dqn_3_1.dqf create mode 100644 RandomBird/q_learning.py diff --git a/RandomBird/FlappyAgent.py b/RandomBird/FlappyAgent.py index 9f3ec84..acc4320 100644 --- a/RandomBird/FlappyAgent.py +++ b/RandomBird/FlappyAgent.py @@ -1,9 +1,33 @@ import numpy as np +from keras.models import Sequential +from keras.layers import Dense +from keras import optimizers -def FlappyPolicy(state, screen): - action=None - if(np.random.randint(0,2)<1): - action=119 - return action +dqn = Sequential() +# 1st layer +dqn.add(Dense(units=500, kernel_initializer='lecun_uniform', activation="relu", input_dim = 8)) +# output layer +dqn.add(Dense(units=2, kernel_initializer='lecun_uniform', activation="linear")) + +dqn.compile(loss='mse', optimizer=optimizers.Adam(1e-4)) + +dqn.load_weights("dqn_3_1.dqf") +batchSize = 256 +actions = [None, 119] +def process_state(state): + """ Renvoie l'état sous forme de liste """ + return [state['player_y'], state['player_vel'], + state['next_pipe_dist_to_player'], state['next_pipe_top_y'], state['next_pipe_bottom_y'], + state['next_next_pipe_dist_to_player'], state['next_next_pipe_top_y'], state['next_next_pipe_bottom_y']] + +def greedy_action(network, state_x): + """ Renvoie la meilleure action possible """ + Q = network.predict(np.array(state_x).reshape(1, len(state_x)), batch_size=batchSize) + return np.argmax(Q) + +def FlappyPolicy(state, screen): + state = process_state(state) + action = greedy_action(dqn, state) + return actions[action] \ No newline at end of file diff --git a/RandomBird/dqn_3_1.dqf b/RandomBird/dqn_3_1.dqf new file mode 100644 index 0000000000000000000000000000000000000000..fce7444ac0791b05f8d5ab2742d6e71738c270ea GIT binary patch literal 85952 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 literal 0 HcmV?d00001 diff --git a/RandomBird/q_learning.py b/RandomBird/q_learning.py new file mode 100644 index 0000000..46518ee --- /dev/null +++ b/RandomBird/q_learning.py @@ -0,0 +1,150 @@ +"""--------------------------------""" +""" Initialisation de Flappy Bird """ +"""--------------------------------""" + +from ple.games.flappybird import FlappyBird +from ple import PLE + +# Définition des actions +actions = [None, 119] + +game = FlappyBird(graphics="fixed") +p = PLE(game, fps=30, frame_skip=1, num_steps=1, force_fps=True, display_screen=True) +p.init() + + +"""----------------------------""" +""" Création du Deep Q-Network """ +"""----------------------------""" + +from keras.models import Sequential +from keras.layers import Dense +from keras import optimizers + +dqn = Sequential() +# 1st layer +dqn.add(Dense(units=500, kernel_initializer='lecun_uniform', activation="relu", input_dim = 8)) +# output layer +dqn.add(Dense(units=2, kernel_initializer='lecun_uniform', activation="linear")) + +dqn.compile(loss='mse', optimizer=optimizers.Adam(1e-4)) + +dqn.load_weights("dqn_2_1.dqf") +#dqn.load_weights("dqn_0_3.dqf") + +"""-----------------------------------------""" +""" Définition de quelques fonctions utiles """ +"""-----------------------------------------""" + +import numpy as np + +def process_state(state): + """ Renvoie l'état sous forme de liste """ + return [state['player_y'], state['player_vel'], + state['next_pipe_dist_to_player'], state['next_pipe_top_y'], state['next_pipe_bottom_y'], + state['next_next_pipe_dist_to_player'], state['next_next_pipe_top_y'], state['next_next_pipe_bottom_y']] + +def epsilon(step): + """ Utile à la décision de l'action """ + #if step<1e6: + # return 1.-step*9e-7 + #return .1 + return 0.01 + +def clip_reward(r): + """ Change la valeur de reward """ + rr=0 + if r > 0: + rr = 1 + if r < 0: + rr = -1000 + return rr + +def greedy_action(network, state_x): + """ Renvoie la meilleure action possible """ + Q = network.predict(np.array(state_x).reshape(1, len(state_x)), batch_size=batchSize) + return np.argmax(Q) + +def MCeval(network, games, gamma): + """ Evaluation du réseau de neurones """ + scores = np.zeros(games) + for i in range(games): + p.reset_game() + state_x = process_state(game.getGameState()) + step = -1 + while not game.game_over(): + step += 1 + action = greedy_action(network, state_x) + reward = p.act(actions[action]) + state_y = process_state(game.getGameState()) + scores[i] = scores[i] + reward + state_x = state_y + return np.mean(scores) + + +"""----------------------""" +""" Apprentissage du DQN """ +"""----------------------""" + +# Variables utiles +total_games = 10000 +gamma = 0.99 +step = 0 +batchSize = 256 + +# Définition des évaluations +evaluation_period = 300 +nb_epochs = total_games // evaluation_period +epoch=-1 +scoreMC = np.zeros((nb_epochs)) + +# Enregistrement du réseau de neurones +filename = "dqn_3_" + + +"""-----------------""" +""" Deep Q-Learning """ +"""-----------------""" + +for id_game in range(total_games): + if id_game % evaluation_period == 0: + epoch += 1 + scoreMC[epoch] = MCeval(dqn, 50, gamma) + dqn.save(filename + str(epoch) + ".dqf") + print(">>> Eval n°%d | score = %f" % (epoch, scoreMC[epoch])) + p.reset_game() # Nouvelle partie + state_x = process_state(game.getGameState()) + id_frame = 0 + score = 0 + alea = 0 + while not game.game_over(): + id_frame += 1 + step += 1 + ## Choisit l'action à effectuer : 0 ou 1 + if np.random.rand() < epsilon(step): # Action au hasard + alea += 1 + action = np.random.choice([0, 1]) + else: # Meilleure action possible + action = greedy_action(dqn, state_x) + ## Joue l'action et observe le gain et l'état suivant + reward = p.act(actions[action]) + reward = clip_reward(reward) + state_y = process_state(game.getGameState()) + ## Mise à jour de Q + QX = dqn.predict(np.array(state_x).reshape(1, len(state_x)), batch_size=batchSize) + y = np.zeros(2) + y[:] = QX[:] + if not game.game_over(): + score += reward + QY = dqn.predict(np.array(state_y).reshape(1, len(state_y)), batch_size=batchSize) + QYmax = np.max(QY) + update = reward + gamma * QYmax + else: + update = reward + y[action] = update + dqn.fit(np.array(state_x).reshape(1, len(state_x)), np.array(y).reshape(1, len(y)), nb_epoch = 3, verbose = 0) + state_x = state_y + print(">>> game n°%d | score = %d | nb_steps = %d | %% aléa = %f%%" % (id_game, score, id_frame, alea/id_frame*100)) + +for i in nb_epochs: + print("epoch n°%d | score = %f" % (i, scoreMC[i])) \ No newline at end of file