f
This commit is contained in:
parent
c8afe48b63
commit
47f6311d71
30
final-evaluation.md
Normal file
30
final-evaluation.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Waiter project - Tao-Sen Chang, Weronika Skowronska, Martyna Druminska
|
||||||
|
|
||||||
|
The main objective of our program is to help the customer with their
|
||||||
|
order, serve meals and pick up dirty plates. Since the program emulates
|
||||||
|
real life circumstances, where the waiter should work efficiently, we
|
||||||
|
used reinforcement learning to train the agent to arrive at the tables
|
||||||
|
as fast as possible by taking note of the table’s coordinates. If the
|
||||||
|
plates happen to be empty, meaning that they probably have not ordered
|
||||||
|
yet, the program renders a couple questions to determine if the customer
|
||||||
|
would like a vegan menu or not. We used the decision tree learning
|
||||||
|
algorithm, to make the best recommendation to the customer. Every 10
|
||||||
|
plates visited, the program asks the user whether they would like to
|
||||||
|
exit the program or not. At beginning of our project, we use
|
||||||
|
reinforcement learning to get the shortest route for our agent to
|
||||||
|
traversal specific tables. Reinforcement learning is how software agent
|
||||||
|
ought to take actions in an environment in order to maximize the notion
|
||||||
|
of cumulative reward. The agent makes a sequence of decisions, and
|
||||||
|
learns to perform the best actions every step. After tons of training
|
||||||
|
loops, the agent could get the optimal strategy which might collect
|
||||||
|
maximal reward. In the case of our program, the “maximal reward”, would
|
||||||
|
be to find the minimum distance to the customer, which in turn would
|
||||||
|
save time and effort. Next, we used decision trees to make a prediction
|
||||||
|
on whether the person would like a vegan menu or not, based on the
|
||||||
|
“customers” appearance. The decision tree algorithm learns off of a
|
||||||
|
dataset with a diverse set of variables to make the best prediction. The
|
||||||
|
program generates a flow-like structure that represents the decisions,
|
||||||
|
where each node is a “test” on an attribute. The decision tree finishes
|
||||||
|
when there are only leaf nodes left. In conclusion, we managed to create
|
||||||
|
a program that runs efficiently and cohesively to satisfy the needs of
|
||||||
|
the customer.
|
478
waiter1406.py
Normal file
478
waiter1406.py
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
#### MD #######
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import pygame
|
||||||
|
from sklearn.model_selection import train_test_split
|
||||||
|
from sklearn.preprocessing import LabelEncoder
|
||||||
|
from sklearn.tree import DecisionTreeClassifier
|
||||||
|
from sklearn.metrics import accuracy_score
|
||||||
|
from sklearn.metrics import confusion_matrix
|
||||||
|
from pygame.locals import *
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from sklearn import tree
|
||||||
|
import random
|
||||||
|
from textpygame import get_key, ask, display_box
|
||||||
|
###### /MD ######
|
||||||
|
|
||||||
|
|
||||||
|
import math
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
### WS ###
|
||||||
|
########################
|
||||||
|
# For CNN:
|
||||||
|
|
||||||
|
import keras
|
||||||
|
from keras.preprocessing import image
|
||||||
|
from keras.models import Sequential
|
||||||
|
from keras.layers import Convolution2D
|
||||||
|
from keras.layers import MaxPooling2D
|
||||||
|
from keras.layers import Flatten
|
||||||
|
from keras.layers import Dense
|
||||||
|
|
||||||
|
|
||||||
|
#initializing:
|
||||||
|
cnn_model = Sequential()
|
||||||
|
#Convolution:
|
||||||
|
cnn_model.add(Convolution2D(32, (3, 3), input_shape =(256, 256, 3), activation = "relu"))
|
||||||
|
#Pooling:
|
||||||
|
cnn_model.add(MaxPooling2D(pool_size = (2,2)))
|
||||||
|
|
||||||
|
# Adding a second convolutional layer
|
||||||
|
cnn_model.add(Convolution2D(32, 3, 3, activation = 'relu'))
|
||||||
|
cnn_model.add(MaxPooling2D(pool_size = (2, 2)))
|
||||||
|
|
||||||
|
#Flattening:
|
||||||
|
cnn_model.add(Flatten())
|
||||||
|
|
||||||
|
#Fully connected layers::
|
||||||
|
cnn_model.add(Dense(units = 128, activation = "relu"))
|
||||||
|
cnn_model.add(Dense(units = 3, activation = "softmax"))
|
||||||
|
|
||||||
|
# loading weigjts:
|
||||||
|
cnn_model.load_weights('s444523/best_model_weights2.h5')
|
||||||
|
#Making CNN:
|
||||||
|
cnn_model.compile(optimizer = "adam", loss = "categorical_crossentropy", metrics = ["accuracy"])
|
||||||
|
|
||||||
|
########################
|
||||||
|
### /WS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### MD#####
|
||||||
|
|
||||||
|
#read csv file
|
||||||
|
dataset= pd.read_csv("veganism.csv")
|
||||||
|
|
||||||
|
|
||||||
|
#create a new dataset
|
||||||
|
newdataset = pd.DataFrame(dataset, columns=['ethnicity', 'gender', 'appearence', 'vegan'])
|
||||||
|
|
||||||
|
# creating instance of labelencoder
|
||||||
|
labelencoder = LabelEncoder()
|
||||||
|
# Assigning numerical values and storing in another column
|
||||||
|
newdataset['ethnicity_no'] = labelencoder.fit_transform(newdataset['ethnicity'])
|
||||||
|
newdataset['gender_no']= labelencoder.fit_transform(newdataset['gender'])
|
||||||
|
newdataset['appearence_no']= labelencoder.fit_transform(newdataset['appearence'])
|
||||||
|
|
||||||
|
|
||||||
|
# for x values drop unimportant columns, axis=1 specifies that we want the columns not rows
|
||||||
|
Y=newdataset['vegan']
|
||||||
|
X=newdataset.drop(newdataset.columns[0:4], axis=1)
|
||||||
|
|
||||||
|
|
||||||
|
#test 14% of the data
|
||||||
|
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.15)
|
||||||
|
classifier = DecisionTreeClassifier()
|
||||||
|
classifier.fit(X_train, Y_train)
|
||||||
|
y_pred = classifier.predict(X_test)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn=['ethnicity','gender','appearence']
|
||||||
|
cn=['yes', 'no']
|
||||||
|
|
||||||
|
# Setting dpi = 300 to make image clearer than default (for the decision tree visualisation)
|
||||||
|
fig, axes = plt.subplots(nrows = 1,ncols = 1,figsize = (4,4), dpi=300)
|
||||||
|
|
||||||
|
tree.plot_tree(classifier,
|
||||||
|
feature_names = fn,
|
||||||
|
class_names=cn,
|
||||||
|
filled = True);
|
||||||
|
|
||||||
|
fig.savefig('imagenamenew.png')
|
||||||
|
|
||||||
|
|
||||||
|
class Customer:
|
||||||
|
def __init__(self, coordinate_i, coordinate_j):
|
||||||
|
self.coordinate_i = coordinate_i
|
||||||
|
self.coordinate_j = coordinate_j
|
||||||
|
change_value(coordinate_i, coordinate_j,1 , 4)
|
||||||
|
class CustomerPlace:
|
||||||
|
def __init__(self, coordinate_i, coordinate_j):
|
||||||
|
self.coordinate_i = coordinate_i
|
||||||
|
self.coordinate_j = coordinate_j
|
||||||
|
change_value(coordinate_i, coordinate_j,1 , 5)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### /MD #######
|
||||||
|
# Colors:
|
||||||
|
# Define some colors
|
||||||
|
BLACK = (0, 0, 0)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
GREEN = (0, 255, 0)
|
||||||
|
RED = (255, 0, 0)
|
||||||
|
BLUE = (0, 0, 240)
|
||||||
|
YELLOW = (255, 255, 0)
|
||||||
|
#Width and Height of each square:
|
||||||
|
WIDTH = 20
|
||||||
|
HEIGHT = 20
|
||||||
|
|
||||||
|
#Margin:
|
||||||
|
MARGIN = 5
|
||||||
|
grid = [[0 for x in range(16)] for y in range(16)]
|
||||||
|
|
||||||
|
def change_value(i, j, width, n):
|
||||||
|
for r in range (i, i+width):
|
||||||
|
for c in range (j, j+width):
|
||||||
|
grid[r][c] = n
|
||||||
|
|
||||||
|
class Table:
|
||||||
|
def __init__(self, coordinate_i, coordinate_j):
|
||||||
|
self.coordinate_i = coordinate_i
|
||||||
|
self.coordinate_j = coordinate_j
|
||||||
|
change_value(coordinate_i, coordinate_j, 2, 1)
|
||||||
|
def get_destination_coor(self):
|
||||||
|
return [self.coordinate_i+2, self.coordinate_j+2]
|
||||||
|
|
||||||
|
########################
|
||||||
|
### WS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
# The finction "state of meal" chooses a photo of a plate at the given table.
|
||||||
|
def state_of_meal(self):
|
||||||
|
## !!!!!!###
|
||||||
|
num = np.random.randint(67, 100)
|
||||||
|
## !!!!!!###
|
||||||
|
|
||||||
|
if num<=67:
|
||||||
|
img_name = 'plates/{}.png'.format(num)
|
||||||
|
else:
|
||||||
|
img_name = 'plates/{}.jpg'.format(num)
|
||||||
|
return img_name
|
||||||
|
|
||||||
|
# The function "change state" changes the value of the state variable.
|
||||||
|
# It informs, whether the client are waiting for the waiter to make an order
|
||||||
|
# (0 - empty plates) are eating (2 - full plates) or are waiting for the
|
||||||
|
# waiter to get a recipt (1 - dirty plates)
|
||||||
|
|
||||||
|
def change_state(self, st):
|
||||||
|
self.state = st
|
||||||
|
|
||||||
|
########################
|
||||||
|
### /WS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
class Kitchen:
|
||||||
|
def __init__(self, coordinate_i, coordinate_j):
|
||||||
|
self.coordinate_i = coordinate_i
|
||||||
|
self.coordinate_j = coordinate_j
|
||||||
|
change_value(coordinate_i, coordinate_j, 3, 2)
|
||||||
|
|
||||||
|
class Agent:
|
||||||
|
def __init__(self,orig_coordinate_i, orig_coordinate_j):
|
||||||
|
self.orig_coordinate_i = orig_coordinate_i
|
||||||
|
self.orig_coordinate_j = orig_coordinate_j
|
||||||
|
self.state = np.array([orig_coordinate_i,orig_coordinate_j])
|
||||||
|
change_value(orig_coordinate_j, orig_coordinate_j, 1, 3)
|
||||||
|
self.state_update(orig_coordinate_i, orig_coordinate_j)
|
||||||
|
|
||||||
|
def state_update(self, c1, c2):
|
||||||
|
self.state[0] = c1
|
||||||
|
self.state[1] = c2
|
||||||
|
|
||||||
|
def leave(self):
|
||||||
|
change_value(self.state[0], self.state[1], 1, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def move_to(self, nextPos):
|
||||||
|
self.leave()
|
||||||
|
nextPos_x, nextPos_y = nextPos
|
||||||
|
self.state_update(nextPos_x, nextPos_y)
|
||||||
|
change_value(self.state[0], self.state[1], 1, 3)
|
||||||
|
|
||||||
|
########################
|
||||||
|
### WS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
#The function "define_table" serches for the apropriate table in the
|
||||||
|
# table_dict (to enable the usage of class attributes and methods)
|
||||||
|
def define_table(self, t_num):
|
||||||
|
t_num = 'table{}'.format(t_num)
|
||||||
|
t_num = table_dict[t_num]
|
||||||
|
return t_num
|
||||||
|
|
||||||
|
# The function "check_plates" uses the pretrained CNN model to classify
|
||||||
|
# the plate on the table as empty(0), full(2) or dirty(1)
|
||||||
|
def check_plates(self, table_number):
|
||||||
|
table = self.define_table(table_number)
|
||||||
|
plate = table.state_of_meal()
|
||||||
|
plate= image.load_img(plate, target_size = (256, 256))
|
||||||
|
plate = image.img_to_array(plate)
|
||||||
|
#plate = plate.reshape((256, 256))
|
||||||
|
plate = np.expand_dims(plate, axis = 0)
|
||||||
|
|
||||||
|
result = cnn_model.predict(plate)[0]
|
||||||
|
print(result)
|
||||||
|
if result[1] == 1:
|
||||||
|
result[1] = 0
|
||||||
|
x = int(input("Excuse me, have You done eating? 1=Yes, 2 = No \n"))
|
||||||
|
result[x] = 1
|
||||||
|
for i, x in enumerate(result):
|
||||||
|
if result[i] == 1:
|
||||||
|
table.change_state(i)
|
||||||
|
return i
|
||||||
|
########################
|
||||||
|
### /WS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
|
||||||
|
def check_done():
|
||||||
|
for event in pygame.event.get(): # Checking for the event
|
||||||
|
if event.type == pygame.QUIT: # If the program is closed:
|
||||||
|
return True # To exit the loop
|
||||||
|
|
||||||
|
def draw_grid():
|
||||||
|
for row in range(16): # Drawing the grid
|
||||||
|
for column in range(16):
|
||||||
|
color = WHITE
|
||||||
|
if grid[row][column] == 1:
|
||||||
|
color = GREEN
|
||||||
|
if grid[row][column] == 2:
|
||||||
|
color = RED
|
||||||
|
if grid[row][column] == 3:
|
||||||
|
color = BLUE
|
||||||
|
pygame.draw.rect(screen,
|
||||||
|
color,
|
||||||
|
[(MARGIN + WIDTH) * column + MARGIN,
|
||||||
|
(MARGIN + HEIGHT) * row + MARGIN,
|
||||||
|
WIDTH,
|
||||||
|
HEIGHT])
|
||||||
|
|
||||||
|
|
||||||
|
## default positions of the agent:
|
||||||
|
x = 12
|
||||||
|
y = 12
|
||||||
|
agent = Agent(x, y)
|
||||||
|
table1 = Table(2, 2)
|
||||||
|
table2 = Table (2,7)
|
||||||
|
table3 = Table(2, 12)
|
||||||
|
table4 = Table(7, 2)
|
||||||
|
table5 = Table(7, 7)
|
||||||
|
table6 = Table(7, 12)
|
||||||
|
table7 = Table(12, 2)
|
||||||
|
table8 = Table(12, 7)
|
||||||
|
|
||||||
|
|
||||||
|
################### WS #####################
|
||||||
|
# I added the dict to loop through tables.
|
||||||
|
table_dict = {"table1":table1, "table2":table2, "table3":table3,"table4":table4,
|
||||||
|
"table5":table5,"table6":table6,"table7":table7,"table8":table8
|
||||||
|
}
|
||||||
|
################### WS #####################
|
||||||
|
|
||||||
|
pygame.init()
|
||||||
|
|
||||||
|
|
||||||
|
####MD ####
|
||||||
|
'''
|
||||||
|
# create a font object.
|
||||||
|
# 1st parameter is the font file
|
||||||
|
# which is present in pygame.
|
||||||
|
# 2nd parameter is size of the font
|
||||||
|
font = pygame.font.Font('freesansbold.ttf', 14)
|
||||||
|
X = 400
|
||||||
|
Y = 400
|
||||||
|
# create a text suface object,
|
||||||
|
# on which text is drawn on it.
|
||||||
|
text = font.render('waiter: hello, let me help you with your order.', True, WHITE, BLACK)
|
||||||
|
userText=font.render('user: ', True, BLUE, BLACK)
|
||||||
|
# create a rectangular object for the
|
||||||
|
# text surface object
|
||||||
|
textRect = text.get_rect()
|
||||||
|
inputRect = userText.get_rect()
|
||||||
|
# set the center of the rectangular object.
|
||||||
|
textRect.center= (200, 340)
|
||||||
|
inputRect.center=(200,370)
|
||||||
|
|
||||||
|
'''
|
||||||
|
#### /MD ####
|
||||||
|
|
||||||
|
|
||||||
|
#class Kitchen:
|
||||||
|
kitchen = Kitchen(13, 13)
|
||||||
|
|
||||||
|
WINDOW_SIZE = [405, 405]
|
||||||
|
screen = pygame.display.set_mode(WINDOW_SIZE)
|
||||||
|
|
||||||
|
pygame.display.set_caption("Waiter_Grid3")
|
||||||
|
|
||||||
|
done = False
|
||||||
|
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
|
with open('res_targets_4-1.data', 'rb') as filehandle:
|
||||||
|
# read the data as binary data stream
|
||||||
|
trained_route = pickle.load(filehandle)
|
||||||
|
|
||||||
|
destination = (4, 14)
|
||||||
|
trained_route.append(destination)
|
||||||
|
|
||||||
|
table_targets = [(9, 4),(4, 4),(4, 9),(4, 14)]
|
||||||
|
|
||||||
|
|
||||||
|
destination_tables = []
|
||||||
|
|
||||||
|
###### MD /########3
|
||||||
|
x=[2,7,12]
|
||||||
|
y=[2,7]
|
||||||
|
|
||||||
|
random_customer_seat_x=random.choice(x)
|
||||||
|
random_customer_seat_y=random.choice(y)
|
||||||
|
print(random_customer_seat_x,random_customer_seat_y)
|
||||||
|
seat=Customer(random_customer_seat_x,random_customer_seat_y)
|
||||||
|
|
||||||
|
next_to=CustomerPlace(random_customer_seat_x,random_customer_seat_y-1)
|
||||||
|
|
||||||
|
WINDOW_SIZE = [405, 405]
|
||||||
|
screen = pygame.display.set_mode(WINDOW_SIZE)
|
||||||
|
|
||||||
|
pygame.display.set_caption("Waiter_Grid3")
|
||||||
|
|
||||||
|
done = False
|
||||||
|
print(random_customer_seat_x,random_customer_seat_y-1)
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#updating the drawing
|
||||||
|
def updateDraw():
|
||||||
|
x = agent.state[0]
|
||||||
|
y = agent.state[1]
|
||||||
|
screen.fill(BLACK) # Background color
|
||||||
|
for row in range(16): # Drawing the grid
|
||||||
|
for column in range(16):
|
||||||
|
color = WHITE
|
||||||
|
if grid[row][column] == 1:
|
||||||
|
color = GREEN
|
||||||
|
if grid[row][column] == 2:
|
||||||
|
color = RED
|
||||||
|
if grid[row][column] == 3:
|
||||||
|
color = BLUE
|
||||||
|
if grid[row][column] == 4:
|
||||||
|
color = MAGENTA
|
||||||
|
surface = pygame.draw.rect(screen,
|
||||||
|
color,
|
||||||
|
|
||||||
|
[(MARGIN + WIDTH) * column + MARGIN,
|
||||||
|
(MARGIN + HEIGHT) * row + MARGIN,
|
||||||
|
WIDTH,
|
||||||
|
HEIGHT])
|
||||||
|
|
||||||
|
def customer():
|
||||||
|
screen.blit(text, textRect)
|
||||||
|
ethnicity3 = input("Excuse me, What's you're ethnicity? <black>, <asian>, <white>\n")
|
||||||
|
gender3= input("Excuse me, What's you're gender? <male>, <female>, <other> \n")
|
||||||
|
appearence3=input("Excuse me, What's you're appearance? <hippie>, <other> \n")
|
||||||
|
if (ethnicity3 =="black"):
|
||||||
|
ethnicity3 = 1
|
||||||
|
elif ethnicity3 == "asian":
|
||||||
|
ethnicity3 = 0
|
||||||
|
else:
|
||||||
|
ethnicity3 = 2
|
||||||
|
|
||||||
|
if gender3 == "male":
|
||||||
|
gender3 = 0
|
||||||
|
else:
|
||||||
|
gender3 = 1
|
||||||
|
|
||||||
|
if appearence3 == "hippie":
|
||||||
|
appearence3= 0
|
||||||
|
else:
|
||||||
|
appearence3 = 1
|
||||||
|
prediction = classifier.predict([[ethnicity3, gender3, appearence3]])
|
||||||
|
#pygame.quit()
|
||||||
|
|
||||||
|
if prediction == [0]:
|
||||||
|
print("You're probably not vegan. Would you like a regular menu?")
|
||||||
|
else:
|
||||||
|
print("It seems like you're vegan. Would you like a vegan menu?")
|
||||||
|
#exit()
|
||||||
|
###### /MD ###
|
||||||
|
# -------- Main Program Loop -----------
|
||||||
|
exit_counter = 0
|
||||||
|
while not done:
|
||||||
|
screen.fill(BLACK) # Background color
|
||||||
|
draw_grid()
|
||||||
|
done = check_done()
|
||||||
|
new_route = trained_route[:]
|
||||||
|
for value in table_dict.values():
|
||||||
|
destination_tables.append(value.get_destination_coor())
|
||||||
|
num_of_table = 1
|
||||||
|
while len(new_route) != 0:
|
||||||
|
# move to next grid
|
||||||
|
agent.move_to(new_route[0])
|
||||||
|
|
||||||
|
# update the grid
|
||||||
|
pygame.time.delay(150)
|
||||||
|
screen.fill(BLACK)
|
||||||
|
draw_grid()
|
||||||
|
# Drawing the grid
|
||||||
|
clock.tick(100) # Limit to 60 frames per second
|
||||||
|
pygame.display.flip() # Updating the screen
|
||||||
|
|
||||||
|
# get current grid coordinate
|
||||||
|
x = agent.state[0]
|
||||||
|
y = agent.state[1]
|
||||||
|
# if reached the table, ask to collect the plates
|
||||||
|
if [x, y] in destination_tables:
|
||||||
|
########################
|
||||||
|
### WS ###
|
||||||
|
########################
|
||||||
|
#pygame.time.delay(100)
|
||||||
|
print("I'm at a table no. {}".format(num_of_table))
|
||||||
|
## Checking at what state are the plates:
|
||||||
|
state_of_table = agent.check_plates(num_of_table)
|
||||||
|
num_of_table +=1
|
||||||
|
|
||||||
|
if state_of_table == 0:
|
||||||
|
customer()
|
||||||
|
|
||||||
|
# Early stopping (after 10 rounds)
|
||||||
|
exit_counter += 1
|
||||||
|
print("exit_counter", exit_counter)
|
||||||
|
if exit_counter == 10:
|
||||||
|
play_again = 1
|
||||||
|
play_again = int(input("Exit? 0=No, 1=Yes \n"))
|
||||||
|
if play_again:
|
||||||
|
pygame.quit()
|
||||||
|
else:
|
||||||
|
exit_counter = 0
|
||||||
|
|
||||||
|
########################
|
||||||
|
### /WS ###
|
||||||
|
########################
|
||||||
|
destination_tables = destination_tables[1:]
|
||||||
|
|
||||||
|
new_route = new_route[1:]
|
||||||
|
|
||||||
|
# After each fool loop, we can quit the program:.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pygame.quit()
|
Loading…
Reference in New Issue
Block a user