世界上最丧病的闯关游戏(基于遗传算法GA进化的小游戏)
世界上最丧病的闯关游戏(基于遗传算法GA进化的小游戏)3、确定最近的食物颗粒的方向:一旦最近的食物颗粒被一个生物体确定,就必须计算出这个颗粒的方向。2、寻找最近的食物颗粒:对于每一个生物体,必须确定最近的食物颗粒。ef evolve(settings organisms_old gen): elitism_num = int(floor(settings['elitism'] * settings['pop_size'])) new_orgs = settings['pop_size'] - elitism_num #--- GET STATS FROM CURRENT GENERATION ---------------- stats = defaultdict(int) for org in organisms_old: if org.fitness > stats['BEST'] or stats['BEST']
摘要: 本文是一篇使用Python语言模拟生物体和食物之间的关系和基于遗传算法进化生物体的实例教程。
在这篇文章中,我们模拟了一个包含生物体和食物的环境,生物体为了生存必须尽可能多的消耗食物。在模拟环境中,生物体将由一个简单的、完全连接的神经网络来控制。神经网络的输入是一种标准化值,从-1到 1之间,这表示最近的食物颗粒的方向。这个方向是通过最近的食物颗粒( /-180度)方向计算出来的。下面是两个生物体和食物颗粒的示例:
因为我们的输入范围从-1到 1,所以输出范围应当也从-1到 1,因此tanh函数将会成为理想的激活函数。下面是一个神经网络的图和它的输入、输出以及它的隐藏层:
这个EA代码程序如下所示:
ef evolve(settings organisms_old gen): elitism_num = int(floor(settings['elitism'] * settings['pop_size'])) new_orgs = settings['pop_size'] - elitism_num #--- GET STATS FROM CURRENT GENERATION ---------------- stats = defaultdict(int) for org in organisms_old: if org.fitness > stats['BEST'] or stats['BEST'] == 0: stats['BEST'] = org.fitness if org.fitness < stats['WORST'] or stats['WORST'] == 0: stats['WORST'] = org.fitness stats['SUM'] = org.fitness stats['COUNT'] = 1 stats['AVG'] = stats['SUM'] / stats['COUNT'] #--- ELITISM (KEEP BEST PERFORMING ORGANISMS) --------- orgs_sorted = sorted(organisms_old key=operator.attrgetter('fitness') reverse=True) organisms_new = [] for i in range(0 elitism_num): organisms_new.append(organism(settings wih=orgs_sorted[i].wih who=orgs_sorted[i].who name=orgs_sorted[i].name)) #--- GENERATE NEW ORGANISMS --------------------------- for w in range(0 new_orgs): # SELECTION (TRUNCATION SELECTION) canidates = range(0 elitism_num) random_index = sample(canidates 2) org_1 = orgs_sorted[random_index[0]] org_2 = orgs_sorted[random_index[1]] # CROSSOVER crossover_weight = random() wih_new = (crossover_weight * org_1.wih) ((1 - crossover_weight) * org_2.wih) who_new = (crossover_weight * org_1.who) ((1 - crossover_weight) * org_2.who) # MUTATION mutate = random() if mutate <= settings['mutate']: # PICK WHICH WEIGHT MATRIX TO MUTATE mat_pick = randint(0 1) # MUTATE: WIH WEIGHTS if mat_pick == 0: index_row = randint(0 settings['hnodes']-1) wih_new[index_row] = wih_new[index_row] * uniform(0.9 1.1) if wih_new[index_row] > 1: wih_new[index_row] = 1 if wih_new[index_row] < -1: wih_new[index_row] = -1 # MUTATE: WHO WEIGHTS if mat_pick == 1: index_row = randint(0 settings['onodes']-1) index_col = randint(0 settings['hnodes']-1) who_new[index_row][index_col] = who_new[index_row][index_col] * uniform(0.9 1.1) if who_new[index_row][index_col] > 1: who_new[index_row][index_col] = 1 if who_new[index_row][index_col] < -1: who_new[index_row][index_col] = -1 organisms_new.append(organism(settings wih=wih_new who=who_new name='gen[' str(gen) ']-org[' str(w) ']')) return organisms_new stats
四、模拟
最后是模拟实际运行的关键代码,模拟函数将在每一代调用一次。模拟时间步骤则是通过将总模拟时间除以时间间隔dt来确定的。例如,如果模拟时间设置为100秒,而dt等于1/25秒,那么总共需要模拟2500个时间步骤。在每一个步骤中,将进行以下操作:
1、碰撞检测:检查生物和食物颗粒之间的碰撞。当检测到碰撞时,该生物体将得到更新,食物颗粒将在一个新的随机位置上重生。
2、寻找最近的食物颗粒:对于每一个生物体,必须确定最近的食物颗粒。
3、确定最近的食物颗粒的方向:一旦最近的食物颗粒被一个生物体确定,就必须计算出这个颗粒的方向。
4、查询神经网络:由于使用了更新的方向值,因此每个生物的神经网络都将变得不同。
5、更新生物体:基于神经网络的响应,生物体的速度和位置都得到了更新。
下面是模拟函数:
def simulate(settings organisms foods gen): total_time_steps = int(settings['gen_time'] / settings['dt']) #--- CYCLE THROUGH EACH TIME STEP --------------------- for t_step in range(0 total_time_steps 1): # PLOT SIMULATION FRAME #if gen == settings['gens'] - 1 and settings['plot']==True: if gen==49: plot_frame(settings organisms foods gen t_step) # UPDATE FITNESS FUNCTION for food in foods: for org in organisms: food_org_dist = dist(org.x org.y food.x food.y) # UPDATE FITNESS FUNCTION if food_org_dist <= 0.075: org.fitness = food.energy food.respawn(settings) # RESET DISTANCE AND HEADING TO NEAREST FOOD SOURCE org.d_food = 100 org.r_food = 0 # CALCULATE HEADING TO NEAREST FOOD SOURCE for food in foods: for org in organisms: # CALCULATE DISTANCE TO SELECTED FOOD PARTICLE food_org_dist = dist(org.x org.y food.x food.y) # DETERMINE IF THIS IS THE CLOSEST FOOD PARTICLE if food_org_dist < org.d_food: org.d_food = food_org_dist org.r_food = calc_heading(org food) # GET ORGANISM RESPONSE for org in organisms: org.think() # UPDATE ORGANISMS POSITION AND VELOCITY for org in organisms: org.update_r(settings) org.update_vel(settings) org.update_pos(settings)return organisms
五、结果
在创建所有的主要组件之后,最终代码就可以组装起来了。注意:在上面的文章中,忽略了一些更小的函数,因为它们太简单了,阅读它们要比直接阅读代码花费更长的时间。所有的代码我都放在GitHub上了,你可以点击这里下载。
我使用了matplotlib来显示模拟。当你运行整个代码时,输出应该与此类似:
以上为译文
文章原标题《Evolving Simple Organisms using a Genetic Algorithm and Deep Learning from Scratch with Python
》,作者:Nathan,译者:黄小凡,审校:袁虎。