add dino jumping environment, deterministic/reproducable behaviour and save-and-load feature

- add feature to save and load learning progress (Q-Table) and current episode count
- episode end is now purely decided by environment instead of monte carlo algo capping it on 10 actions
- using linkedHashMap on all locations to ensure deterministic behaviour
- fixed major RNG issue to reproduce algorithmic behaviour
- clearing rewardHistory, to only save the last 10k rewards
- added google dino jump environment
This commit is contained in:
2019-12-22 23:33:56 +01:00
parent b1246f62cc
commit 5a4e380faf
24 changed files with 415 additions and 56 deletions
@@ -1,8 +1,6 @@
package core.controller;
import core.DiscreteActionSpace;
import core.Environment;
import core.ListDiscreteActionSpace;
import core.*;
import core.algo.EpisodicLearning;
import core.algo.Learning;
import core.algo.Method;
@@ -14,6 +12,7 @@ import core.listener.ViewListener;
import core.policy.EpsilonPolicy;
import javax.swing.*;
import java.io.*;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -23,10 +22,12 @@ public class RLController<A extends Enum> implements ViewListener, LearningListe
protected Learning<A> learning;
protected DiscreteActionSpace<A> discreteActionSpace;
protected LearningView learningView;
private int delay;
private int nrOfEpisodes;
private Method method;
private int prevDelay;
private int delay = LearningConfig.DEFAULT_DELAY;
private float discountFactor = LearningConfig.DEFAULT_DISCOUNT_FACTOR;
private float epsilon = LearningConfig.DEFAULT_EPSILON;
private boolean fastLearning;
private boolean currentlyLearning;
private ExecutorService learningExecutor;
@@ -36,6 +37,7 @@ public class RLController<A extends Enum> implements ViewListener, LearningListe
learningExecutor = Executors.newSingleThreadExecutor();
}
public void start(){
if(environment == null || discreteActionSpace == null || method == null){
throw new RuntimeException("Set environment, discreteActionSpace and method before calling .start()");
@@ -43,7 +45,7 @@ public class RLController<A extends Enum> implements ViewListener, LearningListe
switch (method){
case MC_ONPOLICY_EGREEDY:
learning = new MonteCarloOnPolicyEGreedy<>(environment, discreteActionSpace, delay);
learning = new MonteCarloOnPolicyEGreedy<>(environment, discreteActionSpace, discountFactor, epsilon, delay);
break;
case TD_ONPOLICY:
break;
@@ -76,6 +78,44 @@ public class RLController<A extends Enum> implements ViewListener, LearningListe
}
}
@Override
public void onLoadState(String fileName) {
FileInputStream fis;
ObjectInput in;
try {
fis = new FileInputStream(fileName);
in = new ObjectInputStream(fis);
SaveState<A> saveState = (SaveState<A>) in.readObject();
learning.setStateActionTable(saveState.getStateActionTable());
if(learning instanceof EpisodicLearning){
((EpisodicLearning) learning).setCurrentEpisode(saveState.getCurrentEpisode());
}
in.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void onSaveState(String fileName) {
FileOutputStream fos;
ObjectOutputStream out;
try{
fos = new FileOutputStream(fileName);
out = new ObjectOutputStream(fos);
int currentEpisode;
if(learning instanceof EpisodicLearning){
currentEpisode = ((EpisodicLearning) learning).getCurrentEpisode();
}else{
currentEpisode = 0;
}
out.writeObject(new SaveState<>(learning.getStateActionTable(), currentEpisode));
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
@Override
public void onEpsilonChange(float epsilon) {
if(learning.getPolicy() instanceof EpsilonPolicy){
@@ -169,4 +209,13 @@ public class RLController<A extends Enum> implements ViewListener, LearningListe
this.nrOfEpisodes = nrOfEpisodes;
return this;
}
public RLController<A> setDiscountFactor(float discountFactor){
this.discountFactor = discountFactor;
return this;
}
public RLController<A> setEpsilon(float epsilon){
this.epsilon = epsilon;
return this;
}
}