preparing new evaluation method
This commit is contained in:
parent
006bf59eb0
commit
7d6d835a01
File diff suppressed because it is too large
Load Diff
@ -659,6 +659,9 @@ class RecipeTreeNode(object):
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
def serialize_subtree(self):
|
||||||
|
return [n.serialize() for n in self.traverse()]
|
||||||
|
|
||||||
def node_score(self):
|
def node_score(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@ -781,8 +784,8 @@ class MixNode(RecipeTreeNode):
|
|||||||
#if c_grouped_mix[ia,ib] > 0 or c_grouped_mix[ib,ia] > 0:
|
#if c_grouped_mix[ia,ib] > 0 or c_grouped_mix[ib,ia] > 0:
|
||||||
# s += 1
|
# s += 1
|
||||||
|
|
||||||
ia = m_mix._label_index[grouped_ing_a.to_json()]
|
ia = m_mix._label_index[ing_a.to_json()]
|
||||||
ib = m_mix._label_index[grouped_ing_b.to_json()]
|
ib = m_mix._label_index[ing_b.to_json()]
|
||||||
|
|
||||||
if c_mix[ia,ib] > 0 or c_mix[ib,ia] > 0:
|
if c_mix[ia,ib] > 0 or c_mix[ib,ia] > 0:
|
||||||
s += 1
|
s += 1
|
||||||
@ -1290,10 +1293,10 @@ class Tree(object):
|
|||||||
if node.name() in constant_ingredients:
|
if node.name() in constant_ingredients:
|
||||||
node._constant = True
|
node._constant = True
|
||||||
|
|
||||||
return Tree(root)
|
return Tree(root, main_ingredients)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_serialization(s):
|
def from_serialization(s, main_ingredients = None):
|
||||||
def empty_node(raw_n):
|
def empty_node(raw_n):
|
||||||
if raw_n['type'] == "MixNode":
|
if raw_n['type'] == "MixNode":
|
||||||
node = MixNode(raw_n['constant'])
|
node = MixNode(raw_n['constant'])
|
||||||
@ -1317,7 +1320,7 @@ class Tree(object):
|
|||||||
for c in childs:
|
for c in childs:
|
||||||
nodes[id].add_child(nodes[c])
|
nodes[id].add_child(nodes[c])
|
||||||
|
|
||||||
return Tree(nodes[s[0]['id']])
|
return Tree(nodes[s[0]['id']], main_ingredients)
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, root, main_ingredients=None):
|
def __init__(self, root, main_ingredients=None):
|
||||||
@ -1354,6 +1357,7 @@ class Tree(object):
|
|||||||
|
|
||||||
def collect_scores(self):
|
def collect_scores(self):
|
||||||
self._mix_scores = []
|
self._mix_scores = []
|
||||||
|
self._mix_weights = []
|
||||||
self._act_scores = []
|
self._act_scores = []
|
||||||
self._ing_scores = []
|
self._ing_scores = []
|
||||||
|
|
||||||
@ -1366,6 +1370,7 @@ class Tree(object):
|
|||||||
for n in nodes:
|
for n in nodes:
|
||||||
if type(n) == MixNode:
|
if type(n) == MixNode:
|
||||||
self._mix_scores.append(n.node_score())
|
self._mix_scores.append(n.node_score())
|
||||||
|
self._mix_weights.append(len(n.childs()))
|
||||||
self._n_mix_nodes += 1
|
self._n_mix_nodes += 1
|
||||||
if type(n) == ActionNode:
|
if type(n) == ActionNode:
|
||||||
self._act_scores.append(n.node_score())
|
self._act_scores.append(n.node_score())
|
||||||
@ -1385,12 +1390,13 @@ class Tree(object):
|
|||||||
seen_ingredients.add(n.name())
|
seen_ingredients.add(n.name())
|
||||||
|
|
||||||
self._mix_scores = np.array(self._mix_scores)
|
self._mix_scores = np.array(self._mix_scores)
|
||||||
|
self._mix_weights = np.array(self._mix_weights)
|
||||||
self._act_scores = np.array(self._act_scores)
|
self._act_scores = np.array(self._act_scores)
|
||||||
self._ing_scores = np.array(self._ing_scores)
|
self._ing_scores = np.array(self._ing_scores)
|
||||||
|
|
||||||
|
|
||||||
def mix_scores(self):
|
def mix_scores(self):
|
||||||
return self._mix_scores
|
return self._mix_scores, self._mix_weights
|
||||||
|
|
||||||
def action_scores(self):
|
def action_scores(self):
|
||||||
return self._act_scores
|
return self._act_scores
|
||||||
@ -1426,11 +1432,11 @@ class Tree(object):
|
|||||||
return self._score
|
return self._score
|
||||||
|
|
||||||
self.collect_scores()
|
self.collect_scores()
|
||||||
s_mix = self.mix_scores()
|
s_mix, s_mix_weights = self.mix_scores()
|
||||||
s_act = self.action_scores()
|
s_act = self.action_scores()
|
||||||
s_ing = self.ing_scores()
|
s_ing = self.ing_scores()
|
||||||
|
|
||||||
n = len(s_mix) + len(s_act) + len(s_ing)
|
#n = len(s_mix) + len(s_act) + len(s_ing)
|
||||||
|
|
||||||
avg_mix = np.average(s_mix) if len(s_mix) > 0 else 1
|
avg_mix = np.average(s_mix) if len(s_mix) > 0 else 1
|
||||||
avg_act = np.average(s_act) if len(s_act) > 0 else 1
|
avg_act = np.average(s_act) if len(s_act) > 0 else 1
|
||||||
@ -1441,21 +1447,34 @@ class Tree(object):
|
|||||||
sum_ing = np.sum(s_ing) if len(s_ing) > 0 else 0
|
sum_ing = np.sum(s_ing) if len(s_ing) > 0 else 0
|
||||||
|
|
||||||
self._touched = False
|
self._touched = False
|
||||||
|
contains_main_ingred = True
|
||||||
|
|
||||||
# boost creativity
|
base_main_ings = [i._base_ingredient for i in self.root().traverse_ingredients()]
|
||||||
if len(s_act) < 3:
|
for ing in self._main_ingredients:
|
||||||
self._score = 0
|
if ing not in base_main_ings:
|
||||||
elif len(s_ing) < 3:
|
contains_main_ingred = False
|
||||||
self._score = 0
|
self._score = 0
|
||||||
else:
|
break
|
||||||
self._score = (sum_mix + sum_act + sum_ing) / n
|
|
||||||
self._score *= (len(s_ing) - self._n_duplicates) / len(s_ing)
|
if contains_main_ingred:
|
||||||
#self._score = 0.95 * self._score + 0.05 * self.main_ingredient_score()
|
# boost creativity
|
||||||
|
if len(s_act) < 3:
|
||||||
|
self._score = 0
|
||||||
|
elif len(s_ing) < 3:
|
||||||
|
self._score = 0
|
||||||
|
else:
|
||||||
|
weighted_mix_score = np.array([s_mix[i] * s_mix_weights[i] for i in range(len(s_mix))])
|
||||||
|
#print(weighted_mix_score)
|
||||||
|
n = len(s_act) + len(s_ing) + np.sum(s_mix_weights)
|
||||||
|
self._score = (np.sum(weighted_mix_score) + sum_act + sum_ing) / n
|
||||||
|
#print(self._score)
|
||||||
|
self._score *= (len(s_ing) - self._n_duplicates) / len(s_ing)
|
||||||
|
#self._score = 0.95 * self._score + 0.05 * self.main_ingredient_score()
|
||||||
|
|
||||||
return self._score
|
return self._score
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Tree.from_serialization(self.serialize())
|
return Tree.from_serialization(self.serialize(), self._main_ingredients)
|
||||||
|
|
||||||
|
|
||||||
# ## Population
|
# ## Population
|
||||||
@ -1494,8 +1513,59 @@ class Population(object):
|
|||||||
|
|
||||||
self.population = new_population
|
self.population = new_population
|
||||||
|
|
||||||
|
def crossover(self):
|
||||||
|
# shuffle indices
|
||||||
|
indices = list(range(len(self.population) // 2))
|
||||||
|
indices = [i + len(self.population) // 2 for i in indices]
|
||||||
|
random.shuffle(indices)
|
||||||
|
|
||||||
|
# perform crossover for random pairs
|
||||||
|
for i in range(len(self.population) // 4):
|
||||||
|
i_a = indices[2*i]
|
||||||
|
i_b = indices[2*i+1]
|
||||||
|
|
||||||
|
self.pairwise_crossover(self.population[i_a], self.population[i_b])
|
||||||
|
|
||||||
|
|
||||||
|
def pairwise_crossover(self, tree_a, tree_b):
|
||||||
|
# for crossover: find a random subtree in both trees, and switch them
|
||||||
|
|
||||||
|
# first, select one random mix node from both
|
||||||
|
a_nodes = tree_a.root().traverse()
|
||||||
|
b_nodes = tree_b.root().traverse()
|
||||||
|
|
||||||
|
a_mix_nodes = []
|
||||||
|
b_mix_nodes = []
|
||||||
|
|
||||||
|
for n in a_nodes:
|
||||||
|
if type(n) == MixNode:
|
||||||
|
a_mix_nodes.append(n)
|
||||||
|
|
||||||
|
for n in b_nodes:
|
||||||
|
if type(n) == MixNode:
|
||||||
|
b_mix_nodes.append(n)
|
||||||
|
|
||||||
|
a_mix_node = np.random.choice(a_mix_nodes)
|
||||||
|
b_mix_node = np.random.choice(b_mix_nodes)
|
||||||
|
|
||||||
|
# now select one random child, we will switch the subtrees there
|
||||||
|
a_child = np.random.choice(list(a_mix_node.childs()))
|
||||||
|
b_child = np.random.choice(list(b_mix_node.childs()))
|
||||||
|
|
||||||
|
# ...and perform the switch
|
||||||
|
|
||||||
|
# manually remove references
|
||||||
|
a_mix_node.remove_child(a_child)
|
||||||
|
b_mix_node.remove_child(b_child)
|
||||||
|
|
||||||
|
# and add child to other subtree
|
||||||
|
a_mix_node.add_child(b_child)
|
||||||
|
b_mix_node.add_child(a_child)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def hold_best(self, n=10):
|
def hold_best(self, n=10):
|
||||||
scores = [tree.score() for tree in self.population]
|
scores = np.array([tree.score() for tree in self.population])
|
||||||
|
|
||||||
sorted_indices = np.argsort(-scores)
|
sorted_indices = np.argsort(-scores)
|
||||||
|
|
||||||
@ -1505,8 +1575,8 @@ class Population(object):
|
|||||||
avg_scores = []
|
avg_scores = []
|
||||||
for i in tqdm(range(n), desc="run evolutionary cycles"):
|
for i in tqdm(range(n), desc="run evolutionary cycles"):
|
||||||
self.mutate()
|
self.mutate()
|
||||||
#self.mutate()
|
|
||||||
#self.collect_scores()
|
self.crossover()
|
||||||
|
|
||||||
self.pairwise_competition()
|
self.pairwise_competition()
|
||||||
#self.collect_scores()
|
#self.collect_scores()
|
||||||
@ -1530,17 +1600,13 @@ class Population(object):
|
|||||||
|
|
||||||
# ## Run Evolutionary Algorithm
|
# ## Run Evolutionary Algorithm
|
||||||
|
|
||||||
#p = Population(["noodle"],['noodle'], min_additional=4, max_additional=13, n_population = 50)
|
p = Population(["noodle"],['noodle'], min_additional=4, max_additional=13, n_population = 50, mutations=1)
|
||||||
|
|
||||||
|
|
||||||
#p_ingredient_unprepared(list(p.population[0].root().childs())[0]._name) < 0.2
|
#p_ingredient_unprepared(list(p.population[0].root().childs())[0]._name) < 0.2
|
||||||
|
|
||||||
|
|
||||||
#p.run(50)
|
#avg = p.run(10)
|
||||||
|
|
||||||
|
|
||||||
#p.plot_population(n_best=20)
|
#p.plot_population(n_best=20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user