From 8c3a77f0cb1383043a80e314aa6901dc3f9a233f Mon Sep 17 00:00:00 2001 From: meliani09 Date: Sun, 11 Mar 2018 19:49:10 +0100 Subject: [PATCH 1/2] Project submission --- Meliani/FlappyAgent.py | 12 +++++ Meliani/best_model.dqf | Bin 0 -> 93072 bytes Meliani/q_learn_state.py | 95 +++++++++++++++++++++++++++++++++++++++ Meliani/run.py | 29 ++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 Meliani/FlappyAgent.py create mode 100644 Meliani/best_model.dqf create mode 100644 Meliani/q_learn_state.py create mode 100644 Meliani/run.py diff --git a/Meliani/FlappyAgent.py b/Meliani/FlappyAgent.py new file mode 100644 index 0000000..2d5d797 --- /dev/null +++ b/Meliani/FlappyAgent.py @@ -0,0 +1,12 @@ +import numpy as np +from keras.models import Sequential, load_model +model = load_model("best_model.dqf") +def FlappyPolicy(state, screen): + q = model.predict(np.array(list(state.values())).reshape(1,len(state))) +# q = self.model.predict(screen.reshape(1, screen.shape[0], screen.shape[1], screen.shape[2])) +# print(q) + + return(np.argmax(q)*119) +# return np.random.randint(0,1)*119 + + diff --git a/Meliani/best_model.dqf b/Meliani/best_model.dqf new file mode 100644 index 0000000000000000000000000000000000000000..022ac94479152ea4b60cdcd05bb803bef80bbb5d GIT binary patch literal 93072 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 MbMd(Szak$01wR*de*gdg literal 0 HcmV?d00001 diff --git a/Meliani/q_learn_state.py b/Meliani/q_learn_state.py new file mode 100644 index 0000000..ec4bb27 --- /dev/null +++ b/Meliani/q_learn_state.py @@ -0,0 +1,95 @@ +import numpy as np +from ple.games.flappybird import FlappyBird +from ple import PLE +import numpy as np +from keras import optimizers +from keras.models import Sequential, load_model +from keras.layers.core import Dense, Dropout, Activation +from keras.optimizers import RMSprop, sgd +from keras.layers.recurrent import LSTM +import numpy as np +import random +import sys +from sklearn.preprocessing import StandardScaler as scl +import time +model = Sequential() + +file_path = "test_part_" + + +model.add(Dense(512, init='lecun_uniform', input_shape=(8,))) + +model.add(Activation('relu')) +model.add(Dense(2, init='lecun_uniform')) +model.add(Activation('linear')) +model.compile(loss='mse', optimizer=optimizers.Adam(lr=1e-4)) + +gamma = 0.99 # discount factor +epsilon = 1 # epsilon-greddy +batchSize = 256 # mini batch size + +jeu = FlappyBird() +p= PLE(jeu, fps=30, frame_skip=1, num_steps=1,force_fps=True, display_screen=True) +p.init() + +i=0 + +while (True): + p.reset_game() + state = jeu.getGameState() + state = np.array(list(state.values())) + while(not jeu.game_over()): + + + + qval = model.predict(state.reshape(1,len(state)), batch_size=batchSize) #Learn Q (Q-learning) / model initialise avant (neural-network) + if (random.random() < epsilon): # exploration exploitation strategy + action = np.random.randint(0,2) + else: #choose best action from Q(s,a) values + qval_av_action = [-9999]*2 + + for ac in range(0,2): + qval_av_action[ac] = qval[0][ac] + action = (np.argmax(qval_av_action)) + #Take action, observe new state S' + #Observe reward + reward = p.act(119*action) + if reward == 1: + reaward = 1 + elif reward == -5: + reward = -500 + new_state = jeu.getGameState() + new_state = np.array(list(new_state.values())) + # choose new reward values + + + #Get max_Q(S',a) + newQ = model.predict(new_state.reshape(1,len(state)), batch_size=batchSize) + maxQ = np.max(newQ) + y = np.zeros((1,2)) + y[:] = qval[:] + if reward != -5: #non-terminal state + update = (reward + gamma * maxQ) + else: + update = reward + y[0][action] = update + print("Game #: %s" % (i,)) + model.fit(state.reshape(1, len(state)), y, batch_size=batchSize, nb_epoch=2, verbose=0) + state = new_state + + + # update exploitation / exploration strategy + if epsilon > 0.1: + epsilon -= (1.0/10000) + + # save the model every 1000 epochs + if i==100: + model.save(file_path+"0.dqf") + if i%1000 == 0 and i!=0: + model.save(file_path+str(i/1000)+".dqf") + time.sleep(60) + if i == 100000: + break + + i=i+1 +model.save(file_path+"final.dqf") diff --git a/Meliani/run.py b/Meliani/run.py new file mode 100644 index 0000000..750053b --- /dev/null +++ b/Meliani/run.py @@ -0,0 +1,29 @@ +# You're not allowed to change this file +from ple.games.flappybird import FlappyBird +from ple import PLE +import numpy as np +from FlappyAgent import FlappyPolicy + +game = FlappyBird() # use "fancy" for full background, random bird color and random pipe color, use "fixed" (default) for black background and constant bird and pipe colors. +p = PLE(game, fps=30, frame_skip=1, num_steps=1, force_fps=True, display_screen=True) +# Note: if you want to see you agent act in real time, set force_fps to False. But don't use this setting for learning, just for display purposes. + +p.init() +reward = 0.0 + +nb_games = 100 +cumulated = np.zeros((nb_games)) + +for i in range(nb_games): + p.reset_game() + + while(not p.game_over()): + state = game.getGameState() + screen = p.getScreenRGB() + action=FlappyPolicy(state, screen) ### Your job is to define this function. + + reward = p.act(action) + cumulated[i] = cumulated[i] + reward + +average_score = np.mean(cumulated) +max_score = np.max(cumulated) From ac078d52280694b709e2fad95b39a0bab22931a3 Mon Sep 17 00:00:00 2001 From: meliani09 Date: Sun, 11 Mar 2018 20:07:01 +0100 Subject: [PATCH 2/2] update --- Meliani/run.py | 2 +- README.md | 61 +++++++++++---------------------------- RandomBird/FlappyAgent.py | 9 ------ RandomBird/run.py | 29 ------------------- 4 files changed, 18 insertions(+), 83 deletions(-) delete mode 100644 RandomBird/FlappyAgent.py delete mode 100644 RandomBird/run.py diff --git a/Meliani/run.py b/Meliani/run.py index 750053b..cbaa25d 100644 --- a/Meliani/run.py +++ b/Meliani/run.py @@ -5,7 +5,7 @@ from FlappyAgent import FlappyPolicy game = FlappyBird() # use "fancy" for full background, random bird color and random pipe color, use "fixed" (default) for black background and constant bird and pipe colors. -p = PLE(game, fps=30, frame_skip=1, num_steps=1, force_fps=True, display_screen=True) +p = PLE(game, fps=30, frame_skip=1, num_steps=1, force_fps=False, display_screen=True) # Note: if you want to see you agent act in real time, set force_fps to False. But don't use this setting for learning, just for display purposes. p.init() diff --git a/README.md b/README.md index ce4894f..62fddea 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,22 @@ # RL challenge -Your challenge is to learn to play [Flappy Bird](https://en.wikipedia.org/wiki/Flappy_Bird)! +My challenge is to learn to play [Flappy Bird](https://en.wikipedia.org/wiki/Flappy_Bird)! Flappybird is a side-scrolling game where the agent must successfully nagivate through gaps between pipes. Only two actions in this game: at each time step, either you click and the bird flaps, or you don't click and gravity plays its role. -There are three levels of difficulty in this challenge: -- Learn an optimal policy with hand-crafted features -- Learn an optimal policy with raw variables -- Learn an optimal policy from pixels. - -# Your job - -Your job is to: -
    -
  1. fork the project at [https://github.com/SupaeroDataScience/RLchallenge](https://github.com/SupaeroDataScience/RLchallenge) on your own github (yes, you'll need one). -
  2. rename the "RandomBird" folder into "YourLastName". -
  3. modify 'FlappyPolicy.py' in order to implement the function `FlappyPolicy(state,screen)` used below. You're free to add as many extra files as you need. However, you're not allowed to change 'run.py'. -
  4. you are encouraged, however, to copy-paste the contents of 'run.py' as a basis for your learning algorithm. -
  5. add any useful material (comments, text files, analysis, etc.) -
  6. make a pull request on the original repository when you're done (please don't make a pull request before you think your work is ready to be merged on the original repository). -
- -**All the files you create must be placed inside the directory "YourLastName".** - -`FlappyPolicy(state,screen)` takes both the game state and the screen as input. It gives you the choice of what you base your policy on: -
    -
  • If you use the state variables vector and perform some handcrafted feature engineering, you're playing in the "easy" league. If your agent reaches an average score of 15, you're sure to have a grade of at least 10/20 (possibly more if you implement smart stuff and/or provide a smart discussion). -
  • If you use the state variables vector without altering it (no feature engineering), you're playing in the "good job" league. If your agent reaches an average score of 15, you're sure to have at least 15/20 (possibly more if you implement smart stuff and/or provide a smart discussion). -
  • If your agent uses only the raw pixels from the image, you're playing in the "Deepmind" league. If your agent reaches an average score of 15, you're sure to have at the maximum grade (plus possible additional benefits). -
- -Recall that the evaluation will start by running 'run.py' on our side, so 'FlappyPolicy' should call an already trained policy, otherwise we will be evaluating your agent during learning, which is not the goal. Of course, we will check your learning code and we will greatly appreciate insightful comments and additional material like (documentation, discussion, comparisons, perspectives, state-of-the-art...). - -# Installation - -You will need to install a few things to get started. -First, you will need PyGame. - -``` -pip install pygame -``` - -And you will need [PLE (PyGame Learning Environment)](https://github.com/ntasfi/PyGame-Learning-Environment) which is already present in this repository (the above link is only given for your information). To install it: -``` -cd PyGame-Learning-Environment/ -pip install -e . -``` -Note that this version of FlappyBird in PLE has been slightly changed to make the challenge a bit easier: the background is turned to plain black, the bird and pipe colors are constant (red and green respectively). + + +# DEEP Q-LEARNING + +For this project, I decided to use deep Q-learning. For that, I used Keras and Tensorflow libraries. I worked on the state vector and created a neural network to learn the Q-function. +The Neural Network is only one layer. But we already know that this is theoretically enough to reproduce any mathematical function. + +A lot of the project time has been spent on choosing the right optimizers, loss functions and activation functions. These seem to be very important to build a good neural network. + +Moreover, the reward, although it sounded at first counter-intuitive, but it played a very big role on the quality of the learning. a very big difference in rewards leads to much better results. + +# RESULTS + +The model I kept, is a simple one-layer model, with no experience replay. It hits regularly 30 average score and can peak up to 190 of score. + + diff --git a/RandomBird/FlappyAgent.py b/RandomBird/FlappyAgent.py deleted file mode 100644 index 9f3ec84..0000000 --- a/RandomBird/FlappyAgent.py +++ /dev/null @@ -1,9 +0,0 @@ -import numpy as np - -def FlappyPolicy(state, screen): - action=None - if(np.random.randint(0,2)<1): - action=119 - return action - - diff --git a/RandomBird/run.py b/RandomBird/run.py deleted file mode 100644 index 39b5801..0000000 --- a/RandomBird/run.py +++ /dev/null @@ -1,29 +0,0 @@ -# You're not allowed to change this file -from ple.games.flappybird import FlappyBird -from ple import PLE -import numpy as np -from FlappyAgent import FlappyPolicy - -game = FlappyBird(graphics="fixed") # use "fancy" for full background, random bird color and random pipe color, use "fixed" (default) for black background and constant bird and pipe colors. -p = PLE(game, fps=30, frame_skip=1, num_steps=1, force_fps=False, display_screen=True) -# Note: if you want to see you agent act in real time, set force_fps to False. But don't use this setting for learning, just for display purposes. - -p.init() -reward = 0.0 - -nb_games = 100 -cumulated = np.zeros((nb_games)) - -for i in range(nb_games): - p.reset_game() - - while(not p.game_over()): - state = game.getGameState() - screen = p.getScreenRGB() - action=FlappyPolicy(state, screen) ### Your job is to define this function. - - reward = p.act(action) - cumulated[i] = cumulated[i] + reward - -average_score = np.mean(cumulated) -max_score = np.max(cumulated)