Spaces:
Sleeping
Sleeping
File size: 13,067 Bytes
76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 76c9bfe 3cc63f3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
import random
from typing import Tuple, Dict, List
import matplotlib.pyplot as plt
import numpy as np
class Individual:
'''各個体のクラス
args: 個体の持つ遺伝子情報(np.array)'''
def __init__(self, genom_size):
self.body_hair = np.random.randint(0, 2, genom_size).tolist()
self.body_size = np.random.randint(0, 2, genom_size).tolist()
self.herd_num = np.random.randint(0, 2, genom_size).tolist()
self.eating = np.random.randint(0, 2, genom_size).tolist()
self.body_color = np.random.randint(0, 2, genom_size).tolist()
self.ferocity = np.random.randint(0, 2, genom_size).tolist()
self.all_genoms = {
"body_hair": self.body_hair,
"body_size": self.body_size,
"herd_num": self.herd_num,
"eating": self.eating,
"body_color": self.body_color,
"ferocity": self.ferocity,
}
self.fitness = {
"body_hair": 0,
"body_size": 0,
"herd_num": 0,
"eating": 0,
"body_color": 0,
"ferocity": 0,
} # 個体の適応度(set_fitness関数で設定)
self.set_fitness()
self.set_all_genoms()
def set_fitness(self):
'''個体に対する目的関数(OneMax)の値をself.fitnessに代入'''
self.fitness = {key: sum(value) for key, value in self.all_genoms.items()}
def get_fitness(self):
'''self.fitnessを出力'''
return self.fitness
def set_all_genoms(self):
'''self.all_parameterの中身をself.body_hair以下に代入する'''
self.body_hair = self.all_genoms["body_hair"]
self.body_size = self.all_genoms["body_size"]
self.herd_num = self.all_genoms["herd_num"]
self.eating = self.all_genoms["eating"]
self.body_color = self.all_genoms["body_color"]
self.ferocity = self.all_genoms["ferocity"]
def mutate(self):
'''遺伝子の突然変異'''
for i, (parameter, genom) in enumerate(self.all_genoms.items()):
tmp = genom.copy()
i = np.random.randint(0, len(genom) - 1)
tmp[i] = float(not genom[i])
self.all_genoms[parameter] = tmp
self.set_all_genoms()
self.set_fitness()
def random_temperature() -> float:
"""
火星の気温20℃〜-140℃の範囲でrandomにfloat値を返す
args
times (int): 試行回数
return
float: ランダムに作成した 火星の気温
"""
temperature = random.uniform(-140, 30)
return temperature
def random_food_volume(food_volume):
"""
餌の量
args
times (int): 試行回数
return
float: ランダムに作成した 火星の気温
"""
food_volume += random.randint(-100, 100)
if food_volume < 0:
food_volume = 0
return food_volume
def create_generation(POPURATIONS, GENOMS_SIZE):
'''初期世代の作成
return: 個体クラスのリスト'''
generation = {}
for i in range(POPURATIONS):
individual = Individual(GENOMS_SIZE)
generation[individual] = 0
return generation
def select_tournament(
generation_: List[Tuple[Individual, int]], TOUNAMENT_NUM
) -> List[Tuple[Individual, int]]:
"""
選択の関数(トーナメント方式)。すべてのgenerationから3つ選び、強い(scoreが最も高い)genomを1つ選ぶ。これをgenerationのサイズだけ繰り返す
args
generation List[Tuple[Individual, int]]: Individual で作成したゲノム情報 [["body_hair"], ["body_size"], ["herd_num"]] , 評価score
return
List[Tuple[Individual, int]] : トーナメント戦で生き残ったゲノム1つ
"""
selected_genoms = []
for i in range(len(generation_)):
# 最もスコアのよいgeneration を採用
tournament = random.sample(generation_, TOUNAMENT_NUM)
max_genom = max(tournament, key=lambda x: x[1])
selected_genoms.append(max_genom)
return selected_genoms
def cross_two_point_copy(child1, child2):
'''二点交叉'''
new_child1 = {}
new_child2 = {}
for parameter_genom_1, parameter_genom_2 in zip(child1[0].all_genoms.items(), child2[0].all_genoms.items()):
size = len(parameter_genom_1[1])
tmp_child_parameter1 = parameter_genom_1[0]
tmp_child_parameter2 = parameter_genom_2[0]
tmp_child_genom1 = parameter_genom_1[1].copy()
tmp_child_genom2 = parameter_genom_2[1].copy()
cxpoint1 = np.random.randint(1, size)
cxpoint2 = np.random.randint(1, size - 1)
if cxpoint2 >= cxpoint1:
cxpoint2 += 1
else:
cxpoint1, cxpoint2 = cxpoint2, cxpoint1
tmp_child_genom1[cxpoint1:cxpoint2], tmp_child_genom2[cxpoint1:cxpoint2] = tmp_child_genom2[cxpoint1:cxpoint2].copy(), tmp_child_genom1[cxpoint1:cxpoint2].copy()
child1[0].all_genoms[tmp_child_parameter1] = tmp_child_genom1
child2[0].all_genoms[tmp_child_parameter2] = tmp_child_genom2
child1[0].set_all_genoms()
child1[0].set_fitness()
child2[0].set_all_genoms()
child2[0].set_fitness()
return child1, child2
def crossover(selected, POPURATIONS, CROSSOVER_PB):
'''交叉の関数'''
children = []
if POPURATIONS % 2:
selected.append(selected[0])
for child1, child2 in zip(selected[::2], selected[1::2]):
if np.random.rand() < CROSSOVER_PB:
child1, child2 = cross_two_point_copy(child1, child2)
children.append(child1)
children.append(child2)
children = children[:POPURATIONS]
return children
def mutate(children, MUTATION_PB):
tmp_children = []
for child in children:
individual, score = child[0], child[1]
if np.random.rand() < MUTATION_PB:
individual.mutate()
tmp_children.append((individual, score))
return tmp_children
def reset_generation_score(generation_):
for i, (individual, score) in enumerate(generation_):
generation_[i] = (individual, 0)
return generation_
def scoring(generation_, temperature, food_volume):
MAX_NUM = 4 # fitness の最大値
THREASHOLD_TEMPRETURE = 10 # score の判定に用いる気温のしきい値
THREASHOLD_FOOD_VOLUME = 3000 # score の判定に用いる食料のしきい値
generation_ = reset_generation_score(generation_)
# scoring を実施
for i, (individual, score) in enumerate(generation_):
# 各パラメーターの特性値を探索
for parameter, fitness in individual.get_fitness().items():
# 気温が高い
if temperature > THREASHOLD_TEMPRETURE:
if parameter == "body_hair": # body_hair が小さいほうが有利、大きいほうが不利
score += MAX_NUM - fitness
elif parameter == "body_size": # body_size が小さいほうが有利、大きいほうが不利
score += MAX_NUM - fitness
elif parameter == "body_color": # body_color が暗い方が有利、明るいほうが不利
score += fitness
# 気温が低い
else:
if parameter == "body_hair": # body_hair が大きいほうが有利、小さいほうが不利
score += fitness
elif parameter == "body_size": # body_size が大きいほうが有利、小さいほうが不利
score += fitness
elif parameter == "body_color": # body_color が明るい方が有利、暗いほうが不利
score += MAX_NUM - fitness
# エサが多い
if food_volume > THREASHOLD_FOOD_VOLUME:
if parameter == "body_size": # body_size が大きいほうが有利、小さいほうが不利
score += fitness
elif parameter == "herd_num": # herd_num が大きいほうが有利、小さいほうが不利
score += fitness
elif parameter == "eating": # eating が大きい(肉食)ほうが有利、小さい(草食)ほうが不利
score += fitness
# エサが少ない
else:
if parameter == "body_size": # body_size が小さいほうが有利、大きいほうが不利
score += MAX_NUM - fitness
elif parameter == "herd_num": # herd_num が小さいほうが有利、大きいほうが不利
score += MAX_NUM - fitness
elif parameter == "eating": # eating が小さい(草食)ほうが有利、大さい(肉食)ほうが不利
score += MAX_NUM - fitness
# 強さ
if parameter == "body_size": # body_size が大きいほうが有利、小さい方が不利
score += fitness
elif parameter == "herd_num":
score += fitness
elif parameter == "ferocity": # ferocity が大きい(凶暴)ほうが有利、小さい(おとなしい)ほうが不利
score += fitness
# score を更新
generation_[i] = (individual, int(score))
return generation_
def ga_solve(generation, NUM_GENERATION, POPURATIONS, TOUNAMENT_NUM, CROSSOVER_PB, MUTATION_PB):
'''遺伝的アルゴリズムのソルバー
return: 最終世代の最高適応値の個体、最低適応値の個体'''
best = []
worst = []
temperature_transition = []
food_volume = 500
food_volume_transition = []
parameter_transiton = {
"body_size" : [],
"body_hair" : [],
"herd_num" : [],
"eating" : [],
"body_color" : [],
"ferocity" : [],
}
# --- Generation loop
print('Generation loop start.')
# Dict[Individual, int] から List[Tuple(individual, int)]へ変換
# Dict だと Key の重複ができないため
generation_ = [(individual, score) for individual, score in generation.items()]
for i in range(NUM_GENERATION):
temperature = random_temperature()
temperature_transition.append(temperature)
food_volume = random_food_volume(food_volume)
food_volume_transition.append(food_volume)
# スコアリング
generation_ = scoring(generation_, temperature, food_volume)
# --- Step1. Print fitness in the generation
best_individual_score = max(generation_, key=lambda x: x[1])
best.append(best_individual_score[0].fitness)
worst_individual_score = min(generation_, key=lambda x: x[1])
worst.append(worst_individual_score[0].fitness)
# print("Generation: " + str(i) \
# + ": Best fitness: " + str(best_individual_score[0].fitness) + "Best fitness score: " + str(best_individual_score[1]) \
# + ". Worst fitness: " + str(worst_individual_score[0].fitness) + "Worst fitness score: " + str(worst_individual_score[1])
# )
# --- Step2. Selection (Roulette)
selected_genoms = select_tournament(generation_, TOUNAMENT_NUM)
# --- Step3. Crossover (two_point_copy)
children = crossover(selected_genoms, POPURATIONS, CROSSOVER_PB)
# --- Step4. Mutation
generation_ = mutate(children, MUTATION_PB)
for parameter, genom in best_individual_score[0].all_genoms.items():
parameter_transiton[parameter].append(sum(genom))
best_individual_score[0].set_all_genoms()
best_individual_score[0].set_fitness()
print("Generation loop ended. The best individual: ")
print(best_individual_score[0].all_genoms)
plt.figure(figsize=(20, 5))
plt.title("temperature")
plt.plot(temperature_transition)
plt.ylabel("temperature Celsius")
plt.xlabel("generation")
plt.savefig("simlation_tempreture.png")
plt.figure(figsize=(20, 5))
plt.title("food volume")
plt.plot(food_volume_transition)
plt.ylim(0);
plt.ylabel("food volume")
plt.xlabel("generation")
plt.savefig("simlation_food_volume.png")
plt.figure(figsize=(20, 16))
for i, (parameter, transition) in enumerate(parameter_transiton.items()):
plt.subplot(6, 1, i+1)
plt.title(parameter)
plt.plot(transition, label=parameter)
plt.legend()
plt.ylim(0, 4)
plt.tight_layout()
plt.savefig("each_parameter_transition.png")
return best, worst
def get_word_for_image_generate(word_dict, best, index):
# アルゴリズムの結果に対応するwordを抽出
word_list = [word_dict[parameter][int(fitness)] for parameter, fitness in best[index].items()]
# 最終的な I/F 補足: スペース区切りの文字列 を渡す, 英語もありうる
word = " ".join(word_list)
return word |