Skip to content

Commit 8209e77

Browse files
more info
1 parent ff1bea0 commit 8209e77

File tree

4 files changed

+79
-14
lines changed

4 files changed

+79
-14
lines changed

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
Надя, [01.01.21 20:46]
21
# Deep Maze
32

3+
[English](README_en.md)
4+
5+
[Video v.0](https://www.youtube.com/watch?v=rSkxOtRhY24)
6+
7+
[Video v.1 (current version)](https://youtu.be/-w3PGBhAnzM)
8+
49
Этот проект является симуляцией изучения простого grid world-a ботом с ограниченным полем зрения. Очки начисляются исключительно за открытие новых участков мира, что требует, как минимум, планирования и навигации.
510

611
Типовые настройки мира:
@@ -12,14 +17,18 @@
1217
Видимая область - 17x17
1318
```
1419

15-
В данный момент, используется простой Q-learning, без какой-либо памяти, поэтому в состояние мира был добавлен срез с данными о прошлых передвижениях агента. Таким образом, агент получает данные о проходимости окружающих его клеток и о передвижениях (проходились ли вообще и если да - то как давно, чтобы не использовать LSTM).
20+
В данный момент, используется простой Q-learning, без какой-либо памяти, поэтому в состояние мира был добавлен срез с данными о прошлых передвижениях агента. Таким образом, агент получает данные о проходимости окружающих его клеток и о передвижениях (проходил ли по ячейке и как давно). Текущая версия окружения является чересчур упрощённой и может быть легко решена алгоритмически, но полученный опыт, приёмы и наблюдения могут быть применены к более реальным задачам. Например, карта может быть расширена до тысяч ячеек, с искажениями и другими осложняющими факторами.
1621

1722
Агенты очень часто застревали в сложных участках, поэтому было добавлено детектирование данного поведения, остановка агента и запуск того же агента в режиме исследования. Полученные таким способом данные помещаются в отдельную память, чтобы потом обучить агента как действовать в подобных ситуациях. Эмпирически эффект заметен, но нельзя однозначно утверждать пользу подобного подхода.
1823

1924
Изначально использовалась CNN (что логичнее для карт), но простая Dense-сетка давала сравнимые результат. Возможно, конечно, что остальные доработки могли привести к более заметному улучшению предсказаний CNN. Кроме того, были испробованы различные варианты наград, начальных условий, предобработки и др.
2025

2126
Длительная тренировка одного агента не давала ощутимого прогресса, поэтому, в итоге, были натренированы 4 версии той же сети и затем их решения объединялись вместе (см. [DQNEnsembleAgent.py](Agent/DQNEnsembleAgent.py)). Ансамбль из агентов позволяет получать более стабильные результаты в сложных ситуациях. Например, если агент попадает в сложный участок пространства, то существенно выше шанс что он сможет попытаться найти выход, чем когда агент основывается на предсказании лишь одной сети.
2227

28+
Общий принцип работы ансамбля:
29+
30+
![](img/ensemble.png)
31+
2332
Ниже показано сравнение верхней границы (кол-во открытой области в 10 симуляциях из 100, по 20 прогонов):
2433

2534
![](img/20201231-high.jpg)
@@ -32,6 +41,8 @@
3241

3342
Опять же, прямо ощутимого улучшения нет, но ансамбль немного стабильнее открывает 20-25% карты.
3443

35-
Следующим шагом будет дистилляция ансамбля в единую сеть, а так же использование полноценной сети для комбинации предсказаний подсетей. Есть большая вероятность того, что это позволит уловить более глубокие корреляции т. к. обучаемая сеть будет иметь представление о соотношение Q-values.
44+
Следующим шагом будет дистилляция ансамбля в единую сеть, а так же использование полноценной сети для комбинации предсказаний подсетей. Есть большая вероятность того, что это позволит уловить более глубокие корреляции т. к. обучаемая сеть будет уже иметь представление о соотношение Q-values (сами значения индивидуальны для каждой сети).
45+
46+
# Области применения
3647

37-
Продолжение, правки, фиксы и видео следуют, а пока Happy New Year :)
48+
Подобного рода задачи встречаются повсеместно в робототехнике, например.

README_en.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Deep Maze
2+
3+
[Video v.0](https://www.youtube.com/watch?v=rSkxOtRhY24)
4+
5+
[Video v.1 (current version)](https://youtu.be/-w3PGBhAnzM)
6+
7+
Coming soon.

img/ensemble.png

41.4 KB
Loading

view_maze.py

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,23 @@ class Colors:
4040
RED = (255, 0, 0)
4141
PURPLE = (255, 0, 255)
4242

43-
RLAgent = namedtuple('RLAgent', 'name agent environment')
43+
class DeathDetector:
44+
def __init__(self, env, maxStepsUnchanged=100):
45+
self._env = env
46+
self._maxStepsUnchanged = maxStepsUnchanged
47+
48+
self._lastScore = env.score
49+
self._lastValuableStep = env.steps
50+
return
51+
52+
def deathRatio(self):
53+
if self._lastScore < self._env.score:
54+
self._lastScore = self._env.score
55+
self._lastValuableStep = self._env.steps
56+
57+
return min((1, (self._env.steps - self._lastValuableStep) / self._maxStepsUnchanged))
58+
59+
RLAgent = namedtuple('RLAgent', 'name agent environment detector')
4460

4561
class App:
4662
MODES = ['manual', 'random', 'agent']
@@ -74,10 +90,9 @@ def on_init(self):
7490
def _assignMaze2Agents(self):
7591
agents = []
7692
for agent in self._agents:
77-
agents.append(RLAgent(
78-
agent.name, agent.agent,
79-
self._initMaze.copy()
80-
))
93+
env = self._initMaze.copy()
94+
detector = DeathDetector(env)
95+
agents.append(RLAgent(agent.name, agent.agent, env, detector))
8196

8297
self._agents = agents
8398
return
@@ -94,15 +109,16 @@ def _createNewAgent(self):
94109
name = os.path.basename(filename)
95110

96111
self._agents.append(RLAgent(
97-
name[:-3], agent, self._initMaze.copy()
112+
name[:-3], agent, None, None
98113
))
99114

100115
self._agents.insert(0, RLAgent(
101116
'ensemble',
102117
DQNEnsembleAgent(models),
103-
self._initMaze.copy()
118+
None, None
104119
))
105120

121+
self._assignMaze2Agents()
106122
self._activeAgent = 0
107123
self._paused = True
108124
return
@@ -180,7 +196,36 @@ def on_loop(self):
180196
maze.apply(act)
181197
pass
182198

199+
def _renderMazeMinimap(self, env):
200+
anchor = np.array((450, 650))
201+
maze, moves = env.minimap()
202+
203+
COLOR_A = pygame.Color(*Colors.GREEN)
204+
COLOR_B = pygame.Color(*Colors.WHITE)
205+
206+
h, w = maze.shape
207+
dx, dy = delta = 2 * np.array([64, 64]) / np.array([w, h])
208+
for ix in range(w):
209+
for iy in range(h):
210+
isWall = 0 < maze[ix, iy]
211+
isUnknownArea = maze[ix, iy] < 0
212+
213+
clr = Colors.WHITE
214+
if 0 < moves[ix, iy]:
215+
clr = COLOR_B.lerp(COLOR_A, max((0.25, moves[ix, iy])) )
216+
if isWall: clr = Colors.PURPLE
217+
if isUnknownArea: clr = Colors.BLACK
218+
219+
y, x = (delta * np.array([ix, iy])) + anchor
220+
pygame.draw.rect(self._display_surf, clr, [x, y, dx - 1, dy - 1], 0)
221+
222+
self._drawText('Observed state:', (anchor[1], anchor[0] - 25), Colors.BLUE)
223+
return
224+
183225
def _renderMaze(self, env):
226+
COLOR_A = pygame.Color(*Colors.GREEN)
227+
COLOR_B = pygame.Color(*Colors.WHITE)
228+
184229
fog = env.fog
185230
moves = env.moves
186231
maze = env.maze
@@ -191,11 +236,11 @@ def _renderMaze(self, env):
191236
for iy in range(h):
192237
isDiscovered = 0 < fog[ix, iy]
193238
isWall = 0 < maze[ix, iy]
194-
isWasHere = 0 < moves[ix, iy]
195239
y, x = delta * np.array([ix, iy])
196240

197241
clr = Colors.WHITE
198-
if isWasHere: clr = Colors.GREEN
242+
if 0 < moves[ix, iy]:
243+
clr = COLOR_B.lerp(COLOR_A, max((0.25, moves[ix, iy])) )
199244
if isWall: clr = Colors.PURPLE
200245

201246
if not isDiscovered:
@@ -204,6 +249,7 @@ def _renderMaze(self, env):
204249
# current pos
205250
x, y = delta * env.pos
206251
pygame.draw.rect(self._display_surf, Colors.RED, [x, y, dx - 1, dy - 1], 0)
252+
self._renderMazeMinimap(env)
207253
return
208254

209255
def _renderAgentsMaze(self):
@@ -233,12 +279,13 @@ def _renderInfo(self):
233279
if 'agent' == self._mode:
234280
self._drawText('Speed: x%.0f' % (self._speed), line(1), Colors.BLUE)
235281
for i, agent in enumerate(self._agents):
282+
deathRatio = agent.detector.deathRatio()
236283
self._drawText(
237284
'%s%s | %.1f (%d)' % (
238285
'>> ' if i == self._activeAgent else '',
239286
agent.name, agent.environment.score * 100.0, agent.environment.steps
240287
),
241-
line(2 + i), Colors.BLUE
288+
line(2 + i), Colors.BLUE if deathRatio < 1 else Colors.BLACK
242289
)
243290
return
244291

0 commit comments

Comments
 (0)