header github

This commit is contained in:
Thibault Neveu
2018-06-16 15:04:54 +01:00
parent 436db9fd06
commit 545dc65798
23 changed files with 186 additions and 135 deletions
+2
View File
@@ -3,6 +3,7 @@
var fs = require('fs');
const express = require('express');
var path = require("path");
var cors = require('cors');
function fromDir(startPath,filter){
var files_list = [];
@@ -22,6 +23,7 @@ function get_path(file){
}
const app = express();
app.use(cors());
app.use("/dist", express.static(path.join(__dirname, "dist/")));
app.use("/public", express.static(path.join(__dirname, "webapp/public/")));
+9 -9
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -9,6 +9,7 @@
"author": "Thibault Neveu",
"license": "ISC",
"dependencies": {
"cors": "^2.8.4",
"express": "^4.16.3",
"pixi.js": "^4.8.1"
}
+3 -3
View File
@@ -9,12 +9,12 @@ if (levelObject){
}
// Create the editor (canvasID, levelUrl)
var editor = new metacar.editor("editor", levelToLoad);
var editor = new metacar.editor("editor", "http://localhost:3000/public/levels/levelGet.json");
editor.load().then(() => {
editor.addEvent("save", (content) => {
console.log(content);
// Put the object into storage
localStorage.setItem('mylevel.json', JSON.stringify(content));
window.open("/test_editor.html");
}, {download: false, name: "level0.json"});
}, {download: false, name: "level.json"});
});
+16 -9
View File
@@ -3,9 +3,7 @@ let levelUrl = metacar.level.level0;
// Create the environement (canvasID, levelUrl)
var env = new metacar.env("canvas", levelUrl);
console.log(env);
env.setAgentMotion(metacar.motion.BasicMotion, {rotationStep: 0.1});
env.setAgentMotion(metacar.motion.BasicMotion, {rotationStep: 0.25});
env.setAgentLidar({pts: 2, width: 1, height: 1, pos: 1});
env.carsMoving(false);
@@ -17,12 +15,19 @@ env.loop(() => {
displayState("realtime_viewer", state, 200, 200);
let scores = agent.getStateValues(state);
let reward = env.getLastReward();
//displayScores("realtime_viewer", scores, reward, ["Top", "Left", "Right"]);
})
displayScores("realtime_viewer", scores, reward, ["Top", "Left", "Right"]);
});
env.load().then(() => {
// The level is loaded. Add listernes
env.addEvent("train", () => agent.train());
env.addEvent("train", () => {
let train = confirm("The training process will freeze the tab during 1 minutes. Do you want to continue? You can also load the pre trained agent.");
if (train)
agent.train();
});
env.addEvent("play", () => agent.play());
env.addEvent("stop");
env.addEvent("reset_env", () => {
@@ -30,9 +35,11 @@ env.load().then(() => {
});
env.addEvent("save", () => agent.save());
env.addEvent("load", (content) => {
agent.restore(content);
displayQTable("q_table", agent.stateList, agent, ["Top", "Left", "Right"]);
} , {local: true});
loadJSON("http://localhost:3000/public/models/qtable/qtable.json", (content) => {
agent.restore(content);
displayQTable("q_table", agent.stateList, agent, ["Top", "Left", "Right"]);
});
});
env.addEvent("custom", () => {
});
});
+9 -1
View File
@@ -3,6 +3,8 @@ let levelUrl = metacar.level.level1;
// Create the environement (canvasID, levelUrl)
var env = new metacar.env("canvas", levelUrl);
env.setAgentMotion(metacar.motion.BasicMotion, {rotationStep: 0.1});
// Create the Policy agent
var agent = new PolicyAgent(env);
@@ -16,7 +18,13 @@ env.loop(() => {
env.load().then(() => {
// The level is loaded. Add listernes
env.addEvent("train", () => agent.train());
env.addEvent("train", () => {
let train = confirm("The training process takes some time and might slow this tab. Do you want to continue? \
You can also load a pre-trained model");
if (train)
agent.train();
});
env.addEvent("play", () => agent.play());
env.addEvent("stop", () => agent.stop());
env.addEvent("reset_env", () => {
+8 -11
View File
@@ -22,7 +22,7 @@ class PolicyAgent {
Build the Value function
@weights (Object) Weights for the layer
*/
const LEARNING_RATE = 0.05;
const LEARNING_RATE = 0.01;
const value_optimizer = tf.train.adam(LEARNING_RATE);
/*
-----------------------
@@ -59,7 +59,7 @@ class PolicyAgent {
Build the policy network
@weights (Object) Weights for the layer
*/
const LEARNING_RATE = 0.05;
const LEARNING_RATE = 0.01;
this.policy_optimizer = tf.train.adam(LEARNING_RATE);
/*
-----------------------
@@ -160,7 +160,7 @@ class PolicyAgent {
// Maximum number of step per episode
this.nb_step = 800;
this.mini_batch_size = 200;
this.episodeNb = 100;
this.episodeNb = 200;
}
save(env){
@@ -175,14 +175,8 @@ class PolicyAgent {
/*
Restore the weights of the network
*/
if (window.location.href.indexOf("localhost") == -1){
this.valueModel = await tf.loadModel('https://metacar-project.com/public/models/policy/value-model-policy-agent.json');
this.policyModel = await tf.loadModel("https://metacar-project.com/public/models/policy/policy-model-policy-agent.json");
}
else{
this.valueModel = await tf.loadModel('http://localhost:3000/public/models/policy/value-model-policy-agent.json');
this.policyModel = await tf.loadModel("http://localhost:3000/public/models/policy/policy-model-policy-agent.json");
}
this.valueModel = await tf.loadModel('https://metacar-project.com/public/models/policy/value-model-policy-agent.json');
this.policyModel = await tf.loadModel("https://metacar-project.com/public/models/policy/policy-model-policy-agent.json");
}
play(){
@@ -258,6 +252,9 @@ class PolicyAgent {
st.dispose();
// Step in the environement with this action
reward = this.env.step(action);
if (reward == -1){
reward = -10;
}
}
// Size of the next batches && minibatches
const batch_size = rewards.length;
+9 -11
View File
@@ -14,9 +14,7 @@ class QTableAgent {
save(){
let save_content = JSON.stringify(this.Q);
console.log(save_content);
this.env.save(save_content, "mc_agent.json");
console.log("Q table saved");
this.env.save(save_content, "qtable.json");
}
stringStateToState(state){
@@ -37,7 +35,6 @@ class QTableAgent {
restore(content){
this.Q = {};
this.stateList = [];
content = JSON.parse(content);
for (const key in content){
var nStateToPush = this.stringStateToState(key);
var st = key.toString();
@@ -53,9 +50,6 @@ class QTableAgent {
}
}
}
console.log(this.Q);
console.log(this.stateList);
console.log("Q table loaded");
}
play(){
@@ -103,14 +97,14 @@ class QTableAgent {
}
train(){
let episode = 10000;
let episode = 2000;
let eps = 1.0;
let eps_decrease = 0.99;
let mean_reward = [];
for (let ep = 0; ep < episode; ep++) {
if (ep % 50 == 0){
eps = Math.max(0.1, eps*eps_decrease);
if (ep % 10 == 0){
eps = Math.max(0.05, eps*eps_decrease);
console.log("episode=", ep, "eps=", eps, "mean_reward", mean(mean_reward));
}
mean_reward = [];
@@ -128,11 +122,15 @@ class QTableAgent {
act2 = this.pickAction(st2, 0.);
this.createStateIfNotExist(st2);
this.createStateIfNotExist(st);
this.Q[st][act] = this.Q[st][act] + 0.05*(reward + (gamma*this.Q[st2][act2]) - this.Q[st][act]);
this.Q[st][act] = this.Q[st][act] + 0.01*(reward + (gamma*this.Q[st2][act2]) - this.Q[st][act]);
st = st2;
}
this.env.randomRoadPosition();
}
this.env.render(true);
for (let s=0; s < this.stateList.length; s++){
this.stateList[s] = this.stringStateToState(this.stateList[s]);
}
displayQTable("q_table", this.stateList, this, ["Top", "Left", "Right"]);
}
}
+22
View File
@@ -21,4 +21,26 @@ function argMax(array) {
return Math.floor(Math.random()*array.length);
}
return array.map((x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1];
}
/*
File with some usefull methods
*/
function loadJSON(url, callback) {
/*
Utils method to load a json on the server
@url: Url to the json file to load
@callback: Method to call when the json file is loaded
*/
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', url, true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == 200) {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
console.log(xobj.responseText);
callback(JSON.parse(xobj.responseText));
}
};
xobj.send(null);
}
+5 -6
View File
@@ -43,17 +43,16 @@ function displayScores(id, score, reward, labels){
container.appendChild(textContainer);
}
console.log(score);
var text = "";
for (let c = 0; c < score.length; c++){
text += labels[c] + ": <b>" + Number((parseFloat(score[c])).toFixed(2)) + "</b><br>";
text += labels[c] + ": <b>" + ((score[c])).toFixed(2) + "</b><br>";
}
if (reward){
if (reward < 0)
text += "<br><p style='color: #ee4c32'>Reward: <b>" +Number((parseFloat(reward)).toFixed(2)) + "</b></p>"
if (reward != null){
if (reward <= 0)
text += "<br><p style='color: #ee4c32'>Reward: <b>" + ((reward)).toFixed(2) + "</b></p>"
else
text += "<br><p style='color: #80bf3e'>Reward: <b>" +Number((parseFloat(reward)).toFixed(2)) + "</b></p>"
text += "<br><p style='color: #80bf3e'>Reward: <b>" + ((reward)).toFixed(2) + "</b></p>"
}
textContainer.innerHTML = text;
+9 -9
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+1 -2
View File
@@ -1,7 +1,7 @@
{
"name": "metacar",
"version": "0.0.1",
"main": "index.js",
"main": "dist/metacar.min.js",
"author": "Thibault Neveu",
"license": "MIT",
"devDependencies": {
@@ -13,7 +13,6 @@
},
"dependencies": {
"@types/pixi.js": "^4.7.5",
"express": "^4.16.3",
"pixi.js": "^4.8.0"
},
"scripts": {
-1
View File
@@ -326,7 +326,6 @@ export class AssetManger {
file.map = map;
// If the agent exist
if (this.level.agent){
console.log("enter here to create egent....");
file.agent = {
"mx": this.level.agent.core.mx,
"my": this.level.agent.core.my,
+1 -1
View File
@@ -121,7 +121,7 @@ export class Car {
this.motion.setUp(this.core, this.lidar);
this.core.rotationStep = 0.5;
}
else{
else {
this.core.rotationStep = 0.5;
}
+4 -4
View File
@@ -184,7 +184,7 @@ export const fullCity: any = {
0,
0,
0,
"",
"",
0,
0,
0,
@@ -200,7 +200,7 @@ export const fullCity: any = {
"↦",
"↔",
"↔",
"",
"",
"↔"
],
[
@@ -245,11 +245,11 @@ export const fullCity: any = {
[
0,
0,
"",
"",
0,
0,
0,
"",
"",
0,
0,
0,
+1 -27
View File
@@ -1,31 +1,5 @@
export const level0: any = {
"cars": [
{
"mx": 3,
"my": 2,
"line": 0
},
{
"mx": 1,
"my": 2,
"line": 0
},
{
"mx": 2,
"my": 3,
"line": 0
},
{
"mx": 3,
"my": 1,
"line": 0
},
{
"mx": 1,
"my": 1,
"line": 0
}
],
"cars": [],
"house": [
{
"x": 263,
+2 -1
View File
@@ -13,7 +13,8 @@ export const Graphics = PIXI.Graphics;
export const Container = PIXI.Container;
// Main server
export const URL = window.location.href.indexOf("localhost") == -1 ? "https://metacar-project.com/" : "http://localhost:3000/";
//export const URL = window.location.href.indexOf("localhost") == -1 ? "https://metacar-project.com/" : "http://localhost:3000/";
export const URL = "https://metacar-project.com/";
// Textures files
export const JSON_TEXTURES = URL + "public/textures/textures.json";
+25 -6
View File
@@ -28,6 +28,7 @@ export class Level extends World {
public isCarsMoving: boolean = true;
private lastReward: number = 0;
private rewardFunction: any = null;
constructor(levelContent: LevelInfo, canvasId: string) {
/*
@@ -39,6 +40,18 @@ export class Level extends World {
this.am = new AssetManger(this);
}
/**
* Set a custom reward function
* The @fc will be called with three parameters and should return one number.
* *agentCollisions: A list with all current collisions
* *onRoad: Is the car on the road
* *action: The last action took by the car
* @fc The reward function to call
*/
public setRewardFunction(fc: any) {
this.rewardFunction = fc;
}
/**
* Choose whether other cars move or stay fixed.
* This method should be called before to called 'load'.
@@ -93,7 +106,7 @@ export class Level extends World {
*/
this.agent.reset();
for (var c = 0; c < this.cars.length; c++) {
this.cars[c].reset();
//this.cars[c].reset();
}
}
@@ -105,12 +118,11 @@ export class Level extends World {
if (action == 0 || this.agent.core.v == 1)
reward += 0.5;
if (agent_col.length > 0){
reward = -10;
reward = -1;
}
else if (!on_road){
reward = -10;
reward = -1;
}
this.lastReward = reward;
return reward;
}
@@ -132,12 +144,19 @@ export class Level extends World {
for (var c = 0; c < this.cars.length; c++) {
if (this.cars[c].lidar && !this.cars[c].core.agent) // If this car can move
this.cars[c].step(delta);
}
}
// Move the agent
if (this.agent){
let {agentCollisions, onRoad} = this.agent.step(delta, action);
// Get the reward
let reward = this.setReward(agentCollisions, onRoad, action);
let reward;
if (this.rewardFunction){
reward = this.rewardFunction(agentCollisions, onRoad, action);
}
else {
reward = this.setReward(agentCollisions, onRoad, action);
}
this.lastReward = reward;
return reward;
}
return 0;
+42 -28
View File
@@ -46,34 +46,17 @@ export class MetaCar {
this.canvasId = canvasId;
this.levelToLoad = levelToLoad;
}
/*
Load the environement with the parameters passed in the constructor.
*/
public load(): Promise<void>{
return new Promise((resolve, reject) => {
if (typeof this.levelToLoad == "string"){
U.loadCustomURL(<string>this.levelToLoad, (content: LevelInfo) => {
this.level = new Level(content, this.canvasId);
this.level.setAgentMotion(this.agentMotionEngine, this.agentMotionOptions);
this.level.setAgentLidar(this.agentLidarInfo);
this.level.carsMoving(this.isCarsMoving);
this._setEvents();
this.level.load((delta: number) => this._loop(delta));
resolve();
});
}
else{
this.level = new Level(<LevelInfo>this.levelToLoad, this.canvasId);
this.level.setAgentMotion(this.agentMotionEngine, this.agentMotionOptions);
this.level.setAgentLidar(this.agentLidarInfo);
this.level.carsMoving(this.isCarsMoving);
this._setEvents();
this.level.load((delta: number) => this._loop(delta));
resolve();
}
});
/**
* Set a custom reward function
* The @fc will be called with three parameters and should return one number.
* *agentCollisions: A list with all current collisions
* *onRoad: Is the car on the road
* *action: The last action took by the car
* @fc The reward function to call
*/
public setRewardFunction(fc: any): void {
this.level.setRewardFunction(fc);
}
/**
@@ -257,4 +240,35 @@ export class MetaCar {
];
}
/*
Load the environement with the parameters passed in the constructor.
*/
public load(): Promise<void>{
return new Promise((resolve, reject) => {
if (typeof this.levelToLoad == "string"){
U.loadCustomURL(<string>this.levelToLoad, (content: LevelInfo) => {
this.level = new Level(content, this.canvasId);
this.level.setAgentMotion(this.agentMotionEngine, this.agentMotionOptions);
this.level.setAgentLidar(this.agentLidarInfo);
this.level.carsMoving(this.isCarsMoving);
this._setEvents();
this.level.load((delta: number) => this._loop(delta)).then(() => {
resolve();
});
});
}
else{
this.level = new Level(<LevelInfo>this.levelToLoad, this.canvasId);
this.level.setAgentMotion(this.agentMotionEngine, this.agentMotionOptions);
this.level.setAgentLidar(this.agentLidarInfo);
this.level.carsMoving(this.isCarsMoving);
this._setEvents();
this.level.load((delta: number) => this._loop(delta)).then(() => {
resolve();
});
}
});
}
}
+13 -1
View File
@@ -12,7 +12,7 @@ export class MetaCarEditor {
private canvasId: string;
private levelToLoad: string|Object;
private event: UIEvent;
private eventList: string[] = ["save"]
private eventList: string[] = ["save"];
private eventCallback: any[];
/**
@@ -62,6 +62,18 @@ export class MetaCarEditor {
});
}
/**
* Usefull method to save/download a string as file.
* @content The content of the file
* @file_name The name of the file
*/
public save(content: string, file_name: string): void{
/*
Save the agent
*/
U.saveAs(content, file_name);
}
/**
* This method is used to add button under the canvas. When a
* click is detected on the window, the associated @fc is called.
+3 -4
View File
@@ -15,7 +15,7 @@ export function loadJSON(url: string, callback: any) {
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == 200) {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
callback(JSON.parse(xobj.responseText));
}
};
xobj.send(null);
@@ -40,9 +40,8 @@ export function loadCustomURL(url: string, callback: any):void {
*/
const customCall: any = {
"embedded:": loadEmbeddedURL,
"http://": loadJSON,
"https://": loadJSON,
"localstorage://": loadLocalStorageURL
"http:": loadJSON,
"https:": loadJSON
}
const split = url.split("//");
customCall[split[0]](url, callback);
+1 -1
View File
@@ -58,7 +58,7 @@ export class World {
document.getElementById(this.canvasId).appendChild(this.app.view);
return new Promise((resolve, reject) => {
Loader.add([JSON_TEXTURES, JSON_IMAGE]).load(() => {
Loader.add([JSON_TEXTURES, JSON_IMAGE], {crossOrigin: true}).load(() => {
this._setup(info); // Set up the level (Add assets)
resolve();
});