Compare commits
53 Commits
master
...
VowpalWabb
Author | SHA1 | Date | |
---|---|---|---|
|
7ee29820a6 | ||
|
8ca6b13fb3 | ||
6d21be1665 | |||
bfa30af3b2 | |||
bc655dded2 | |||
b55707b543 | |||
1ee731eec5 | |||
d67ed545dc | |||
794f80c1a7 | |||
3824702e4d | |||
|
118a8a1b1d | ||
|
8d6501708e | ||
83d95f008b | |||
|
b1a25ecc77 | ||
a8a0f97f3a | |||
|
00563e34f2 | ||
923251016a | |||
|
2e9d079d87 | ||
22550b92ec | |||
|
320c702482 | ||
|
3ba1f27d63 | ||
cf6172b5b2 | |||
78c4b6f01c | |||
dc14001bc5 | |||
89d0c03949 | |||
98b232a982 | |||
|
f48a725712 | ||
|
49c5c2aef4 | ||
|
737f59671d | ||
a49f41d681 | |||
|
09ff70271a | ||
|
ab69d0d986 | ||
d9e0bf434b | |||
f509230f60 | |||
0b2b255a20 | |||
813cf2accb | |||
28d2faaaed | |||
0c87e6de66 | |||
cf3bf3d4f5 | |||
|
d9fc9e1384 | ||
|
7d80f5c05f | ||
|
28c6dd4744 | ||
|
35fe3314f2 | ||
|
d9d65c249f | ||
d95378c72e | |||
913dba936f | |||
c969355d70 | |||
42d124cc6e | |||
|
94064f5d03 | ||
|
635292d9f5 | ||
|
15f88b9e20 | ||
|
abb6dbb5dd | ||
22e4a12eff |
@ -1,5 +1,6 @@
|
||||
import pygame
|
||||
from DataModels.Cell import Cell
|
||||
from VowpalWabbit.vowpal_utils import MAP_CONTENT
|
||||
|
||||
class Dump( Cell ):
|
||||
def __init__( self, x, y, max_rubbish, dump_type, yellow = 0, green = 0, blue = 0 ):
|
||||
@ -12,3 +13,10 @@ class Dump( Cell ):
|
||||
self.container.yellow, self.container.green, self.container.blue = collector.container.empty(dump_type,
|
||||
[self.container.yellow, self.container.green, self.container.blue])
|
||||
self.update_image()
|
||||
|
||||
def Visit(self):
|
||||
self.unvisited = not self.unvisited
|
||||
if self.unvisited:
|
||||
MAP_CONTENT[self.y][self.x] = self.dump_type[5]
|
||||
else:
|
||||
MAP_CONTENT[self.y][self.x] = "V"
|
||||
|
@ -2,26 +2,29 @@ from DataModels.Cell import Cell
|
||||
from DataModels.Road import Road
|
||||
from DataModels.House import House
|
||||
from DataModels.Dump import Dump
|
||||
from config import GRID_WIDTH, GRID_HEIGHT, DELAY
|
||||
from utilities import movement, check_moves, save_moveset
|
||||
from config import GRID_WIDTH, GRID_HEIGHT, DELAY, CLOSE_ON_END
|
||||
from utilities import movement, check_moves, save_moveset, unvisit_dump
|
||||
from VowpalWabbit.vowpal_utils import parse_list, get_predicted_move
|
||||
from Traversal.DFS import DFS
|
||||
from Traversal.BestFS import BestFS
|
||||
from Traversal.BFS import BFS
|
||||
import pygame
|
||||
import pygame, sys
|
||||
|
||||
class GC(Cell):
|
||||
moves_made = 0
|
||||
def __init__(self, x, y, max_rubbish, yellow=0, green=0, blue=0):
|
||||
algorithm_run = False
|
||||
def __init__(self, x, y, map_objects, max_rubbish, yellow=0, green=0, blue=0):
|
||||
Cell.__init__(self, x, y, max_rubbish, yellow, green, blue)
|
||||
self.moves = []
|
||||
self.old_time = pygame.time.get_ticks()
|
||||
self.vowpal_house_visited = 0
|
||||
unvisit_dump(map_objects)
|
||||
|
||||
def move(self, direction, environment):
|
||||
self.x, self.y = movement(environment, self.x, self.y)[0][direction]
|
||||
self.update_rect(self.x, self.y)
|
||||
self.moves_made = self.moves_made + 1 #moves counter
|
||||
|
||||
print(check_moves(environment, self.x, self.y,direction))
|
||||
|
||||
def collect(self, enviromnent):
|
||||
x, y = [self.x, self.y]
|
||||
coordinates = [(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y)]
|
||||
@ -41,40 +44,47 @@ class GC(Cell):
|
||||
return self.moves_made
|
||||
|
||||
def find_houses(self,enviromnent, house_count,dump_count, mode):
|
||||
self.algorithm_run = True
|
||||
|
||||
x = self.x
|
||||
y = self.y
|
||||
result = []
|
||||
element_list=[]
|
||||
house_count_after_search=house_count
|
||||
for home in range(house_count):
|
||||
last_x = x
|
||||
last_y = y
|
||||
avalible_moves = check_moves(enviromnent, x,y)
|
||||
if mode == "DFS":
|
||||
house,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],House)
|
||||
elif mode == "BFS":
|
||||
house,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],House)
|
||||
result = result[1::]
|
||||
self.moves.extend(result)
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
element_list.append(house)
|
||||
|
||||
house.Visit()
|
||||
unvisit_dump(enviromnent)
|
||||
for dump in range(dump_count):
|
||||
last_x = x
|
||||
last_y = y
|
||||
avalible_moves = check_moves(enviromnent, x,y)
|
||||
if mode == "DFS":
|
||||
dump,[x,y],result = DFS(enviromnent,avalible_moves,[[x,y]],Dump)
|
||||
elif mode == "BFS":
|
||||
dump,[x,y],result = BFS(enviromnent,avalible_moves,[[x,y]],Dump)
|
||||
self.moves.extend(result)
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
element_list.append(dump)
|
||||
dump.Visit()
|
||||
for x in element_list:
|
||||
x.unvisited = True
|
||||
x.Visit()
|
||||
self.moves.reverse()
|
||||
save_moveset(self.moves)
|
||||
|
||||
|
||||
def find_houses_BestFS(self, environment):
|
||||
self.algorithm_run = True
|
||||
|
||||
x = self.x
|
||||
y = self.y
|
||||
result = [[x,y]]
|
||||
|
||||
houses_list = []
|
||||
dump_list = []
|
||||
a = 0
|
||||
@ -89,32 +99,65 @@ class GC(Cell):
|
||||
a += 1
|
||||
|
||||
x, y = self.x, self.y
|
||||
|
||||
for i in range(len(houses_list)):
|
||||
last_x = x
|
||||
last_y = y
|
||||
available_movement = check_moves(environment, x, y)
|
||||
output = BestFS(environment, available_movement, [[x,y]], houses_list)
|
||||
if(output != None):
|
||||
[x,y],result,houses_list = output[0], output[1], output[2]
|
||||
self.moves.extend(result[1:])
|
||||
[x,y],result,houses_list,house = output[0], output[1], output[2], output[3]
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
house.Visit()
|
||||
unvisit_dump(environment)
|
||||
for i in range(len(dump_list)):
|
||||
last_x = x
|
||||
last_y = y
|
||||
available_movement = check_moves(environment, x, y)
|
||||
output = BestFS(environment, available_movement, [[x,y]], dump_list)
|
||||
if(output != None):
|
||||
[x,y],result,dump_list = output[0], output[1], output[2]
|
||||
self.moves.extend(result[1:])
|
||||
[x,y],result,dump_list,dump = output[0], output[1], output[2], output[3]
|
||||
self.moves.extend(parse_list(result[1:], last_x,last_y))
|
||||
dump.Visit()
|
||||
self.moves.reverse()
|
||||
save_moveset(self.moves)
|
||||
|
||||
def run_vw(self, grid, house_count):
|
||||
print("VOWPAL WABBIT")
|
||||
x, y = self.x, self.y
|
||||
possible_goals=[]
|
||||
action, position = get_predicted_move([x, y])
|
||||
self.moves.append(action)
|
||||
if(action != "pick_garbage"):
|
||||
x,y = position
|
||||
else:
|
||||
possible_goals.append([x+1,y])
|
||||
possible_goals.append([x-1,y])
|
||||
possible_goals.append([x,y+1])
|
||||
possible_goals.append([x,y-1])
|
||||
for location in possible_goals:
|
||||
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
|
||||
cell = grid[location[0]][location[1]]
|
||||
if(type(cell)==Dump and cell.unvisited) or ((type(cell) == House) and cell.unvisited):
|
||||
cell.Visit()
|
||||
print(cell.x, cell.y)
|
||||
self.vowpal_house_visited = self.vowpal_house_visited +1
|
||||
if self.vowpal_house_visited == house_count:
|
||||
unvisit_dump(grid)
|
||||
#self.moves.reverse()
|
||||
print(self.moves)
|
||||
|
||||
def make_actions_from_list(self,environment):
|
||||
now = pygame.time.get_ticks()
|
||||
if len(self.moves)==0 or now - self.old_time <= DELAY:
|
||||
if(len(self.moves)==0 and CLOSE_ON_END=="true" and self.algorithm_run):
|
||||
print("DONE")
|
||||
sys.exit()
|
||||
return
|
||||
|
||||
self.old_time = pygame.time.get_ticks()
|
||||
if self.moves[-1] == "pick_garbage":
|
||||
self.collect(environment)
|
||||
self.moves.pop()
|
||||
return
|
||||
self.x, self.y = self.moves.pop()
|
||||
self.moves_made = self.moves_made + 1 #moves counter
|
||||
self.update_rect(self.x,self.y)
|
||||
self.move(self.moves[-1],environment)
|
||||
self.moves.pop()
|
||||
|
@ -1,5 +1,5 @@
|
||||
from DataModels.Cell import Cell
|
||||
|
||||
from VowpalWabbit.vowpal_utils import MAP_CONTENT
|
||||
|
||||
class House(Cell):
|
||||
def __init__(self, x, y, max_rubbish, yellow=0, green=0, blue=0):
|
||||
@ -10,3 +10,10 @@ class House(Cell):
|
||||
self.container.yellow, self.container.green, self.container.blue = collector.container.add(
|
||||
[self.container.yellow, self.container.green, self.container.blue])
|
||||
self.update_image()
|
||||
|
||||
def Visit(self):
|
||||
self.unvisited = not self.unvisited
|
||||
if self.unvisited:
|
||||
MAP_CONTENT[self.y][self.x] = "H"
|
||||
else:
|
||||
MAP_CONTENT[self.y][self.x] = "V"
|
||||
|
@ -141,13 +141,13 @@ def GenerateMap():
|
||||
GC_position = random.choice(roads)
|
||||
|
||||
#Save map to file
|
||||
name = ".\\Resources\\Maps\\map"+str(datetime.datetime.now().strftime("%Y%m%d%H%M%S"))+"_auto.txt"
|
||||
name = "./Resources/Maps/map"+str(datetime.datetime.now().strftime("%Y%m%d%H%M%S%f"))+"_auto.txt"
|
||||
map_file = open(name, "w+")
|
||||
map_file.write(str(width)+" "+str(height)+"\n")
|
||||
map_file.write(str(GC_position[0])+" "+str(GC_position[1])+"\n")
|
||||
for row in grid:
|
||||
map_file.write(" ".join(row)+"\n")
|
||||
map_file.close()
|
||||
print(name)
|
||||
#print(name)
|
||||
|
||||
return(name)
|
104
Raports/SI_Raport_VowpalWabbit.md
Normal file
104
Raports/SI_Raport_VowpalWabbit.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Sztuczna inteligencja 2019 - Vowpal Wabbit
|
||||
|
||||
**Czas trwania opisywanych prac:** 22.05.2019 - 13.06.2019
|
||||
|
||||
**Osoby odpowiedzialne za implementajcę:** Anna Nowak, Magdalena Wilczyńska
|
||||
|
||||
**Implementowana technika:** Vowpal Wabbit
|
||||
|
||||
**Link do repozytorium projektu:** https://git.wmi.amu.edu.pl/s440556/SZI2019SmieciarzWmi
|
||||
|
||||
## Techniki uczenia - Vowpal Wabbit
|
||||
|
||||
#### Implementacja
|
||||
Cała implementacja dla VW znajduje się na osobnym branchu /VowpalWabbit
|
||||
|
||||
##### Środowisko i łączenie z Python3
|
||||
W związku z informacjami o błędach w implementacji wrappera VowpalWabbit dla Python3, został zaimplementowany własny wrapper umożliwiający komunikację między aplikacją a VW. Dodana została możliwość wywoływania skryptów shellowych (w języku bash) bezpośrednio ze środowiska Python3, dzięki czemu mogłyśmy uzyskać płynną komunikację.
|
||||
|
||||
Aby móc dostarczać poprawne dane wejściowe zarówno w trakcie procesu uczenia się jak i podczas szukania rozwiązania problemu, musiałyśmy dodać kilka modyfikacji do istniejących algorytmów. Domki oraz wysypiska dostają teraz dodatkowe oznaczenie jeśli zostały już odwiedzone.
|
||||
|
||||
Dodatkowo, podczas szukania rozwiązania istniejącymi algorytmami planowania ruchu, oprócz listy koordynatów agenta zwracamy listę komend, które wykonuje.
|
||||
|
||||
##### Komunikacja agent - VW
|
||||
Dodałyśmy wiele funkcji obsługujących łącznośc między agentem oraz samą aplikacją a VW:
|
||||
|
||||
1. Parsery - mapują komendy oraz obiekty na liczby.
|
||||
2. Generatory danych wejściowych:
|
||||
- Generator danych do uczenia się - konwertuje listy ruchów, koordynatów i otoczenia na wiersze w formacie VW, po czym zapisuje je do pliku.
|
||||
- Generator danych rzeczywistych - konwertuje listę obiektów w otoczeniu agenta o promieniu R = 1 na wiersz w formacie VW i zapisuje ją do pliku przeznaczonego do tymczasowego przechowywania danych.
|
||||
3. Funkcja odczytująca obiekty w otoczeniu agenta o promieniu R = 1. Funkcja ta oblicza współrzędne lewego górnego rogu pola widzenia agenta w celu poprawnego zapisania obiektów w otoczeniu. Funkcja pomija współrzędne agenta oraz współrzędne będące poza siatką mapy.
|
||||
4. Funkcja odczytująca wynik przewidywań VW. Funkcja ta odczytuje liczbę rzeczywistą zwrócona przez VW i mapuje ją do jednej z możliwych do wykonania przez agenta komend. Przewidywanie VW otrzymujemy przy użyciu komendy
|
||||
|
||||
vw -i ./VowpalWabbit/VowpalModels/100k_input.model -t ./VowpalWabbit/VowpalDataCahce/constant_input.txt -p ./vowpalWabbit/VowpalDataCahce/constant_output.txt
|
||||
|
||||
##### Format danych
|
||||
Przedstawione poniżej tabele pokazują mapowania użyte podczas procesu generwania danych.
|
||||
|
||||
**Mapowanie obiektów na mapie**
|
||||
|
||||
| Obiekt | Cyfra |
|
||||
| --- | --- |
|
||||
| E: empty | 0 |
|
||||
| R: road | 1 |
|
||||
| H: house | 2 |
|
||||
| V: visited house | 0 |
|
||||
| Y: yellow dump | 2 |
|
||||
| B: blue dump | 2 |
|
||||
| G: green dump | 2 |
|
||||
|
||||
**Mapowanie komend**
|
||||
|
||||
| Komenda | Cyfra | Waga przykładu |
|
||||
| --- | --- | --- |
|
||||
| pick_garbage | 1 | 5.0 |
|
||||
| right | 2 | 1.0 |
|
||||
| left | 3 | 1.0 |
|
||||
| up | 4 | 1.0 |
|
||||
| down | 5 | 1.0 |
|
||||
|
||||
Jeżeli w polu widzenia agenta znajduje się nieodwiedzony domek, a nie ma on aktualnie do niego dostępu, to następny ruch jest wykonywany z wagą 3.0.
|
||||
|
||||
Wyjściowa linijka dla VW:
|
||||
|
||||
> akcja waga | F00:a F01:b F10:c F20:d F21:e
|
||||
|
||||
Gdzie *Fxy: a* to zmapowany na cyfrę obiekt a będący na koordynatach (x,y) w stosunku do prawego górnego rogu pola widzenia agenta.
|
||||
|
||||
Przykładowa linijka danych:
|
||||
> 1 5.0 | F00:0.0 F01:1.0 F02:0.0 F10:2.0 F12:0.0 F20:0.0 F21:1.0 F22:1.0
|
||||
|
||||
##### Proces uczenia
|
||||
Aby usprawnić proces zbierania danych dodałyśmy parametry wymagane przy starcie aplikacji. Dla projektu VowpalWabbit, zamiast
|
||||
|
||||
python3 ./main.py ./Resources/Maps/map_name.txt
|
||||
|
||||
od teraz wymagane są 2 do 3 argumentów:
|
||||
- plik mapy (ścieżka do mapy lub "auto" dla losowo generowanych map)
|
||||
- informacja, czy aplikacja ma się zamknąc po zakończeniu wykonywania jednego z wcześniej zaimplementowanych algorytmów (true / false)
|
||||
- algorytm, który automatycznie uruchamia się po starcie aplikacji (bfs / dfs / bestfs / brak wartości jeżeli nie chcemy nic automatycznie włączać)
|
||||
|
||||
Przykładowe wywołanie komendy:
|
||||
python3 ./main.py auto false dfs
|
||||
|
||||
W celu maksymalnego zautomatyzowania procesu uczenia się, stworzyłyśmy skrypt, które wszystkie potrzebne rzeczy robi za nas. Wymaga podania liczby uruchomień aplikacji, informacji, czy ma wyczyścić poprzednie dane, nazwę wyjściowego modelu oraz informację, czy po zakończeniu zbierania danych powinien od razu zacząć sie uczyć. Po uruchomieniu aplikacji wymaganą liczbę razy, skrypt zbiera dane z powstałych plików i tworzy z nich jeden plik .txt, który następnie przekazuje do VW za pomocą komendy
|
||||
|
||||
vw --oaa 5 data_set.txt -f data_model.model
|
||||
|
||||
Poniżej znajdują się parametry, dla których stworzyłyśmy dwa prezentowane modele:
|
||||
|
||||
| Nazwa | Liczba wykonań programu | Typ mapy | Przykładowy algorytm | Pole widzenia |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1k.model | 1000 | auto | BestFS | 2 |
|
||||
| 100.model | 100 | auto | BestFS | 1 |
|
||||
|
||||
W wyniku procesu zbierania danych, otrzymałyśmy dane w liczbie około 50 000 linii oraz 5 000 linii.
|
||||
|
||||
#### Obserwacje
|
||||
|
||||
Pomimo dostosowania danych wejściowych i ich parametrów agent nie zawsze podejmuje racjonalne ruchy. Za każdym razem gdy trafia na skrzyżowanie nie potrafi dostosować ruchu do sytuacji. Udało nam się jednak nauczyć agenta kierowania się w stronę nieodwiedzonego domku, jeżeli ma taki w polu widzenia.
|
||||
Podczas obserwacji obu modeli doszłyśmy do wniosku, że agent o zwiększonym polu widzenia(model 1k.model) sprawuje się gorzej niż model o ograniczonym polu widzenia (mimo większej ilości danych).
|
||||
|
||||
---
|
||||
|
||||
Ze względu na to, że agent nie potrafi wyznaczyć odpowiedniego rozwiązania zadanego mu problemu ograniczyłyśmy przewidywanie do jednego ruchu.
|
@ -33,7 +33,6 @@ def BFS(grid, available_movement, gc_moveset, mode):
|
||||
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
|
||||
cell = grid[location[0]][location[1]]
|
||||
if(type(cell) == mode and cell.unvisited):
|
||||
cell.unvisited = False
|
||||
object_in_area = True
|
||||
break
|
||||
|
||||
|
@ -25,7 +25,7 @@ def BestFS(grid, available_movement, gc_moveset, object_list, depth = 0):
|
||||
gc_moveset.append("pick_garbage")
|
||||
cell = grid[min_distance_goal[0][0]][min_distance_goal[0][1]]
|
||||
object_list.remove([cell,min_distance_goal[0]])
|
||||
return([x, y], gc_moveset, object_list)
|
||||
return([x, y], gc_moveset, object_list, cell)
|
||||
|
||||
#if depth exceeded, return
|
||||
if(depth > 15 or len(available_movement) == 0):
|
||||
|
@ -5,7 +5,6 @@ from DataModels.Container import Container
|
||||
from config import GRID_WIDTH, GRID_HEIGHT
|
||||
|
||||
def DFS(grid, available_movement, gc_moveset, mode,depth=0):
|
||||
|
||||
possible_goals = []
|
||||
a = gc_moveset[-1][0]
|
||||
b = gc_moveset[-1][1]
|
||||
@ -18,7 +17,6 @@ def DFS(grid, available_movement, gc_moveset, mode,depth=0):
|
||||
if GRID_WIDTH>location[0]>=0 and GRID_HEIGHT>location[1]>=0:
|
||||
cell = grid[location[0]][location[1]]
|
||||
if(type(cell) == mode and cell.unvisited):
|
||||
cell.unvisited = False
|
||||
object_in_area = True
|
||||
break
|
||||
|
||||
|
1
VowpalWabbit/VowpalDataCache/constant_input.txt
Normal file
1
VowpalWabbit/VowpalDataCache/constant_input.txt
Normal file
@ -0,0 +1 @@
|
||||
1.0 | F00:0.0 F01:0.1 F02:0.0 F10:0.1 F12:0.0 F20:0.0 F21:0.1 F22:0.0
|
1
VowpalWabbit/VowpalDataCache/constant_output.txt
Normal file
1
VowpalWabbit/VowpalDataCache/constant_output.txt
Normal file
@ -0,0 +1 @@
|
||||
1
|
52208
VowpalWabbit/VowpalInputData/input_dataset061200291k.txt
Normal file
52208
VowpalWabbit/VowpalInputData/input_dataset061200291k.txt
Normal file
File diff suppressed because it is too large
Load Diff
5404
VowpalWabbit/VowpalInputData/input_dataset06121019100.txt
Normal file
5404
VowpalWabbit/VowpalInputData/input_dataset06121019100.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
VowpalWabbit/VowpalModels/100.model
Normal file
BIN
VowpalWabbit/VowpalModels/100.model
Normal file
Binary file not shown.
BIN
VowpalWabbit/VowpalModels/1k.model
Normal file
BIN
VowpalWabbit/VowpalModels/1k.model
Normal file
Binary file not shown.
4
VowpalWabbit/VowpalWrapper/wrapper.py
Normal file
4
VowpalWabbit/VowpalWrapper/wrapper.py
Normal file
@ -0,0 +1,4 @@
|
||||
import subprocess
|
||||
|
||||
def wrap_ex(command):
|
||||
subprocess.check_call(["./VowpalWabbit/VowpalWrapper/wrapper_exec.sh", command])
|
2
VowpalWabbit/VowpalWrapper/wrapper_exec.sh
Executable file
2
VowpalWabbit/VowpalWrapper/wrapper_exec.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
eval "$1"
|
38
VowpalWabbit/generate_dataset.py
Normal file
38
VowpalWabbit/generate_dataset.py
Normal file
@ -0,0 +1,38 @@
|
||||
import glob, datetime, os
|
||||
from VowpalWrapper.wrapper import wrap_ex
|
||||
|
||||
def generate_dataset(run_count, clear, model_name, learn):
|
||||
print("GENERATING DATASET")
|
||||
|
||||
if(clear == True):
|
||||
print("Clearing stored data... ", end = '')
|
||||
for dfile in glob.glob('./VowpalWabbit/VowpalInputData/input_map*.txt'):
|
||||
if(os.path.exists(dfile)):
|
||||
os.remove(dfile)
|
||||
print("Done")
|
||||
|
||||
print("Collecting data from " + str(run_count) + " runs...")
|
||||
wrap_ex("./VowpalWabbit/vowpal_auto_run.sh "+str(run_count))
|
||||
print("Collected data")
|
||||
|
||||
filename = "./VowpalWabbit/VowpalInputData/input_dataset" + str(datetime.datetime.now().strftime("%m%d%H%M")) + model_name
|
||||
print("Creating input file " + filename + ".txt... ", end = '')
|
||||
|
||||
input_file = open(filename,"a+")
|
||||
for pfile in glob.glob('./VowpalWabbit/VowpalInputData/input_map*.txt'):
|
||||
#print(pfile)
|
||||
partial_input = open(pfile, "r+")
|
||||
for line in partial_input:
|
||||
input_file.write(line)
|
||||
partial_input.close()
|
||||
input_file.close()
|
||||
os.rename(filename, filename + ".txt")
|
||||
print("Done")
|
||||
|
||||
if(learn == True):
|
||||
print("Learning from " + str(filename) + ".txt")
|
||||
model_file = "./VowpalWabbit/VowpalModels/" + model_name + ".model"
|
||||
wrap_ex("vw --oaa 5 " + filename + ".txt -f " + model_file)
|
||||
print("Learning process complete, model saved to " + model_file)
|
||||
|
||||
generate_dataset(100, True, "100", True)
|
6
VowpalWabbit/vowpal_auto_run.sh
Executable file
6
VowpalWabbit/vowpal_auto_run.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
for ((i=1; i<=$1; i++))
|
||||
do
|
||||
echo "Run "$i"/"$1
|
||||
python3 ./main.py auto true bestfs
|
||||
done
|
177
VowpalWabbit/vowpal_utils.py
Normal file
177
VowpalWabbit/vowpal_utils.py
Normal file
@ -0,0 +1,177 @@
|
||||
import re, os
|
||||
from config import MAP_NAME, GRID_WIDTH, GRID_HEIGHT, GC_X, GC_Y
|
||||
from VowpalWabbit.VowpalWrapper import wrapper
|
||||
|
||||
#const
|
||||
RADIUS = 1
|
||||
##
|
||||
|
||||
COORDINATES_LIST = []
|
||||
MOVES_LIST = []
|
||||
|
||||
with open( MAP_NAME, 'r' ) as map:
|
||||
MAP_CONTENT = map.readlines()[2:]
|
||||
MAP_CONTENT = [list(row.strip().replace(" ","")) for row in MAP_CONTENT]
|
||||
|
||||
moves_mapping = {
|
||||
"pick_garbage": 1,
|
||||
"right": 2,
|
||||
"left": 3,
|
||||
"up": 4,
|
||||
"down": 5
|
||||
}
|
||||
|
||||
predictions_mapping = {
|
||||
1 : "pick_garbage",
|
||||
2 : "right",
|
||||
3 : "left",
|
||||
4 : "up",
|
||||
5 : "down"
|
||||
}
|
||||
|
||||
environment_mapping = {
|
||||
"E":0,
|
||||
"R":1,
|
||||
"H":2,
|
||||
"V":0,
|
||||
"Y":2,
|
||||
"B":2,
|
||||
"G":2
|
||||
}
|
||||
def parse_list(whole_result,current_x,current_y):
|
||||
global COORDINATES_LIST, MOVES_LIST
|
||||
COORDINATES_LIST = whole_result.copy()
|
||||
moves = []
|
||||
primary_x = current_x
|
||||
primary_y = current_y
|
||||
#print("x,y",current_x,current_y,"list",whole_result)
|
||||
parser = {'[0,1]':"down",'[0,-1]':"up",'[1,0]':"right",'[-1,0]':"left"}
|
||||
for x in range(len(whole_result)):
|
||||
if whole_result[x]=="pick_garbage":
|
||||
moves.append(whole_result[x])
|
||||
else:
|
||||
x_subtraction = whole_result[x][0] - current_x
|
||||
y_subtraction = whole_result[x][1] - current_y
|
||||
current_x = whole_result[x][0]
|
||||
current_y = whole_result[x][1]
|
||||
moves.append(parser[f"[{x_subtraction},{y_subtraction}]"])
|
||||
#print(moves)
|
||||
MOVES_LIST = moves.copy()
|
||||
generate_input([primary_x,primary_y])
|
||||
return moves
|
||||
|
||||
def generate_input(current_position):
|
||||
i = 0 #we'll use it to map coords to moves
|
||||
input_file_content = []
|
||||
for position in COORDINATES_LIST:
|
||||
coords = check_position(current_position, i) #set valid gc position
|
||||
#vowpal config goes here
|
||||
importance = 1.0
|
||||
label = moves_mapping[MOVES_LIST[i]]
|
||||
area,importance = get_gc_area(coords, RADIUS)
|
||||
if importance == None:
|
||||
importance = 1.0
|
||||
if MOVES_LIST[i] == "pick_garbage":
|
||||
importance = 5.0
|
||||
input_line = str(label) + " " + str(importance) + " | "
|
||||
print ( predictions_mapping[label]+" " +str(importance)+ " |", end = " " )
|
||||
current_position = position
|
||||
for a in area:
|
||||
input_line += a + " "
|
||||
print( a ,end =" ")
|
||||
i += 1
|
||||
print()
|
||||
input_file_content.append(input_line)
|
||||
|
||||
#save to file
|
||||
tag = re.findall("(map_[0-9]+|map[0-9]+_auto)", MAP_NAME)[0]
|
||||
filename = "./VowpalWabbit/VowpalInputData/input_" + str(tag) + ".txt"
|
||||
input_file = open(filename,"a+")
|
||||
for line in input_file_content:
|
||||
input_file.write(line+"\n")
|
||||
input_file.close()
|
||||
|
||||
def pass_input(position):
|
||||
area,importance = get_gc_area(position, RADIUS)
|
||||
print(get_gc_area(position,1)[0])
|
||||
if importance==None:
|
||||
importance = 1.0
|
||||
input_line = str(importance) + " | "
|
||||
for a in area:
|
||||
input_line += a + " "
|
||||
|
||||
print(input_line)
|
||||
|
||||
#save to file
|
||||
filename = "./VowpalWabbit/VowpalDataCache/constant_input.txt"
|
||||
input_file = open(filename,"w+")
|
||||
input_file.write(input_line)
|
||||
input_file.close()
|
||||
return filename
|
||||
|
||||
|
||||
def get_gc_area(position, radius):
|
||||
area = []
|
||||
upper_right_coord = [position[0] - radius, position[1] - radius]
|
||||
importance = None
|
||||
for x in range(max(0, position[0] - radius), min(position[0] + radius + 1, GRID_WIDTH)): #prevents going abroad
|
||||
for y in range(max(0, position[1] - radius), min(position[1] + radius + 1, GRID_HEIGHT)):
|
||||
if([x,y] == position): #we dont need gc data here
|
||||
continue
|
||||
if MAP_CONTENT[y][x] == 'H' or MAP_CONTENT[y][x] == 'B' or MAP_CONTENT[y][x] == 'Y' or MAP_CONTENT[y][x] == 'G':
|
||||
importance = 3.0
|
||||
area.append("F"+str(x - upper_right_coord[0])+str(y - upper_right_coord[1])+":0."+str(environment_mapping[MAP_CONTENT[y][x]]))
|
||||
return area,importance
|
||||
|
||||
def check_position(position, i):
|
||||
if(type(position) is list): #if position valid, return it
|
||||
return position
|
||||
elif(position == "pick_garbage"): #if invalid, look for recent coords. if not found, return initial coords
|
||||
for j in range(i-1,-1,-1):
|
||||
if(type(COORDINATES_LIST[j]) is list):
|
||||
return COORDINATES_LIST[j]
|
||||
return [GC_X, GC_Y]
|
||||
else: #in case sh t happened
|
||||
print("An error has ocurred while processing GC position.")
|
||||
|
||||
def get_predicted_move(position):
|
||||
input_filename = pass_input(position)
|
||||
output_filename = "./VowpalWabbit/VowpalDataCache/constant_output.txt"
|
||||
command = "vw --oaa 5 -i ./VowpalWabbit/VowpalModels/100.model -t "+input_filename+" -p "+output_filename
|
||||
print(command)
|
||||
wrapper.wrap_ex(command)
|
||||
with open( output_filename, 'r' ) as fout:
|
||||
prediction = float(list(fout.readline().split())[0])
|
||||
move = make_move_from_prediction(prediction)
|
||||
print(position, prediction, move)
|
||||
if(move == "pick_garbage"):
|
||||
new_position = move
|
||||
else:
|
||||
axis = 0
|
||||
if(move in ["up", "down"]):
|
||||
axis = 1
|
||||
direction = 1
|
||||
if(move in ["up", "left"]):
|
||||
direction = -1
|
||||
new_position = position.copy()
|
||||
new_position[axis] += direction
|
||||
if(axis == 1 and (new_position[axis] < 0 or new_position[axis] >= GRID_HEIGHT)):
|
||||
new_position = position.copy()
|
||||
print("VIOLATED GRID HEIGHT")
|
||||
if(axis == 0 and (new_position[axis] < 0 or new_position[axis] >= GRID_WIDTH)):
|
||||
new_position = position.copy()
|
||||
print("VIOLATED GRID WIDTH")
|
||||
return move, new_position
|
||||
|
||||
def make_move_from_prediction(prediction):
|
||||
if(prediction > 4.5):
|
||||
move = predictions_mapping[5]
|
||||
elif(prediction > 3.5):
|
||||
move = predictions_mapping[4]
|
||||
elif(prediction > 2.5):
|
||||
move = predictions_mapping[3]
|
||||
elif(prediction > 1.5):
|
||||
move = predictions_mapping[2]
|
||||
else:
|
||||
move = predictions_mapping[1]
|
||||
return move
|
29
config.py
29
config.py
@ -1,15 +1,34 @@
|
||||
import sys, random
|
||||
from MapGenerator import GenerateMap
|
||||
import sys, random, MapGenerator
|
||||
|
||||
CELL_SIZE = 64
|
||||
FPS = 60
|
||||
DELAY = 50
|
||||
DELAY = 5
|
||||
|
||||
try:
|
||||
MAP_NAME = sys.argv[1]
|
||||
map_mode = sys.argv[1]
|
||||
if(map_mode == "auto"):
|
||||
MAP_NAME = MapGenerator.GenerateMap()
|
||||
else:
|
||||
MAP_NAME = map_mode
|
||||
except:
|
||||
MAP_NAME = GenerateMap()
|
||||
print("ERROR: Invalid map mode\n Please enter \"auto\" for generated map or provide a path to an existing map.")
|
||||
sys.exit()
|
||||
|
||||
if(len(sys.argv)>2):
|
||||
CLOSE_ON_END = sys.argv[2]
|
||||
if(CLOSE_ON_END != "true" and CLOSE_ON_END != "false"):
|
||||
print("ERROR: Invalid close on end statement\n Please enter \"true\" or \"false\" to specify if app has to shut after finding solution.")
|
||||
sys.exit()
|
||||
else:
|
||||
print("ERROR: Invalid close on end statement\n Please enter \"true\" or \"false\" to specify if app has to shut after finding solution.")
|
||||
sys.exit()
|
||||
|
||||
ALGORITHM = None
|
||||
if(len(sys.argv)>3):
|
||||
ALGORITHM = sys.argv[3]
|
||||
if(ALGORITHM != "bfs" and ALGORITHM != "dfs" and ALGORITHM!= "bestfs"):
|
||||
print("ERROR: Invalid algorithm statement\n Please enter \"bfs\", \"dfs\" or \"bestfs\" to specify algorithm you want to use.")
|
||||
sys.exit()
|
||||
|
||||
map = open( MAP_NAME, 'r' )
|
||||
|
||||
|
23
main.py
Normal file → Executable file
23
main.py
Normal file → Executable file
@ -3,16 +3,14 @@
|
||||
import pygame
|
||||
import sys
|
||||
from random import randint
|
||||
from config import WINDOW_HEIGHT, WINDOW_WIDTH, GRID_HEIGHT, GRID_WIDTH, HOUSE_CAPACITY, FPS, GC_X, GC_Y, MAP_NAME
|
||||
|
||||
from config import WINDOW_HEIGHT, WINDOW_WIDTH, GRID_HEIGHT, GRID_WIDTH, HOUSE_CAPACITY, FPS, GC_X, GC_Y, MAP_NAME, ALGORITHM
|
||||
from PIL import Image,ImageDraw
|
||||
|
||||
from DataModels.Grass import Grass
|
||||
from DataModels.House import House
|
||||
from DataModels.Dump import Dump
|
||||
from DataModels.Road import Road
|
||||
from DataModels.GC import GC
|
||||
|
||||
from utilities import unvisit_dump
|
||||
pygame.init()
|
||||
|
||||
pygame_sprites = pygame.sprite.Group()
|
||||
@ -21,6 +19,8 @@ dump_count=0
|
||||
FPS_CLOCK = pygame.time.Clock()
|
||||
GAME_WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0, 32)
|
||||
|
||||
algorithm = ALGORITHM
|
||||
|
||||
map = open(MAP_NAME, 'r')
|
||||
map.readline()
|
||||
map.readline()
|
||||
@ -77,12 +77,21 @@ for line in map_objects:
|
||||
for item in line:
|
||||
pygame_sprites.add(item)
|
||||
|
||||
gc = GC(GC_X, GC_Y, 200)
|
||||
print("GC: " + str(GC_X) + str(GC_Y))
|
||||
gc = GC(GC_X, GC_Y,map_objects, 200)
|
||||
#print("GC: " + str(GC_X) + str(GC_Y))
|
||||
pygame_sprites.add(gc)
|
||||
|
||||
while True:
|
||||
|
||||
if(algorithm != None):
|
||||
if(algorithm == "bfs"):
|
||||
gc.find_houses(map_objects,house_count,dump_count, "BFS")
|
||||
elif(algorithm == "dfs"):
|
||||
gc.find_houses(map_objects,house_count,dump_count, "DFS")
|
||||
elif (algorithm == "bestfs"):
|
||||
gc.find_houses_BestFS(map_objects)
|
||||
algorithm = None
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
@ -104,6 +113,8 @@ while True:
|
||||
gc.find_houses_BestFS(map_objects)
|
||||
elif event.key == pygame.K_8:
|
||||
gc.find_houses(map_objects,house_count,dump_count, "BFS")
|
||||
elif event.key == pygame.K_1:
|
||||
gc.run_vw(map_objects,house_count)
|
||||
|
||||
gc.make_actions_from_list(map_objects)
|
||||
pygame_sprites.update()
|
||||
|
13
utilities.py
13
utilities.py
@ -1,7 +1,7 @@
|
||||
from config import GRID_WIDTH, GRID_HEIGHT
|
||||
from DataModels.Road import Road
|
||||
import json, os, platform
|
||||
|
||||
from DataModels.Dump import Dump
|
||||
import platform,os,json
|
||||
def movement(environment, x ,y):
|
||||
movement = {
|
||||
"right": (x + 1, y) if x + 1 < GRID_WIDTH and type(environment[x + 1][y]) == Road else (x, y),
|
||||
@ -51,3 +51,12 @@ def save_moveset(moveset):
|
||||
f.seek(0)
|
||||
json.dump(results, f, indent=1)
|
||||
f.close()
|
||||
|
||||
def unvisit_dump(enviromnent):
|
||||
dump = []
|
||||
for x in enviromnent:
|
||||
for y in x:
|
||||
if type(y) == Dump:
|
||||
dump.append(y)
|
||||
for x in dump:
|
||||
x.Visit()
|
||||
|
Loading…
Reference in New Issue
Block a user