From 4860028fa2e90885a8b8fca75512c12b114abba8 Mon Sep 17 00:00:00 2001 From: Marcin Kwapisz Date: Mon, 18 May 2020 22:05:58 +0200 Subject: [PATCH 1/6] Gotowy podprojekt --- Marcin.py | 15 ++++++++++----- ui.py | 9 ++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Marcin.py b/Marcin.py index db3fb80..eac09c7 100644 --- a/Marcin.py +++ b/Marcin.py @@ -9,6 +9,7 @@ class main(): self.field = field self.ui = ui self.path = path + self.mode_value = 0 def get_output_layers(self,net): layer_names = net.getLayerNames() @@ -27,7 +28,7 @@ class main(): COLORS = np.random.uniform(0, 255, size=(len(classes), 3)) - net = cv2.dnn.readNet("si_final.weights", "si.cfg") + net = cv2.dnn.readNet("si_20000.weights", "si.cfg") blob = cv2.dnn.blobFromImage(image, scale, (416, 416), (0, 0, 0), True, crop=False) @@ -48,16 +49,18 @@ class main(): confidence = scores[class_id] if confidence > 0.5: class_ids.append(class_id) - print(class_id) - print(scores) - return class_id + return class_ids[0] def main(self): self.pole = self.ui.field_images[self.field.get_value(self.traktor.get_poz())] self.img = pygame.surfarray.array3d(self.pole) self.img = self.img.transpose([1,0,2]) self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2BGR) - self.traktor.set_mode(self.mode(self.recognition(self.img))) + self.reco = self.mode(self.recognition(self.img)) + if self.reco == 10: + print("Nic nie trzeba robić") + else: + self.traktor.set_mode(self.reco) def mode(self,mode): self.mode_value = mode @@ -69,3 +72,5 @@ class main(): return 2 elif self.mode_value in [8]: return 3 + elif self.mode_value in [6]: + return 10 diff --git a/ui.py b/ui.py index 6fa34e9..29daa46 100644 --- a/ui.py +++ b/ui.py @@ -1,5 +1,5 @@ import pygame - +import random class game_ui(): def __init__(self,traktor,field): @@ -34,8 +34,11 @@ class game_ui(): self.pole1_surf_rect.y = self.POLE_POZ[1] - 75 self.traktor_img = ["traktor_d.png", "traktor_l.png", "traktor_u.png", "traktor_r.png"] self.field_images = [] - for i in ['gleba_pix.png','gleba_chwasty_pix.png','sadzonka_suchi_pix.png','sadzonka_chwasty_pix.png','gleba_mokra_pix.png','gleba_mokra_chwasty.png','sadzonka_mokra_pix.png','sadzonka_mokra_chwasty_pix.png','gotowy_burak_pix.png']: - self.field_images.append(pygame.image.load('images/'+i)) + # self.field_images_path = [] + # self.random = random.randint(0,99) + for i in ['gleba_pix','gleba_chwasty_pix','sadzonka_suchi_pix','sadzonka_chwasty_pix','gleba_mokra_pix','gleba_mokra_chwasty','sadzonka_mokra_pix','sadzonka_mokra_chwasty_pix','gotowy_burak_pix']: + # self.field_images_path.append("images/"+i+"/"+i+str(self.random)+".png") + self.field_images.append(pygame.image.load("images/"+i+".png")) # Zezwalamy na przechwytywanie klawiszy pygame.event.pump() From 9a7c329a20f2cd92e47decc2d894ea83b1a2057d Mon Sep 17 00:00:00 2001 From: Marcin Kwapisz Date: Tue, 19 May 2020 00:09:16 +0200 Subject: [PATCH 2/6] Dodany raport do podprojektu sieci neuronowych --- Marcin.md | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Marcin.md diff --git a/Marcin.md b/Marcin.md new file mode 100644 index 0000000..d52546b --- /dev/null +++ b/Marcin.md @@ -0,0 +1,93 @@ +# Podprojekt - sieć neuronowa" +**Twórca: Marcin Kwapisz** + +**Klawisz F7 uruchamia program** + +Program otrzymuje zdjęcie aktualnego pola i za +pomocą sieci neuronowej określa jakie to jest pole +i wybiera tryb w jakim ma pracować traktor + +Sieć neuronowa została nauczona przy użyciu modułu darknet. Sieć została użyta po +20000 iteracjach treningowych + +**Main** +``` + def main(self): + self.pole = self.ui.field_images[self.field.get_value(self.traktor.get_poz())] + self.img = pygame.surfarray.array3d(self.pole) + self.img = self.img.transpose([1,0,2]) + self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2BGR) + self.reco = self.mode(self.recognition(self.img)) + if self.reco == 10: + print("Nic nie trzeba robić") + else: + self.traktor.set_mode(self.reco) +``` +Wywołuje wszystkie pozostałe funkcje programu + +**Get_output_layers** +``` + def get_output_layers(self,net): + layer_names = net.getLayerNames() + output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()] + return output_layers +``` +Zwraca nazwy kolejnych warstw, warstwa wyjściowa nie jest połączona z żadną następną warstwą + +**Recognition** +``` + def recognition(self,photo): + image = photo + + Width = image.shape[1] + Height = image.shape[0] + scale = 0.00392 + + with open("si.names", 'r') as f: + classes = [line.strip() for line in f.readlines()] + + COLORS = np.random.uniform(0, 255, size=(len(classes), 3)) + + net = cv2.dnn.readNet("si_20000.weights", "si.cfg") + + blob = cv2.dnn.blobFromImage(image, scale, (416, 416), (0, 0, 0), True, crop=False) + + net.setInput(blob) + + outs = net.forward(self.get_output_layers(net)) + + class_ids = [] + confidences = [] + boxes = [] + conf_threshold = 0.5 + nms_threshold = 0.4 + + for out in outs: + for detection in out: + scores = detection[5:] + class_id = np.argmax(scores) + confidence = scores[class_id] + if confidence > 0.5: + class_ids.append(class_id) + return class_ids[0] +``` +Odpowiada za odebranie zdjęcia od funkcji głównej i +używa sieci neuronowej do rozpoznania zdjęcia + +**Mode** +``` + def mode(self,mode): + self.mode_value = mode + if self.mode_value in [0, 1, 2, 3]: + return 0 + elif self.mode_value in [1, 3, 5, 7]: + return 1 + elif self.mode_value in [0, 1, 4, 5]: + return 2 + elif self.mode_value in [8]: + return 3 + elif self.mode_value in [6]: + return 10 +``` +Na podstawie klasy otrzymanej przez funkcję **recognition** wybiera tryb +w jakim ma pracować traktor \ No newline at end of file From 9da48366d3a1c8c3ebc45363ff8636f3058c27c8 Mon Sep 17 00:00:00 2001 From: Kamila Matysiak Date: Tue, 19 May 2020 11:25:05 +0000 Subject: [PATCH 3/6] Zaktualizuj 'decisiontree.md' --- decisiontree.md | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/decisiontree.md b/decisiontree.md index 1835440..38646fe 100644 --- a/decisiontree.md +++ b/decisiontree.md @@ -9,3 +9,161 @@ ### Drzewo Decyzyjne +Projekt wykorzystuje drzewo decyzyjne do wybrania najoptymalniejszego trybu. Uruchamia się go za pomocą klawisza **F6**. + +#### Przygotowanie Danych: + +Za przygotowanie danych odpowiedzialne są dwie funkcje: +**find_best_action**, która pobiera macierz pól, tworzy macierz czynności do wykonania, a następnie buduje drzewo. + +``` + def find_best_action(self): + testing_data = [] + matrix = self.field.get_matrix() # pobranie macierzy pól + matrix_todo = [] + for i in range(10): + matrix_todo.append([]) + verse = matrix[i] + for j in range(len(verse)): + coord = (i, j) + current_field = check(verse[j]) # czynnosci ktore trzeba jeszcze zrobic na kazdym polu + matrix_todo[i].append([]) + for action in current_field: + matrix_todo[i][j].append(action[-1]) + testing_data.extend(current_field) + if len(testing_data) > 0: + x = build_tree(testing_data) # zbudowanie drzewa + print_tree(x) + if isinstance(x, Leaf): # wybór najlepszej czynności do wykonania + self.best_action = self.find_remaining_action(matrix_todo) + return + self.best_action = x.question.column + print(header[x.question.column]) + print(x.question.value) + else: + self.best_action = self.find_remaining_action(matrix_todo) + return + +``` +drugą funkcją jest **check**, która interpretuje pola z macierzy na podstawie numerów, dodając stringa z czynnością do wykonania na danym polu. + +``` +def check(field): + if field == 0: + return [[0, 0, 1, 0, "Zasadzic"], [0, 0, 1, 0, "Podlac"]] + elif field == 1: + return [[0, 1, 1, 0, "Odchwascic"], [0, 1, 1, 0, "Podlac"], [0, 1, 1, 0, "Zasadzic"]] + elif field == 2: + return [[0, 0, 0, 0, "Podlac"]] + elif field == 3: + return [[0, 1, 0, 0, "Odchwascic"], [0, 1, 0, 0, "Podlac"]] + elif field == 4: + return [[1, 0, 1, 0, "Zasadzic"]] + elif field == 5: + return [[1, 1, 1, 0, "Odchwascic"], [1, 1, 1, 0, "Zasadzic"]] + elif field == 6: + return [] + elif field == 7: + return [[1, 1, 0, 0, "Odchwascic"]] + elif field == 8: + return [[0, 0, 0, 1, "Zebrac"], [0, 0, 0, 1, "Potem podlac"], [0, 0, 0, 1, "Potem zasadzic"]] + else: + print("Błąd: Zły numer pola.") + +``` + +#### Budowanie Drzewa: + +Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie dzieli nam dane na spełnione i niespełnione wiersze: + +``` +# podział danych na spełnione i niespełnione wiersze +def partition(rows, question): + true_rows, false_rows = [], [] + for row in rows: + if question.match(row): + true_rows.append(row) + else: + false_rows.append(row) + return true_rows, false_rows +``` + +Następnie wyokrzystujemy **Index Gini** i **Info Gain**. + Index Gini mierzy jak często losowo wybrany element będzie źle zindentyfikowany. + Information gain mierzy zmianę entropii, która powstaje na skutek podziału zestawu danych testowych na mniejsze części. + +``` +# funkcja implementująca indeks gini +def gini(rows): + counts = class_counts(rows) + impurity = 1 + for lbl in counts: + prob_of_lbl = counts[lbl] / float(len(rows)) + impurity -= prob_of_lbl ** 2 + return impurity + +#information gain +def info_gain(left, right, current_uncertainty): + p = float(len(left)) / (len(left) + len(right)) + return current_uncertainty - p * gini(left) - (1 - p) * gini(right) + +``` + +Następnie na podstawie uzykanych informacji, znajdujemy najlepsze miejsce na podział danych: + +``` +# znalezienie najlepszego "miejsca" na podział danych +def find_best_split(rows): + best_gain = 0 + best_question = None + current_uncertainty = gini(rows) + n_features = len(rows[0]) - 1 + for col in range(n_features): + values = set([row[col] for row in rows]) + for val in values: + question = Question(col, val) + true_rows, false_rows = partition(rows, question) + if len(true_rows) == 0 or len(false_rows) == 0: + continue + gain = info_gain(true_rows, false_rows, current_uncertainty) + if gain >= best_gain: + best_gain, best_question = gain, question + return best_gain, best_question +``` + +Po stworzeniu klas definiujących liść i węzęł deycyzyjny przechodzimy do właściwej funkcji **build_tree*: +``` +# funkcja budująca drzewo +def build_tree(rows): + gain, question = find_best_split(rows) # znalezienie najlepszego podziału + if gain == 0: + return Leaf(rows) + true_rows, false_rows = partition(rows, question) # podział danych + + true_branch = build_tree(true_rows) + false_branch = build_tree(false_rows) #stworzenie gałęzi prawdy i fałszu + + return DecisionNode(question, true_branch, false_branch) +``` + +#### Integracja: + +Gdy za pomocą funkcji **find_best_action** zostanie wybrana najbardziej opłacalna czynność wykorzystujemy algorytm A* zaimplementowany w pliku **pathfinding.py**. Ustawiamy tryb traktora i w pętli każemy znajdować mu pola. + +``` + def do_best_action(self): + self.traktor.set_mode(self.best_action) + while self.path.pathfinding(self.traktor, self.field, self.ui) != 0: + pass +``` +Kiedy zostanie już tylko jedna czynność do wykonania przypisujemy jej **find_remaining_action**, dzięki czemu nasze pole zostanie w pełni oprawione. + +``` + def find_remaining_action(self, matrix_todo): + for row in matrix_todo: + for field in row: + for action in field: + print(action) + return work.index(action) + return -1 +``` \ No newline at end of file From bbc9b3fc34e8b842208b40203afed9452d25c736 Mon Sep 17 00:00:00 2001 From: Kamila Matysiak Date: Tue, 19 May 2020 11:26:37 +0000 Subject: [PATCH 4/6] Zaktualizuj 'decisiontree.md' --- decisiontree.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/decisiontree.md b/decisiontree.md index 38646fe..8f41e4f 100644 --- a/decisiontree.md +++ b/decisiontree.md @@ -45,7 +45,7 @@ Za przygotowanie danych odpowiedzialne są dwie funkcje: return ``` -drugą funkcją jest **check**, która interpretuje pola z macierzy na podstawie numerów, dodając stringa z czynnością do wykonania na danym polu. +Drugą funkcją jest **check**, która interpretuje pola z macierzy na podstawie numerów, dodając stringa z czynnością do wykonania na danym polu. ``` def check(field): @@ -74,7 +74,7 @@ def check(field): #### Budowanie Drzewa: -Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie dzieli nam dane na spełnione i niespełnione wiersze: +Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie zapytania dzieli nam dane na spełnione i niespełnione wiersze: ``` # podział danych na spełnione i niespełnione wiersze From 905a2d9c1e92065adf8250a7518943fac8fcfc42 Mon Sep 17 00:00:00 2001 From: Kamila Matysiak Date: Sun, 24 May 2020 20:14:49 +0000 Subject: [PATCH 5/6] Zaktualizuj 'decisiontree.md' --- decisiontree.md | 115 +++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 79 deletions(-) diff --git a/decisiontree.md b/decisiontree.md index 8f41e4f..6036691 100644 --- a/decisiontree.md +++ b/decisiontree.md @@ -2,77 +2,37 @@ **Członkowie zespołu:** Marcin Kwapisz, Kamila Matysiak, Piotr Rychlicki, Justyna Zarzycka -**Temat podprojektu:** Wybór trybu pracy traktora za pomocą drzewa decyzyjnego - **Autor podprojektu:** Kamila Matysiak ### Drzewo Decyzyjne -Projekt wykorzystuje drzewo decyzyjne do wybrania najoptymalniejszego trybu. Uruchamia się go za pomocą klawisza **F6**. +Projekt wykorzystuje drzewo decyzyjne do wybrania czynności dla każdego pola, a następnie wysłania traktora do pól zgodnych z obecnie wybranym trybem. -#### Przygotowanie Danych: +Projekt używa metody CART (Classification and Regression Tree). Tworzy on drzewo binarne, w którym rozpatruje wszystkie możliwe podziały zbioru wartości cech na dwa rozłączne i uzupełniające się podzbiory dla cech dyskretnych. -Za przygotowanie danych odpowiedzialne są dwie funkcje: -**find_best_action**, która pobiera macierz pól, tworzy macierz czynności do wykonania, a następnie buduje drzewo. +Uruchamia się go za pomocą klawisza **F6**. + +#### Zbiór uczący: + +Zbiorem uczącym jest zestaw danych informujących drzewo jak postępować z polem o danych parametrach. +Kolejne cyfry odpowiadają za: nawodnienie pola, obecność chwastów, czy pole jest puste, czy jest do zbioru. ``` - def find_best_action(self): - testing_data = [] - matrix = self.field.get_matrix() # pobranie macierzy pól - matrix_todo = [] - for i in range(10): - matrix_todo.append([]) - verse = matrix[i] - for j in range(len(verse)): - coord = (i, j) - current_field = check(verse[j]) # czynnosci ktore trzeba jeszcze zrobic na kazdym polu - matrix_todo[i].append([]) - for action in current_field: - matrix_todo[i][j].append(action[-1]) - testing_data.extend(current_field) - if len(testing_data) > 0: - x = build_tree(testing_data) # zbudowanie drzewa - print_tree(x) - if isinstance(x, Leaf): # wybór najlepszej czynności do wykonania - self.best_action = self.find_remaining_action(matrix_todo) - return - self.best_action = x.question.column - print(header[x.question.column]) - print(x.question.value) - else: - self.best_action = self.find_remaining_action(matrix_todo) - return - -``` -Drugą funkcją jest **check**, która interpretuje pola z macierzy na podstawie numerów, dodając stringa z czynnością do wykonania na danym polu. - -``` -def check(field): - if field == 0: - return [[0, 0, 1, 0, "Zasadzic"], [0, 0, 1, 0, "Podlac"]] - elif field == 1: - return [[0, 1, 1, 0, "Odchwascic"], [0, 1, 1, 0, "Podlac"], [0, 1, 1, 0, "Zasadzic"]] - elif field == 2: - return [[0, 0, 0, 0, "Podlac"]] - elif field == 3: - return [[0, 1, 0, 0, "Odchwascic"], [0, 1, 0, 0, "Podlac"]] - elif field == 4: - return [[1, 0, 1, 0, "Zasadzic"]] - elif field == 5: - return [[1, 1, 1, 0, "Odchwascic"], [1, 1, 1, 0, "Zasadzic"]] - elif field == 6: - return [] - elif field == 7: - return [[1, 1, 0, 0, "Odchwascic"]] - elif field == 8: - return [[0, 0, 0, 1, "Zebrac"], [0, 0, 0, 1, "Potem podlac"], [0, 0, 0, 1, "Potem zasadzic"]] - else: - print("Błąd: Zły numer pola.") - +training_data = [[0, 0, 1, 0, "Zasadzic"], + [0, 1, 1, 0, "Odchwascic"], + [0, 0, 0, 0, "Podlac"], + [0, 1, 0, 0, "Odchwascic"], + [1, 0, 1, 0, "Zasadzic"], + [1, 1, 1, 0, "Odchwascic"], + [1, 0, 0, 0, "Czekac"], + [1, 1, 0, 0, "Odchwascic"], + [0, 0, 0, 1, "Zebrac"]] + self.tree = build_tree(training_data) + print_tree(self.tree) ``` -#### Budowanie Drzewa: +#### Algotytm tworzenia drzewa: Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie zapytania dzieli nam dane na spełnione i niespełnione wiersze: @@ -88,9 +48,9 @@ def partition(rows, question): return true_rows, false_rows ``` -Następnie wyokrzystujemy **Index Gini** i **Info Gain**. - Index Gini mierzy jak często losowo wybrany element będzie źle zindentyfikowany. - Information gain mierzy zmianę entropii, która powstaje na skutek podziału zestawu danych testowych na mniejsze części. +Następnie wyokrzystujemy **Index Gini**, który mierzy jak często losowo wybrany element będzie źle zindentyfikowany. Gdy jest równy 0, oznacza to, że element zostanie właściwie oznaczony. + + ``` # funkcja implementująca indeks gini @@ -102,7 +62,6 @@ def gini(rows): impurity -= prob_of_lbl ** 2 return impurity -#information gain def info_gain(left, right, current_uncertainty): p = float(len(left)) / (len(left) + len(right)) return current_uncertainty - p * gini(left) - (1 - p) * gini(right) @@ -148,22 +107,20 @@ def build_tree(rows): #### Integracja: -Gdy za pomocą funkcji **find_best_action** zostanie wybrana najbardziej opłacalna czynność wykorzystujemy algorytm A* zaimplementowany w pliku **pathfinding.py**. Ustawiamy tryb traktora i w pętli każemy znajdować mu pola. +Program sczytuje dane z głównego projektu, następnie interpretuje je za pomocą prostej funkcji **translate**, która zwraca informacje o stanie pola. Następnie za pomocą drzewa określamy czynność, jaka powinna zostać wykonana na tym polu. Wykonanie pracy zlecamy klasie **pathfinding**, która za pomocą algorytmu A* wysyła traktor na pola odpowiadające wybranemu trybowi. ``` - def do_best_action(self): - self.traktor.set_mode(self.best_action) - while self.path.pathfinding(self.traktor, self.field, self.ui) != 0: - pass + def search_field(self): + matrix = self.field.get_matrix() + for i in range(len(matrix)): + for j in range(len(matrix[i])): + print("Pole (%d,%d) Przewidziania czynnosc: %s" + % (i, j, print_leaf(classify(translate(matrix[i][j]), self.tree)))) + if work[self.traktor.get_mode()] in self.work_field(classify(translate(matrix[i][j]), self.tree)): + print("Zgodna z aktualnym trybem, czynnosc wykonywana") + self.path.find_path(self.traktor, self.field, self.ui, [j, i]) + self.ui.update() + time.sleep(0.5) ``` -Kiedy zostanie już tylko jedna czynność do wykonania przypisujemy jej **find_remaining_action**, dzięki czemu nasze pole zostanie w pełni oprawione. -``` - def find_remaining_action(self, matrix_todo): - for row in matrix_todo: - for field in row: - for action in field: - print(action) - return work.index(action) - return -1 -``` \ No newline at end of file + From 8d1f64fd582477e27f61abe22d4520b1da58ea39 Mon Sep 17 00:00:00 2001 From: Kamila Matysiak Date: Sun, 24 May 2020 20:15:54 +0000 Subject: [PATCH 6/6] Zaktualizuj 'decisiontree.md' --- decisiontree.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/decisiontree.md b/decisiontree.md index 6036691..8a86b3a 100644 --- a/decisiontree.md +++ b/decisiontree.md @@ -20,14 +20,14 @@ Kolejne cyfry odpowiadają za: nawodnienie pola, obecność chwastów, czy pole ``` training_data = [[0, 0, 1, 0, "Zasadzic"], - [0, 1, 1, 0, "Odchwascic"], - [0, 0, 0, 0, "Podlac"], - [0, 1, 0, 0, "Odchwascic"], - [1, 0, 1, 0, "Zasadzic"], - [1, 1, 1, 0, "Odchwascic"], - [1, 0, 0, 0, "Czekac"], - [1, 1, 0, 0, "Odchwascic"], - [0, 0, 0, 1, "Zebrac"]] + [0, 1, 1, 0, "Odchwascic"], + [0, 0, 0, 0, "Podlac"], + [0, 1, 0, 0, "Odchwascic"], + [1, 0, 1, 0, "Zasadzic"], + [1, 1, 1, 0, "Odchwascic"], + [1, 0, 0, 0, "Czekac"], + [1, 1, 0, 0, "Odchwascic"], + [0, 0, 0, 1, "Zebrac"]] self.tree = build_tree(training_data) print_tree(self.tree) ```