KJMAN678 commited on
Commit
76c9bfe
·
1 Parent(s): 2b28e98

実行ファイルを追加、チームや取り組んだチャレンジ概要をREADME.mdに追記

Browse files
Files changed (3) hide show
  1. README.md +29 -3
  2. StableDiffusionSample.ipynb +0 -0
  3. simulation.py +439 -0
README.md CHANGED
@@ -5,11 +5,37 @@
5
  - Mr. Matsubara (松原さん)
6
  - Me, Shimizu (清水(記))
7
 
 
 
 
 
 
 
 
 
 
8
  - [Slide (Sorry, Japanese)](https://docs.google.com/presentation/d/1Umq53JqME-GUJN6TgCDA7Fu1CcQhMJTG/edit#slide=id.g15d379b926a_3_0)
9
 
10
  ### Output Images
 
 
 
 
 
11
  <div align="center">
12
- <img src="./images/first_generation.png" alt="エビフライトライアングル" title="サンプル" witdh="">
13
- <img src="./images/500th_generation.png" alt="エビフライトライアングル" title="サンプル" witdh="">
14
- <img src="./images/1000th_generation.png" alt="エビフライトライアングル" title="サンプル" witdh="">
 
 
 
15
 
 
 
 
 
 
 
 
 
 
 
5
  - Mr. Matsubara (松原さん)
6
  - Me, Shimizu (清水(記))
7
 
8
+ ### Choice Theme
9
+
10
+ - [BUILD A SPACE BIOLOGY SUPERHERO](https://2022.spaceappschallenge.org/challenges/2022-challenges/space-biology-superhero/details)
11
+
12
+ ### Discription
13
+
14
+ - 簡単な火星の環境をシミュレートした遺伝的アルゴリズムにより導き出した究極生命体の特徴(=画像生成に与えるキーワード)を画像生成プログラムに与えて未来に生き残る究極生命体の画像を生成する。
15
+ - The image generation program is given the characteristics of the ultimate life form (= keywords for image generation) derived by a genetic algorithm that simulates a simple Martian environment to generate images of the ultimate life form that will survive in the future.
16
+
17
  - [Slide (Sorry, Japanese)](https://docs.google.com/presentation/d/1Umq53JqME-GUJN6TgCDA7Fu1CcQhMJTG/edit#slide=id.g15d379b926a_3_0)
18
 
19
  ### Output Images
20
+
21
+ ##### left: first Generation! Very Furry Tall Herd of No teeth Lighter skin Ferocious alien from Mars
22
+ ##### center: 500th Generation! Pair Carnivorous Gentle alien from Mars
23
+ ##### right: 1000th Generation! Pair Herbivorous Ferocious alien from Mars
24
+
25
  <div align="center">
26
+ <img src="./images/first_generation.png" alt="エビフライトライアングル" title="サンプル" style="width:300px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
27
+ <img src="./images/500th_generation.png" alt="エビフライトライアングル" title="サンプル" style="width:300px;"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
28
+ <img src="./images/1000th_generation.png" alt="エビフライトライアングル" title="サンプル" style="width:300px;"/>
29
+ </div>
30
+
31
+ ### file organization
32
 
33
+ - StableDiffusionSample.ipynb
34
+ - An executable file that performs image generation.
35
+ - 画像生成を行う実行ファイル。
36
+ - simulation.py
37
+ - A file with a genetic algorithm simulation running in StableDiffusionSample.ipynb
38
+ - StableDiffusionSample.ipynb で実行する、遺伝的アルゴリズムによるシミュレーションを行っているファイル。
39
+ - images
40
+ - Folder containing the Output image described above.
41
+ - 上述のOutput画像が入ったフォルダ
StableDiffusionSample.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
simulation.py ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """simulation.ipynb
3
+
4
+ Automatically generated by Colaboratory.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1ZVm7p9Kb39Br5GUk1qVby8sG7YmlXLJX
8
+
9
+ - [遺伝アルゴリズム 参考記事](https://mori-memo.hateblo.jp/entry/2022/06/16/232644#%E5%88%9D%E6%9C%9F%E4%B8%96%E4%BB%A3%E3%81%AE%E4%BD%9C%E6%88%90)
10
+ - [バックアップ](https://colab.research.google.com/drive/1CfA0nBjBrrTS3lj0H5-TbOTTD0JdSCqW#scrollTo=rLmsKrtg1NPE)
11
+ - [【NASAより】火星の気温](https://mars.nasa.gov/files/mep/facts/Temperature-Mars-Facts.jpg)
12
+ """
13
+
14
+ import numpy as np
15
+ import matplotlib.pyplot as plt
16
+ import random
17
+ from typing import Tuple, Dict, List
18
+
19
+ """### HACK
20
+ 1. (済) 画像生成実行colab で下記のシミュレーションを実行できるよう修正
21
+ 2. (済) 画像生成ワードを3つから6つに戻す
22
+ 3. (済) 各パラメーターのスコアの推移を表示
23
+ 4. スコアがintデータから途中でfloat型になってしまう -> スコアは修正済み、遺伝子の中の数が変
24
+ 5. パラメーター調整 -> 気温や餌の量のしきい値、共同体の規模や世代数など
25
+ """
26
+
27
+ class Individual:
28
+ '''各個体のクラス
29
+ args: 個体の持つ遺伝子情報(np.array)'''
30
+ def __init__(self, genom_size):
31
+ self.body_hair = np.random.randint(0, 2, genom_size).tolist()
32
+ self.body_size = np.random.randint(0, 2, genom_size).tolist()
33
+ self.herd_num = np.random.randint(0, 2, genom_size).tolist()
34
+ self.eating = np.random.randint(0, 2, genom_size).tolist()
35
+ self.body_color = np.random.randint(0, 2, genom_size).tolist()
36
+ self.ferocity = np.random.randint(0, 2, genom_size).tolist()
37
+
38
+ self.all_genoms = {
39
+ "body_hair": self.body_hair,
40
+ "body_size": self.body_size,
41
+ "herd_num": self.herd_num,
42
+ "eating": self.eating,
43
+ "body_color": self.body_color,
44
+ "ferocity": self.ferocity,
45
+ }
46
+ self.fitness = {
47
+ "body_hair": 0,
48
+ "body_size": 0,
49
+ "herd_num": 0,
50
+ "eating": 0,
51
+ "body_color": 0,
52
+ "ferocity": 0,
53
+ } # 個体の適応度(set_fitness関数で設定)
54
+ self.set_fitness()
55
+ self.set_all_genoms()
56
+
57
+ def set_fitness(self):
58
+ '''個体に対する目的関数(OneMax)の値をself.fitnessに代入'''
59
+ self.fitness = {key: sum(value) for key, value in self.all_genoms.items()}
60
+
61
+ def get_fitness(self):
62
+ '''self.fitnessを出力'''
63
+ return self.fitness
64
+
65
+ def set_all_genoms(self):
66
+ '''self.all_parameterの中身をself.body_hair以下に代入する'''
67
+ self.body_hair = self.all_genoms["body_hair"]
68
+ self.body_size = self.all_genoms["body_size"]
69
+ self.herd_num = self.all_genoms["herd_num"]
70
+ self.eating = self.all_genoms["eating"]
71
+ self.body_color = self.all_genoms["body_color"]
72
+ self.ferocity = self.all_genoms["ferocity"]
73
+
74
+ def mutate(self):
75
+ '''遺伝子の突然変異'''
76
+ for i, (parameter, genom) in enumerate(self.all_genoms.items()):
77
+
78
+ tmp = genom.copy()
79
+ i = np.random.randint(0, len(genom) - 1)
80
+ tmp[i] = float(not genom[i])
81
+ self.all_genoms[parameter] = tmp
82
+
83
+ self.set_all_genoms()
84
+ self.set_fitness()
85
+
86
+ def random_temperature() -> float:
87
+ """
88
+ 火星の気温20℃〜-140℃の範囲でrandomにfloat値を返す
89
+
90
+ args
91
+ times (int): 試行回数
92
+ return
93
+ float: ランダムに作成した 火星の気温
94
+ """
95
+
96
+ temperature = random.uniform(-140, 30)
97
+
98
+ return temperature
99
+
100
+ def random_food_volume(food_volume):
101
+ """
102
+ 餌の量
103
+
104
+ args
105
+ times (int): 試行回数
106
+ return
107
+ float: ランダムに作成した 火星の気温
108
+ """
109
+
110
+ food_volume += random.randint(-100, 100)
111
+ if food_volume < 0:
112
+ food_volume = 0
113
+
114
+ return food_volume
115
+
116
+ def create_generation(POPURATIONS, GENOMS_SIZE):
117
+ '''初期世代の作成
118
+ return: 個体クラスのリスト'''
119
+ generation = {}
120
+ for i in range(POPURATIONS):
121
+ individual = Individual(GENOMS_SIZE)
122
+ generation[individual] = 0
123
+ return generation
124
+
125
+ def select_tournament(generation_: List[Tuple[Individual, int]]) -> List[Tuple[Individual, int]]:
126
+
127
+ """
128
+ 選択の関数(トーナメント方式)。すべてのgenerationから3つ選び、強い(scoreが最も高い)genomを1つ選ぶ。これをgenerationのサイズだけ繰り返す
129
+
130
+ args
131
+ generation List[Tuple[Individual, int]]: Individual で作成したゲノム情報 [["body_hair"], ["body_size"], ["herd_num"]] , 評価score
132
+ return
133
+ List[Tuple[Individual, int]] : トーナメント戦で生き残ったゲノム1つ
134
+ """
135
+
136
+ selected_gemems = []
137
+
138
+ for i in range(len(generation)):
139
+
140
+ # 最もスコアのよいgeneration を採用
141
+ tournament = random.sample(generation_, TOUNAMENT_NUM)
142
+ max_genom = max(tournament, key=lambda x: x[1])
143
+
144
+ selected_gemems.append(max_genom)
145
+
146
+ return selected_gemems
147
+
148
+ def cross_two_point_copy(child1, child2):
149
+ '''二点交叉'''
150
+
151
+ new_child1 = {}
152
+ new_child2 = {}
153
+
154
+ for parameter_genom_1, parameter_genom_2 in zip(child1[0].all_genoms.items(), child2[0].all_genoms.items()):
155
+
156
+ size = len(parameter_genom_1[1])
157
+
158
+ tmp_child_parameter1 = parameter_genom_1[0]
159
+ tmp_child_parameter2 = parameter_genom_2[0]
160
+
161
+ tmp_child_genom1 = parameter_genom_1[1].copy()
162
+ tmp_child_genom2 = parameter_genom_2[1].copy()
163
+
164
+ cxpoint1 = np.random.randint(1, size)
165
+ cxpoint2 = np.random.randint(1, size - 1)
166
+
167
+ if cxpoint2 >= cxpoint1:
168
+ cxpoint2 += 1
169
+ else:
170
+ cxpoint1, cxpoint2 = cxpoint2, cxpoint1
171
+
172
+ tmp_child_genom1[cxpoint1:cxpoint2], tmp_child_genom2[cxpoint1:cxpoint2] = tmp_child_genom2[cxpoint1:cxpoint2].copy(), tmp_child_genom1[cxpoint1:cxpoint2].copy()
173
+
174
+ child1[0].all_genoms[tmp_child_parameter1] = tmp_child_genom1
175
+ child2[0].all_genoms[tmp_child_parameter2] = tmp_child_genom2
176
+
177
+ child1[0].set_all_genoms()
178
+ child1[0].set_fitness()
179
+ child2[0].set_all_genoms()
180
+ child2[0].set_fitness()
181
+
182
+ return child1, child2
183
+
184
+ def crossover(selected):
185
+ '''交叉の関数'''
186
+ children = []
187
+ if POPURATIONS % 2:
188
+ selected.append(selected[0])
189
+ for child1, child2 in zip(selected[::2], selected[1::2]):
190
+ if np.random.rand() < CROSSOVER_PB:
191
+ child1, child2 = cross_two_point_copy(child1, child2)
192
+ children.append(child1)
193
+ children.append(child2)
194
+ children = children[:POPURATIONS]
195
+ return children
196
+
197
+ def mutate(children):
198
+ for child in children:
199
+ if np.random.rand() < MUTATION_PB:
200
+ child.mutate()
201
+ return children
202
+
203
+ def mutate(children):
204
+
205
+ tmp_children = []
206
+
207
+ for child in children:
208
+ individual, score = child[0], child[1]
209
+ individual.mutate()
210
+
211
+ tmp_children.append((individual, score))
212
+
213
+ return tmp_children
214
+
215
+ def reset_generation_score(generation_):
216
+
217
+ for i, (individual, score) in enumerate(generation_):
218
+ generation_[i] = (individual, 0)
219
+
220
+ return generation_
221
+
222
+ def scoring(generation_, temperature, food_volume):
223
+
224
+ generation_ = reset_generation_score(generation_)
225
+
226
+ # scoring を実施
227
+ for i, (individual, score) in enumerate(generation_):
228
+
229
+ # 各パラメーターの特性値を探索
230
+ for parameter, fitness in individual.get_fitness().items():
231
+
232
+ # 気温が高い
233
+ if temperature > THREASHOLD_TEMPRETURE:
234
+ if parameter == "body_hair": # body_hair が小さいほうが有利、大きいほうが不利
235
+ score += MAX_NUM - fitness
236
+ elif parameter == "body_size": # body_size が小さいほうが有利、大きいほうが不利
237
+ score += MAX_NUM - fitness
238
+ elif parameter == "body_color": # body_color が暗い方が有利、明るいほうが不利
239
+ score += fitness
240
+
241
+ # 気温が低い
242
+ else:
243
+ if parameter == "body_hair": # body_hair が大きいほうが有利、小さいほうが不利
244
+ score += fitness
245
+ elif parameter == "body_size": # body_size が大きいほうが有利、小さいほうが不利
246
+ score += fitness
247
+ elif parameter == "body_color": # body_color が明るい方が有利、暗いほうが不利
248
+ score += MAX_NUM - fitness
249
+
250
+ # エサが多い
251
+ if food_volume > THREASHOLD_FOOD_VOLUME:
252
+ if parameter == "body_size": # body_size が大きいほうが有利、小さいほうが不利
253
+ score += fitness
254
+ elif parameter == "herd_num": # herd_num が大きいほうが有利、小さいほうが不利
255
+ score += fitness
256
+ elif parameter == "eating": # eating が大きい(肉食)ほうが有利、小さい(草食)ほうが不利
257
+ score += fitness
258
+
259
+ # エサが少ない
260
+ else:
261
+ if parameter == "body_size": # body_size が小さいほうが有利、大きいほうが不利
262
+ score += MAX_NUM - fitness
263
+ elif parameter == "herd_num": # herd_num が小さいほうが有利、大きいほうが不利
264
+ score += MAX_NUM - fitness
265
+ elif parameter == "eating": # eating が小さい(草食)ほうが有利、大さい(肉食)ほうが不利
266
+ score += MAX_NUM - fitness
267
+
268
+
269
+ # 強さ
270
+ if parameter == "body_size": # body_size が大きいほうが有利、小さい方が不利
271
+ score += fitness
272
+ elif parameter == "herd_num":
273
+ score += fitness
274
+ elif parameter == "ferocity": # ferocity が大きい(凶暴)ほうが有利、小さい(おとなしい)ほうが不利
275
+ score += fitness
276
+
277
+
278
+ # score を更新
279
+ generation_[i] = (individual, int(score))
280
+
281
+ return generation_
282
+
283
+ def ga_solve(generation):
284
+ '''遺伝的アルゴリズムのソルバー
285
+ return: 最終世代の最高適応値の個体、最低適応値の個体'''
286
+
287
+ best = []
288
+ worst = []
289
+
290
+ temperature_transition = []
291
+ food_volume = 500
292
+ food_volume_transition = []
293
+
294
+ parameter_transiton = {
295
+ "body_size" : [],
296
+ "body_hair" : [],
297
+ "herd_num" : [],
298
+ "eating" : [],
299
+ "body_color" : [],
300
+ "ferocity" : [],
301
+ }
302
+
303
+ # --- Generation loop
304
+ print('Generation loop start.')
305
+
306
+ # Dict[Individual, int] から List[Tuple(individual, int)]へ変換
307
+ # Dict だと Key の重複ができないため
308
+ generation_ = [(individual, score) for individual, score in generation.items()]
309
+
310
+ for i in range(GENERATIONS):
311
+
312
+ temperature = random_temperature()
313
+ temperature_transition.append(temperature)
314
+ food_volume = random_food_volume(food_volume)
315
+ food_volume_transition.append(food_volume)
316
+
317
+ # スコアリング
318
+ generation_ = scoring(generation_, temperature, food_volume)
319
+
320
+
321
+ # --- Step1. Print fitness in the generation
322
+ best_individual_score = max(generation_, key=lambda x: x[1])
323
+
324
+ best.append(best_individual_score[0].fitness)
325
+ worst_individual_score = min(generation_, key=lambda x: x[1])
326
+
327
+ worst.append(worst_individual_score[0].fitness)
328
+ # print("Generation: " + str(i) \
329
+ # + ": Best fitness: " + str(best_individual_score[0].fitness) + "Best fitness score: " + str(best_individual_score[1]) \
330
+ # + ". Worst fitness: " + str(worst_individual_score[0].fitness) + "Worst fitness score: " + str(worst_individual_score[1])
331
+ # )
332
+
333
+ # --- Step2. Selection (Roulette)
334
+ selected_genoms = select_tournament(generation_)
335
+
336
+ # --- Step3. Crossover (two_point_copy)
337
+ children = crossover(selected_genoms)
338
+
339
+ # --- Step4. Mutation
340
+ generation_ = mutate(children)
341
+
342
+ for parameter, genom in best_individual_score[0].all_genoms.items():
343
+ parameter_transiton[parameter].append(sum(genom))
344
+
345
+ best_individual_score[0].set_all_genoms()
346
+ best_individual_score[0].set_fitness()
347
+
348
+ print("Generation loop ended. The best individual: ")
349
+ print(best_individual_score[0].all_genoms)
350
+
351
+ plt.figure(figsize=(20, 5))
352
+ plt.title("temperature")
353
+ plt.plot(temperature_transition)
354
+ plt.ylabel("temperature Celsius")
355
+ plt.xlabel("generation")
356
+ plt.savefig("simlation_tempreture.png")
357
+
358
+ plt.figure(figsize=(20, 5))
359
+ plt.title("food volume")
360
+ plt.plot(food_volume_transition)
361
+ plt.ylim(0);
362
+ plt.ylabel("food volume")
363
+ plt.xlabel("generation")
364
+ plt.savefig("simlation_food_volume.png")
365
+
366
+ plt.figure(figsize=(20, 16))
367
+ for i, (parameter, transition) in enumerate(parameter_transiton.items()):
368
+ plt.subplot(6, 1, i+1)
369
+ plt.title(parameter)
370
+ plt.plot(transition, label=parameter)
371
+ plt.legend()
372
+ plt.ylim(0, 4)
373
+ plt.tight_layout()
374
+ plt.savefig("each_parameter_transition.png")
375
+
376
+ return best, worst
377
+
378
+ def get_word_for_image_generate(word_dict, best, index):
379
+
380
+ # アルゴリズムの結果に対応するwordを抽出
381
+ word_list = [word_dict[parameter][int(fitness)] for parameter, fitness in best[index].items()]
382
+
383
+ # 最終的な I/F 補足: スペース区切りの文字列 を渡す, 英語もありうる
384
+ word = " ".join(word_list)
385
+ return word
386
+
387
+ """### 実行"""
388
+
389
+ # シード値の固定
390
+ SEED = 42
391
+ np.random.seed(seed=SEED)
392
+ random.seed(SEED)
393
+
394
+ # パラメーター
395
+ POPURATIONS = 200
396
+ GENOMS_SIZE = 4 # 遺伝配列 0, 1 のどちらかを要素とした配列のサイズ
397
+ GENERATIONS = 1000 # 世代数
398
+ CROSSOVER_PB = 0.5 # cross over(交差) する確率
399
+ MUTATION_PB = 0.7 # mutation(突然変異)する確率
400
+ TOUNAMENT_NUM = 10 # トーナメント方式で競わせる数
401
+ MAX_NUM = 4 # fitness の最大値
402
+
403
+ THREASHOLD_TEMPRETURE = 5
404
+ THREASHOLD_FOOD_VOLUME = 1500
405
+
406
+ # 渡すデータの加工イメージ
407
+ # dict 型 {項目(key): 画像生成プログラムに与えるキーワード{value}}
408
+ word_dict = {
409
+ "body_size": ["Very small", "Small", "Ordinary size", "Big", "Giant"],
410
+ "body_hair": ["Very Skinny", "Skinny", "Ordinary Skin", "Furry", "Very Furry"],
411
+ "herd_num": ["Lone", "Pair", "Eight", "Many", "Too Many"],
412
+ "eating": ["Very Herbivorous", "Herbivorous", "Omnivorous", "Carnivorous","Very Carnivorous"],
413
+ "body_color": ["Lightest", "Lighter", "Ordinary Tone", "Darker", "Darkest"],
414
+ "ferocity": ["Very Gentle", "Gentle", "Ordinary", "Ferocious", "Very Ferocious"],
415
+ }
416
+
417
+ # create first genetarion
418
+ generation = create_generation(POPURATIONS, GENOMS_SIZE)
419
+
420
+ # アルゴリズムの実行
421
+ best, worst = ga_solve(generation)
422
+
423
+ # 抽出する世代
424
+ first_generation = 0
425
+ midle_generation = len(best) // 2
426
+ last_generation = -1
427
+
428
+ first_generation_word = get_word_for_image_generate(word_dict, best, first_generation) + " alien from Mars"
429
+ midle_generation_word = get_word_for_image_generate(word_dict, best, midle_generation) + " alien from Mars"
430
+ last_generation_word = get_word_for_image_generate(word_dict, best, last_generation) + " alien from Mars"
431
+
432
+ # 抽出する世代のワードを出力
433
+ print()
434
+ print(
435
+ "最初の世代:", first_generation_word, "\n",
436
+ f"中間の{midle_generation}世代目:", midle_generation_word, "\n",
437
+ f"最後の{GENERATIONS}世代目:", last_generation_word, "\n",
438
+ )
439
+