Commit 38423832 authored by hagrid67's avatar hagrid67
Browse files

Merge branch 'master' of gitlab.aicrowd.com:flatland/flatland

parents 708f3adb 49bd3b56
Pipeline #467 failed with stage
in 1 minute and 50 seconds
......@@ -11,7 +11,7 @@ Development
* A Egli <adrian.egli@sbb.ch>
* Mattias Ljungström <ml@mljx.io>
* Mattias Ljungström
Contributors
------------
......
========
flatland
Flatland
========
......@@ -15,45 +15,86 @@ flatland
Multi Agent Reinforcement Learning on Trains
Getting Started
===============
Generate Docs
--------------
| The docs have a lot more details about how to interact with this codebase.
| **TODO**: Mohanty to add atleast a neat outline herefor the contents to the docs here.
.. code-block:: bash
git clone git@gitlab.aicrowd.com:flatland/flatland.git
cd flatland
pip install -r requirements_dev.txt
The docs have a lot more details about how to interact with this codebase.
* Linux and macOS
**TODO**: Mohanty to add atleast a neat outline herefor the contents to the docs here ::
.. code-block:: bash
git clone git@gitlab.aicrowd.com:flatland/flatland.git
cd flatland
pip install -r requirements_dev.txt
make docs
* On, Linux and macOS ::
make docs
* Windows
.. code-block:: bash
* On, Windows ::
python setup.py develop (or)
python setup.py install
python make_docs.py
python setup.py develop (or)
python setup.py install
python make_docs.py
Features
--------
* TODO
TODO
Installation
============
Stable Release
--------------
To install flatland, run this command in your terminal ::
pip install flatland-rl
This is the preferred method to install flatland, as it will always install the most recent stable release.
If you don’t have `pip <https://pip.pypa.io/en/stable/>`_ installed, this `Python installation guide <https://docs.python-guide.org/starting/installation/>`_ can guide you through the process.
From Sources
------------
The sources for flatland can be downloaded from the `Gitlab repo <https://gitlab.aicrowd.com/flatland/flatland>`_.
You can clone the public repository ::
$ git clone git@gitlab.aicrowd.com:flatland/flatland.git
Once you have a copy of the source, you can install it with ::
$ python setup.py install
Usage
=====
To use flatland in a project ::
import flatland
flatland
========
TODO: explain the interface here
Authors
--------
* Sharada Mohanty <mohanty@aicrowd.com>
* Giacomo Spigler <giacomo.spigler@gmail.com>
* Mattias Ljungström <ml@mljx.io>
* Mattias Ljungström
* Jeremy Watson
* Erik Nygren <erik.nygren@sbb.ch>
* Adrian Egli <adrian.egli@sbb.ch>
* Vaibhav Agrawal <theinfamouswayne@gmail.com>
<please fill yourself in>
No preview for this file type
from flatland.envs.rail_env import RailEnv, random_rail_generator
from flatland.envs.rail_env import RailEnv, complex_rail_generator
# from flatland.core.env_observation_builder import TreeObsForRailEnv
from flatland.utils.rendertools import RenderTool
from flatland.baselines.dueling_double_dqn import Agent
......@@ -6,7 +6,6 @@ from collections import deque
import torch
import random
import numpy as np
import matplotlib.pyplot as plt
import time
......@@ -34,7 +33,7 @@ class Player(object):
self.tStart = time.time()
# Reset environment
#self.obs = self.env.reset()
# self.obs = self.env.reset()
self.env.obs_builder.reset()
self.obs = self.env._get_observations()
for a in range(self.env.number_of_agents):
......@@ -86,7 +85,6 @@ def max_lt(seq, val):
return None
def main(render=True, delay=0.0):
random.seed(1)
......@@ -94,27 +92,26 @@ def main(render=True, delay=0.0):
# Example generate a rail given a manual specification,
# a map of tuples (cell_type, rotation)
transition_probability = [0.5, # empty cell - Case 0
1.0, # Case 1 - straight
1.0, # Case 2 - simple switch
0.3, # Case 3 - diamond drossing
0.5, # Case 4 - single slip
0.5, # Case 5 - double slip
0.2, # Case 6 - symmetrical
0.0] # Case 7 - dead end
# transition_probability = [0.5, # empty cell - Case 0
# 1.0, # Case 1 - straight
# 1.0, # Case 2 - simple switch
# 0.3, # Case 3 - diamond crossing
# 0.5, # Case 4 - single slip
# 0.5, # Case 5 - double slip
# 0.2, # Case 6 - symmetrical
# 0.0] # Case 7 - dead end
# Example generate a random rail
env = RailEnv(width=15,
height=15,
rail_generator=random_rail_generator(cell_type_relative_proportion=transition_probability),
number_of_agents=5)
env = RailEnv(width=15, height=15,
rail_generator=complex_rail_generator(nr_start_goal=15, min_dist=5),
number_of_agents=1)
if render:
env_renderer = RenderTool(env, gl="QT")
plt.figure(figsize=(5,5))
# plt.figure(figsize=(5,5))
# fRedis = redis.Redis()
handle = env.get_agent_handles()
# handle = env.get_agent_handles()
state_size = 105
action_size = 4
......@@ -152,7 +149,7 @@ def main(render=True, delay=0.0):
obs = env.reset()
for a in range(env.number_of_agents):
norm = max(1, max_lt(obs[a],np.inf))
norm = max(1, max_lt(obs[a], np.inf))
obs[a] = np.clip(np.array(obs[a]) / norm, -1, 1)
# env.obs_builder.util_print_obs_subtree(tree=obs[0], num_elements_per_node=5)
......@@ -162,9 +159,9 @@ def main(render=True, delay=0.0):
# Run episode
for step in range(50):
#if trials > 114:
#env_renderer.renderEnv(show=True)
#print(step)
# if trials > 114:
# env_renderer.renderEnv(show=True)
# print(step)
# Action
for a in range(env.number_of_agents):
action = agent.act(np.array(obs[a]), eps=eps)
......@@ -188,7 +185,6 @@ def main(render=True, delay=0.0):
iFrame += 1
obs = next_obs.copy()
if done['__all__']:
env_done = 1
......@@ -202,23 +198,23 @@ def main(render=True, delay=0.0):
dones_list.append((np.mean(done_window)))
print(('\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%' +
'\tEpsilon: {:.2f} \t Action Probabilities: \t {}').format(
env.number_of_agents,
trials,
np.mean(scores_window),
100 * np.mean(done_window),
eps, action_prob/np.sum(action_prob)),
'\tEpsilon: {:.2f} \t Action Probabilities: \t {}').format(
env.number_of_agents,
trials,
np.mean(scores_window),
100 * np.mean(done_window),
eps, action_prob/np.sum(action_prob)),
end=" ")
if trials % 100 == 0:
tNow = time.time()
rFps = iFrame / (tNow - tStart)
print(('\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%' +
'\tEpsilon: {:.2f} fps: {:.2f} \t Action Probabilities: \t {}').format(
env.number_of_agents,
trials,
np.mean(scores_window),
100 * np.mean(done_window),
eps, rFps, action_prob / np.sum(action_prob)))
'\tEpsilon: {:.2f} fps: {:.2f} \t Action Probabilities: \t {}').format(
env.number_of_agents,
trials,
np.mean(scores_window),
100 * np.mean(done_window),
eps, rFps, action_prob / np.sum(action_prob)))
torch.save(agent.qnetwork_local.state_dict(),
'../flatland/baselines/Nets/avoid_checkpoint' + str(trials) + '.pth')
action_prob = [1]*4
......
......@@ -25,12 +25,19 @@ env = RailEnv(width=10,
rail_generator=random_rail_generator(cell_type_relative_proportion=transition_probability),
number_of_agents=1)
"""
env = RailEnv(width=20,
height=20,
rail_generator=complex_rail_generator(nr_start_goal=20, min_dist=10, max_dist=99999, seed=0),
number_of_agents=5)
"""
env = RailEnv(width=20,
height=20,
rail_generator=rail_from_list_of_saved_GridTransitionMap_generator(
['../flatland/baselines/test-editor.npy']),
['../env-data/tests/circle.npy']),
number_of_agents=1)
"""
env_renderer = RenderTool(env, gl="QT")
handle = env.get_agent_handles()
......@@ -47,7 +54,7 @@ scores = []
dones_list = []
action_prob = [0] * 4
agent = Agent(state_size, action_size, "FC", 0)
agent.qnetwork_local.load_state_dict(torch.load('../flatland/baselines/Nets/avoid_checkpoint15000.pth'))
agent.qnetwork_local.load_state_dict(torch.load('../flatland/baselines/Nets/avoid_checkpoint14900.pth'))
demo = True
......@@ -102,10 +109,10 @@ for trials in range(1, n_trials + 1):
for a in range(env.number_of_agents):
if demo:
eps = 0
action = agent.act(np.array(obs[a]), eps=eps)
action = 2 #agent.act(np.array(obs[a]), eps=eps)
action_prob[action] += 1
action_dict.update({a: action})
#env.obs_builder.util_print_obs_subtree(tree=obs[a], num_features_per_node=5)
# Environment step
next_obs, all_rewards, done, _ = env.step(action_dict)
for a in range(env.number_of_agents):
......@@ -120,7 +127,7 @@ for trials in range(1, n_trials + 1):
if done['__all__']:
env_done = 1
break
# Epsioln decay
# Epsilon decay
eps = max(eps_end, eps_decay * eps) # decrease epsilon
done_window.append(env_done)
......
......@@ -17,6 +17,7 @@ class ObservationBuilder:
"""
ObservationBuilder base class.
"""
def __init__(self):
pass
......@@ -55,6 +56,7 @@ class TreeObsForRailEnv(ObservationBuilder):
The information is local to each agent and exploits the tree structure of the rail
network to simplify the representation of the state of the environment for each agent.
"""
def __init__(self, max_depth):
self.max_depth = max_depth
......@@ -135,7 +137,7 @@ class TreeObsForRailEnv(ObservationBuilder):
new_cell = self._new_position(position, neigh_direction)
if new_cell[0] >= 0 and new_cell[0] < self.env.height and \
new_cell[1] >= 0 and new_cell[1] < self.env.width:
new_cell[1] >= 0 and new_cell[1] < self.env.width:
desired_movement_from_new_cell = (neigh_direction + 2) % 4
......@@ -176,7 +178,7 @@ class TreeObsForRailEnv(ObservationBuilder):
"""
Utility function that converts a compass movement over a 2D grid to new positions (r, c).
"""
if movement == 0: # NORTH
if movement == 0: # NORTH
return (position[0] - 1, position[1])
elif movement == 1: # EAST
return (position[0], position[1] + 1)
......@@ -325,7 +327,7 @@ class TreeObsForRailEnv(ObservationBuilder):
if not last_isDeadEnd:
# Keep walking through the tree along `direction'
exploring = True
# TODO: Remove below calculation, this is computed already above and could be reused
for i in range(4):
if cell_transitions[i]:
position = self._new_position(position, i)
......@@ -340,7 +342,8 @@ class TreeObsForRailEnv(ObservationBuilder):
elif num_transitions == 0:
# Wrong cell type, but let's cover it and treat it as a dead-end, just in case
print("WRONG CELL TYPE detected in tree-search (0 transitions possible)")
print("WRONG CELL TYPE detected in tree-search (0 transitions possible) at cell", position[0],
position[1], direction)
last_isTerminal = True
break
......@@ -394,7 +397,7 @@ class TreeObsForRailEnv(ObservationBuilder):
observation = observation + branch_observation
elif last_isSwitch and self.env.rail.get_transition((position[0], position[1], direction),
branch_direction):
(branch_direction + 2) % 4):
new_cell = self._new_position(position, branch_direction)
branch_observation = self._explore_branch(handle,
......@@ -456,6 +459,7 @@ class GlobalObsForRailEnv(ObservationBuilder):
- A 4 elements array with one of encoding of the direction.
"""
def __init__(self):
super(GlobalObsForRailEnv, self).__init__()
......
......@@ -531,9 +531,50 @@ class RailEnvTransitions(Grid4Transitions):
int('1001011000100001', 2), # Case 4 - single slip
int('1100110000110011', 2), # Case 5 - double slip
int('0101001000000010', 2), # Case 6 - symmetrical
int('0010000000000000', 2)] # Case 7 - dead end
int('0010000000000000', 2), # Case 7 - dead end
int('0100000000000010', 2), # Case 1b (8) - simple turn right
int('0001001000000000', 2), # Case 1c (9) - simple turn left
int('1100000000100010', 2)] # Case 2b (10) - simple switch mirrored
def __init__(self):
super(RailEnvTransitions, self).__init__(
transitions=self.transition_list
)
# create this to make validation faster
self.transitions_all = []
for index, trans in enumerate(self.transitions):
self.transitions_all.append(trans)
if index in (2, 4, 6, 7, 8, 9, 10):
for _ in range(3):
trans = self.rotate_transition(trans, rotation=90)
self.transitions_all.append(trans)
elif index in (1, 5):
trans = self.rotate_transition(trans, rotation=90)
self.transitions_all.append(trans)
def print(self, cell_transition):
print(" NESW")
print("N", format(cell_transition >> (3*4) & 0xF, '04b'))
print("E", format(cell_transition >> (2*4) & 0xF, '04b'))
print("S", format(cell_transition >> (1*4) & 0xF, '04b'))
print("W", format(cell_transition >> (0*4) & 0xF, '04b'))
def is_valid(self, cell_transition):
"""
Checks if a cell transition is a valid cell setup.
Parameters
----------
cell_transition : int
64 bits used to encode the valid transitions for a cell.
Returns
-------
Boolean
True or False
"""
for trans in self.transitions_all:
if cell_transition == trans:
return True
return False
This diff is collapsed.
......@@ -33,6 +33,7 @@ class View(object):
class JupEditor(object):
def __init__(self, env, wid_img):
print("Correct editor")
self.env = env
self.wid_img = wid_img
......
......@@ -7,7 +7,7 @@ import numpy as np
class QTGL(GraphicsLayer):
def __init__(self, width, height):
self.cell_pixels = 50
self.cell_pixels = 60
self.tile_size = self.cell_pixels
self.width = width
......
......@@ -71,11 +71,11 @@
```
%% Cell type:code id: tags:
``` python
sfEnv = "../flatland/env-data/tests/test1.npy"
sfEnv = "C:/Users/u224870/Projekte_Git/flatland/env-data/tests/test1.npy"
if True:
oEnv.rail.load_transition_map(sfEnv)
oEnv.width = oEnv.rail.width
oEnv.height = oEnv.rail.height
```
......@@ -157,11 +157,11 @@
%% Cell type:code id: tags:
``` python
wid_img.unregister_all()
oEditor = JupEditor(oEnv, wid_img)
oEditor = JupEditor(oEnv,wid_img)
wid_img.register_move(oEditor.event_handler)
wid_img.register_click(oEditor.on_click)
```
......@@ -280,10 +280,31 @@
``` python
if False:
oEnv.rail.save_transition_map("../flatland/env-data/tests/test-editor.npy")
```
%%%% Output: error
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-20-a40691809d2c> in <module>()
----> 1 oEnv.rail.save_transition_map("../flatland/env-data/tests/test-editor.npy")
c:\users\u224870\appdata\local\programs\python\python36\lib\site-packages\flatland_rl-0.1.1-py3.6.egg\flatland\core\transition_map.py in save_transition_map(self, filename)
259
260 """
--> 261 np.save(filename, self.grid)
262
263 def load_transition_map(self, filename, override_gridsize=True):
c:\users\u224870\appdata\local\programs\python\python36\lib\site-packages\numpy\lib\npyio.py in save(file, arr, allow_pickle, fix_imports)
490 if not file.endswith('.npy'):
491 file = file + '.npy'
--> 492 fid = open(file, "wb")
493 own_fid = True
494 elif is_pathlib_path(file):
FileNotFoundError: [Errno 2] No such file or directory: '../flatland/env-data/tests/test-editor.npy'
%% Cell type:markdown id: tags:
## Junk below here
%% Cell type:code id: tags:
......
......@@ -3,6 +3,56 @@
"""Tests for `flatland` package."""
from flatland.core.transitions import RailEnvTransitions, Grid8Transitions
from flatland.envs.rail_env import validate_new_transition
import numpy as np
def test_is_valid_railenv_transitions():
rail_env_trans = RailEnvTransitions()
transition_list = rail_env_trans.transitions
for t in transition_list:
assert(rail_env_trans.is_valid(t) is True)
for i in range(3):
rot_trans = rail_env_trans.rotate_transition(t, 90 * i)
assert(rail_env_trans.is_valid(rot_trans) is True)
assert(rail_env_trans.is_valid(int('1111111111110010', 2)) is False)
assert(rail_env_trans.is_valid(int('1001111111110010', 2)) is False)
assert(rail_env_trans.is_valid(int('1001111001110110', 2)) is False)
def test_adding_new_valid_transition():
rail_trans = RailEnvTransitions()
rail_array = np.zeros(shape=(15, 15), dtype=np.uint16)
# adding straight
assert(validate_new_transition(rail_trans, rail_array, (4, 5), (5, 5), (6, 5), (10, 10)) is True)
# adding valid right turn
assert(validate_new_transition(rail_trans, rail_array, (5, 4), (5, 5), (5, 6), (10, 10)) is True)
# adding valid left turn
assert(validate_new_transition(rail_trans, rail_array, (5, 6), (5, 5), (5, 6), (10, 10)) is True)
# adding invalid turn
rail_array[(5, 5)] = rail_trans.transitions[2]
assert(validate_new_transition(rail_trans, rail_array, (4, 5), (5, 5), (5, 6), (10, 10)) is False)
# should create #4 -> valid
rail_array[(5, 5)] = rail_trans.transitions[3]
assert(validate_new_transition(rail_trans, rail_array, (4, 5), (5, 5), (5, 6), (10, 10)) is True)
# adding invalid turn
rail_array[(5, 5)] = rail_trans.transitions[7]
assert(validate_new_transition(rail_trans, rail_array, (4, 5), (5, 5), (5, 6), (10, 10)) is False)
# test path start condition
rail_array[(5, 5)] = rail_trans.transitions[0]
assert(validate_new_transition(rail_trans, rail_array, None, (5, 5), (5, 6), (10, 10)) is True)
# test path end condition
rail_array[(5, 5)] = rail_trans.transitions[0]
assert(validate_new_transition(rail_trans, rail_array, (5, 4), (5, 5), (6, 5), (6, 5)) is True)
def test_valid_railenv_transitions():
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment