distinguish learning and episodic learning, enable fast-learning without drawing every step to reduce lag

- repainting every step on no time delay will certainly freeze the app, so "fast-learning" will disable it, only refreshing current episode label
- Added new abstract class "Episodic Learning". Maybe just use an interface instead?! Important because TD learning is not episodic, needs another way to represent the rewards received (maybe mean of last X rewards or sth)
- Opening two JFrames, one with learning infos and one with environment
This commit is contained in:
2019-12-21 00:23:09 +01:00
parent 7db5a2af3b
commit 34e7e3fdd6
14 changed files with 188 additions and 75 deletions
+29 -5
View File
@@ -1,7 +1,8 @@
package core.gui;
import core.algo.Episodic;
import core.algo.Learning;
import core.controller.ViewListener;
import core.listener.ViewListener;
import core.policy.EpsilonPolicy;
import javax.swing.*;
@@ -11,39 +12,62 @@ public class LearningInfoPanel extends JPanel {
private JLabel policyLabel;
private JLabel discountLabel;
private JLabel epsilonLabel;
private JLabel episodeLabel;
private JSlider epsilonSlider;
private JLabel delayLabel;
private JSlider delaySlider;
private JButton toggleFastLearningButton;
private boolean fastLearning;
public LearningInfoPanel(Learning learning, ViewListener viewListener){
this.learning = learning;
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
policyLabel = new JLabel();
discountLabel = new JLabel();
epsilonLabel = new JLabel();
delayLabel = new JLabel();
if(learning instanceof Episodic){
episodeLabel = new JLabel();
add(episodeLabel);
}
delaySlider = new JSlider(0,1000, learning.getDelay());
delaySlider.addChangeListener(e -> viewListener.onDelayChange(delaySlider.getValue()));
add(policyLabel);
add(discountLabel);
if(learning.getPolicy() instanceof EpsilonPolicy){
epsilonLabel = new JLabel();
epsilonSlider = new JSlider(0, 100, (int)((EpsilonPolicy)learning.getPolicy()).getEpsilon() * 100);
epsilonSlider.addChangeListener(e -> viewListener.onEpsilonChange(epsilonSlider.getValue() / 100f));
add(epsilonLabel);
add(epsilonSlider);
}
toggleFastLearningButton = new JButton("Enable fast-learn");
fastLearning = false;
toggleFastLearningButton.addActionListener(e->{
fastLearning = !fastLearning;
delaySlider.setEnabled(!fastLearning);
epsilonSlider.setEnabled(!fastLearning);
viewListener.onFastLearnChange(fastLearning);
});
add(delayLabel);
add(delaySlider);
add(toggleFastLearningButton);
refreshLabels();
setVisible(true);
}
public void refreshLabels(){
public void refreshLabels() {
policyLabel.setText("Policy: " + learning.getPolicy().getClass());
discountLabel.setText("Discount factor: " + learning.getDiscountFactor());
if(learning.getPolicy() instanceof EpsilonPolicy){
epsilonLabel.setText("Exploration (Epsilon): " + ((EpsilonPolicy)learning.getPolicy()).getEpsilon());
if(learning instanceof Episodic){
episodeLabel.setText("Episode: " + ((Episodic)(learning)).getCurrentEpisode());
}
if (learning.getPolicy() instanceof EpsilonPolicy) {
epsilonLabel.setText("Exploration (Epsilon): " + ((EpsilonPolicy) learning.getPolicy()).getEpsilon());
epsilonSlider.setValue((int)(((EpsilonPolicy) learning.getPolicy()).getEpsilon() * 100));
}
delayLabel.setText("Delay (ms): " + learning.getDelay());
delaySlider.setValue(learning.getDelay());
toggleFastLearningButton.setText(fastLearning ? "Disable fast-learning" : "Enable fast-learning");
}
}
+63 -25
View File
@@ -1,7 +1,8 @@
package core.gui;
import core.Environment;
import core.algo.Learning;
import core.controller.ViewListener;
import core.listener.ViewListener;
import core.listener.LearningListener;
import lombok.Getter;
import org.knowm.xchart.QuickChart;
@@ -10,27 +11,31 @@ import org.knowm.xchart.XYChart;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class View<A extends Enum> implements LearningListener {
private Learning<A> learning;
private Environment<A> environment;
@Getter
private XYChart chart;
private XYChart rewardChart;
@Getter
private LearningInfoPanel learningInfoPanel;
@Getter
private JFrame mainFrame;
private JFrame environmentFrame;
private XChartPanel<XYChart> rewardChartPanel;
private ViewListener viewListener;
private boolean drawEveryStep;
public View(Learning<A> learning, ViewListener viewListener){
public View(Learning<A> learning, Environment<A> environment, ViewListener viewListener) {
this.learning = learning;
this.environment = environment;
this.viewListener = viewListener;
this.initMainFrame();
drawEveryStep = true;
SwingUtilities.invokeLater(this::initMainFrame);
}
private void initMainFrame(){
private void initMainFrame() {
mainFrame = new JFrame();
mainFrame.setPreferredSize(new Dimension(1280, 720));
mainFrame.setLayout(new BorderLayout());
@@ -44,29 +49,40 @@ public class View<A extends Enum> implements LearningListener {
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setVisible(true);
if (environment instanceof Visualizable) {
environmentFrame = new JFrame() {
{
add(((Visualizable) environment).visualize());
pack();
setVisible(true);
}
};
}
}
private void initLearningInfoPanel(){
private void initLearningInfoPanel() {
learningInfoPanel = new LearningInfoPanel(learning, viewListener);
}
private void initRewardChart(){
chart =
private void initRewardChart() {
rewardChart =
QuickChart.getChart(
"Rewards per Episode",
"Sum of Rewards per Episode",
"Episode",
"Reward",
"randomWalk",
new double[] {0},
new double[] {0});
chart.getStyler().setLegendVisible(true);
chart.getStyler().setXAxisTicksVisible(true);
rewardChartPanel = new XChartPanel<>(chart);
rewardChartPanel.setPreferredSize(new Dimension(300,300));
"rewardHistory",
new double[]{0},
new double[]{0});
rewardChart.getStyler().setLegendVisible(true);
rewardChart.getStyler().setXAxisTicksVisible(true);
rewardChartPanel = new XChartPanel<>(rewardChart);
rewardChartPanel.setPreferredSize(new Dimension(300, 300));
}
public void showState(Visualizable state){
new JFrame(){
public void showState(Visualizable state) {
new JFrame() {
{
JComponent stateComponent = state.visualize();
setPreferredSize(new Dimension(stateComponent.getWidth(), stateComponent.getHeight()));
@@ -76,25 +92,47 @@ public class View<A extends Enum> implements LearningListener {
};
}
public void updateRewardGraph(List<Double> rewardHistory){
chart.updateXYSeries("randomWalk", null, rewardHistory, null);
public void setDrawEveryStep(boolean drawEveryStep){
this.drawEveryStep = drawEveryStep;
}
public void updateRewardGraph(List<Double> rewardHistory) {
rewardChart.updateXYSeries("rewardHistory", null, rewardHistory, null);
rewardChartPanel.revalidate();
rewardChartPanel.repaint();
}
public void updateLearningInfoPanel(){
public void updateLearningInfoPanel() {
this.learningInfoPanel.refreshLabels();
}
@Override
public void onEpisodeEnd(List<Double> rewardHistory) {
SwingUtilities.invokeLater(()->{
updateRewardGraph(rewardHistory);
});
SwingUtilities.invokeLater(() ->{
if(drawEveryStep){
updateRewardGraph(rewardHistory);
}
updateLearningInfoPanel();
});
}
@Override
public void onEpisodeStart() {
if(drawEveryStep) {
SwingUtilities.invokeLater(this::repaintEnvironment);
}
}
@Override
public void onStepEnd() {
if(drawEveryStep){
SwingUtilities.invokeLater(this::repaintEnvironment);
}
}
private void repaintEnvironment(){
if (environmentFrame != null) {
environmentFrame.repaint();
}
}
}