zoukankan      html  css  js  c++  java
  • 是AI就躲个飞机-纯Python实现人工智能

    你要的答案或许都在这里小鹏的博客目录

    代码下载:Here。

    很久以前微信流行过一个小游戏:打飞机,这个游戏简单又无聊。在2017年来临之际,我就实现一个超级弱智的人工智能(AI),这货可以躲避从屏幕上方飞来的飞机。本帖只使用纯Python实现,不依赖任何高级库。

    本文的AI基于neuro-evolution,首先简单科普一下neuro-evolution。从neuro-evolution这个名字就可以看出它由两部分组成-neuro and evolution,它是使用进化算法(遗传算法是进化算法的一种)提升人工神经网络的机器学习技术,其实就是用进化算法改进并选出最优的神经网络。

    neuro-evolution

    定义一些变量:

    [python] view plain copy

    1. import math  

    2. import random  

    3.    

    4. # 神经网络3层, 1个隐藏层; 4个input和1个output  

    5. network = [4, [16], 1]  

    6. # 遗传算法相关  

    7. population = 50  

    8. elitism = 0.2   

    9. random_behaviour = 0.1  

    10. mutation_rate = 0.5  

    11. mutation_range = 2  

    12. historic = 0  

    13. low_historic = False  

    14. score_sort = -1  

    15. n_child = 1  

    定义神经网络:

    [python] view plain copy

    1. # 激活函数  

    2. def sigmoid(z):  

    3.     return 1.0/(1.0+math.exp(-z))  

    4. # random number  

    5. def random_clamped():  

    6.     return random.random()*2-1  

    7.    

    8. # "神经元"  

    9. class Neuron():  

    10.     def __init__(self):  

    11.         self.biase = 0  

    12.         self.weights = []  

    13.    

    14.     def init_weights(self, n):  

    15.         self.weights = []  

    16.         for i in range(n):  

    17.             self.weights.append(random_clamped())  

    18.     def __repr__(self):  

    19.         return 'Neuron weight size:{}  biase value:{}'.format(len(self.weights), self.biase)  

    20.    

    21. # 层  

    22. class Layer():  

    23.     def __init__(self, index):  

    24.         self.index = index  

    25.         self.neurons = []  

    26.    

    27.     def init_neurons(self, n_neuron, n_input):  

    28.         self.neurons = []  

    29.         for i in range(n_neuron):  

    30.             neuron = Neuron()  

    31.             neuron.init_weights(n_input)  

    32.             self.neurons.append(neuron)  

    33.    

    34.     def __repr__(self):  

    35.         return 'Layer ID:{}  Layer neuron size:{}'.format(self.index, len(self.neurons))  

    36.    

    37. # 神经网络  

    38. class NeuroNetwork():  

    39.     def __init__(self):  

    40.         self.layers = []  

    41.    

    42.     # input:输入层神经元数 hiddens:隐藏层 output:输出层神经元数  

    43.     def init_neuro_network(self, input, hiddens , output):  

    44.         index = 0  

    45.         previous_neurons = 0  

    46.         # input  

    47.         layer = Layer(index)  

    48.         layer.init_neurons(input, previous_neurons)  

    49.         previous_neurons = input  

    50.         self.layers.append(layer)  

    51.         index += 1  

    52.         # hiddens  

    53.         for i in range(len(hiddens)):  

    54.             layer = Layer(index)  

    55.             layer.init_neurons(hiddens[i], previous_neurons)  

    56.             previous_neurons = hiddens[i]  

    57.             self.layers.append(layer)  

    58.             index += 1  

    59.         # output  

    60.         layer = Layer(index)  

    61.         layer.init_neurons(output, previous_neurons)  

    62.         self.layers.append(layer)  

    63.    

    64.     def get_weights(self):  

    65.         data = { 'network':[], 'weights':[] }  

    66.         for layer in self.layers:  

    67.             data['network'].append(len(layer.neurons))  

    68.             for neuron in layer.neurons:  

    69.                 for weight in neuron.weights:  

    70.                     data['weights'].append(weight)  

    71.         return data  

    72.    

    73.     def set_weights(self, data):  

    74.         previous_neurons = 0  

    75.         index = 0  

    76.         index_weights = 0  

    77.    

    78.         self.layers = []  

    79.         for i in data['network']:  

    80.             layer = Layer(index)  

    81.             layer.init_neurons(i, previous_neurons)  

    82.             for j in range(len(layer.neurons)):  

    83.                 for k in range(len(layer.neurons[j].weights)):  

    84.                     layer.neurons[j].weights[k] = data['weights'][index_weights]  

    85.                     index_weights += 1  

    86.             previous_neurons = i  

    87.             index += 1  

    88.             self.layers.append(layer)  

    89.    

    90.     # 输入游戏环境中的一些条件(如敌机位置), 返回要执行的操作  

    91.     def feed_forward(self, inputs):  

    92.         for i in range(len(inputs)):  

    93.             self.layers[0].neurons[i].biase = inputs[i]  

    94.    

    95.         prev_layer = self.layers[0]  

    96.         for i in range(len(self.layers)):  

    97.             # 第一层没有weights  

    98.             if i == 0:  

    99.                 continue  

    100.             for j in range(len(self.layers[i].neurons)):  

    101.                 sum = 0  

    102.                 for k in range(len(prev_layer.neurons)):  

    103.                     sum += prev_layer.neurons[k].biase * self.layers[i].neurons[j].weights[k]  

    104.                 self.layers[i].neurons[j].biase = sigmoid(sum)  

    105.             prev_layer = self.layers[i]  

    106.    

    107.         out = []  

    108.         last_layer = self.layers[-1]  

    109.         for i in range(len(last_layer.neurons)):  

    110.             out.append(last_layer.neurons[i].biase)  

    111.         return out  

    112.    

    113.     def print_info(self):  

    114.         for layer in self.layers:  

    115.             print(layer)  

    遗传算法:

    [python] view plain copy

    1. # "基因组"  

    2. class Genome():  

    3.     def __init__(self, score, network_weights):  

    4.         self.score = score  

    5.         self.network_weights = network_weights  

    6.    

    7. class Generation():  

    8.     def __init__(self):  

    9.         self.genomes = []  

    10.    

    11.     def add_genome(self, genome):  

    12.         i = 0  

    13.         for i in range(len(self.genomes)):  

    14.             if score_sort < 0:  

    15.                 if genome.score > self.genomes[i].score:  

    16.                     break  

    17.             else:  

    18.                 if genome.score < self.genomes[i].score:  

    19.                     break  

    20.         self.genomes.insert(i, genome)  

    21.    

    22.         # 杂交+突变  

    23.     def breed(self, genome1, genome2, n_child):  

    24.         datas = []  

    25.         for n in range(n_child):  

    26.             data = genome1  

    27.             for i in range(len(genome2.network_weights['weights'])):  

    28.                 if random.random() <= 0.5:  

    29.                     data.network_weights['weights'][i] = genome2.network_weights['weights'][i]  

    30.    

    31.             for i in range(len(data.network_weights['weights'])):  

    32.                 if random.random() <= mutation_rate:  

    33.                     data.network_weights['weights'][i] += random.random() * mutation_range * 2 - mutation_range  

    34.             datas.append(data)  

    35.         return datas  

    36.    

    37.         # 生成下一代  

    38.     def generate_next_generation(self):  

    39.         nexts = []  

    40.         for i in range(round(elitism*population)):  

    41.             if len(nexts) < population:  

    42.                 nexts.append(self.genomes[i].network_weights)  

    43.    

    44.         for i in range(round(random_behaviour*population)):  

    45.             n = self.genomes[0].network_weights  

    46.             for k in range(len(n['weights'])):  

    47.                 n['weights'][k] = random_clamped()  

    48.             if len(nexts) < population:  

    49.                 nexts.append(n)  

    50.    

    51.         max_n = 0  

    52.         while True:  

    53.             for i in range(max_n):  

    54.                 childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1)  

    55.                 for c in range(len(childs)):  

    56.                     nexts.append(childs[c].network_weights)  

    57.                     if len(nexts) >= population:  

    58.                         return nexts  

    59.             max_n += 1  

    60.             if max_n >= len(self.genomes)-1:  

    61.                 max_n = 0  

    NeuroEvolution:

    [python] view plain copy

    1. class Generations():  

    2.     def __init__(self):  

    3.         self.generations = []  

    4.    

    5.     def first_generation(self):  

    6.         out = []  

    7.         for i in range(population):  

    8.             nn = NeuroNetwork()  

    9.             nn.init_neuro_network(network[0], network[1], network[2])  

    10.             out.append(nn.get_weights())  

    11.         self.generations.append(Generation())  

    12.         return out  

    13.           

    14.     def next_generation(self):  

    15.         if len(self.generations) == 0:  

    16.             return False  

    17.    

    18.         gen = self.generations[-1].generate_next_generation()  

    19.         self.generations.append(Generation())  

    20.         return gen  

    21.    

    22.     def add_genome(self, genome):  

    23.         if len(self.generations) == 0:  

    24.             return False  

    25.    

    26.         return self.generations[-1].add_genome(genome)  

    27.    

    28. class NeuroEvolution():  

    29.     def __init__(self):  

    30.         self.generations = Generations()  

    31.    

    32.     def restart(self):  

    33.         self.generations = Generations()  

    34.    

    35.     def next_generation(self):  

    36.         networks = []  

    37.         if len(self.generations.generations) == 0:  

    38.             networks = self.generations.first_generation()  

    39.         else:  

    40.             networks = self.generations.next_generation()  

    41.    

    42.         nn = []  

    43.         for i in range(len(networks)):  

    44.             n = NeuroNetwork()  

    45.             n.set_weights(networks[i])  

    46.             nn.append(n)  

    47.    

    48.         if low_historic:  

    49.             if len(self.generations.generations) >= 2:  

    50.                 genomes = self.generations.generations[len(self.generations.generations) - 2].genomes  

    51.                 for i in range(genomes):  

    52.                     genomes[i].network = None  

    53.    

    54.         if historic != -1:  

    55.             if len(self.generations.generations) > historic+1:  

    56.                 del self.generations.generations[0:len(self.generations.generations)-(historic+1)]  

    57.    

    58.         return nn  

    59.    

    60.     def network_score(self, score, network):  

    61.         self.generations.add_genome(Genome(score, network.get_weights()))  

    是AI就躲个飞机

    [python] view plain copy

    1. import pygame  

    2. import sys  

    3. from pygame.locals import *  

    4. import random  

    5. import math  

    6.    

    7. import neuro_evolution  

    8.    

    9. BACKGROUND = (200200200)  

    10. SCREEN_SIZE = (320480)  

    11.    

    12. class Plane():  

    13.     def __init__(self, plane_image):  

    14.         self.plane_image = plane_image  

    15.         self.rect = plane_image.get_rect()  

    16.    

    17.         self.width = self.rect[2]  

    18.         self.height = self.rect[3]  

    19.         self.x = SCREEN_SIZE[0]/2 - self.width/2  

    20.         self.y = SCREEN_SIZE[1] - self.height  

    21.    

    22.         self.move_x = 0  

    23.         self.speed = 2  

    24.    

    25.         self.alive = True  

    26.    

    27.     def update(self):  

    28.         self.x += self.move_x * self.speed  

    29.    

    30.     def draw(self, screen):  

    31.         screen.blit(self.plane_image, (self.x, self.y, self.width, self.height))  

    32.    

    33.     def is_dead(self, enemes):  

    34.         if self.x < -self.width or self.x + self.width > SCREEN_SIZE[0]+self.  

    35.             return True  

    36.    

    37.         for eneme in enemes:  

    38.             if self.collision(eneme):  

    39.                 return True  

    40.         return False  

    41.    

    42.     def collision(self, eneme):  

    43.         if not (self.x > eneme.x + eneme.width or self.x + self.width < eneme.x or self.y > eneme.y + eneme.height or self.y + self.height < eneme.y):  

    44.             return True  

    45.         else:  

    46.             return False  

    47.    

    48.     def get_inputs_values(self, enemes, input_size=4):  

    49.         inputs = []  

    50.    

    51.         for i in range(input_size):  

    52.             inputs.append(0.0)  

    53.    

    54.         inputs[0] = (self.x*1.0 / SCREEN_SIZE[0])  

    55.         index = 1  

    56.         for eneme in enemes:  

    57.             inputs[index] = eneme.x*1.0 / SCREEN_SIZE[0]  

    58.             index += 1  

    59.             inputs[index] = eneme.y*1.0 / SCREEN_SIZE[1]  

    60.             index += 1  

    61.         #if len(enemes) > 0:  

    62.             #distance = math.sqrt(math.pow(enemes[0].x + enemes[0].width/2 - self.x + self.width/2, 2) + math.pow(enemes[0].y + enemes[0].height/2 - self.y + self.height/2, 2));  

    63.         if len(enemes) > 0 and self.x < enemes[0].x:  

    64.             inputs[index] = -1.0  

    65.             index += 1  

    66.         else:  

    67.             inputs[index] = 1.0  

    68.    

    69.         return inputs  

    70.    

    71. class Enemy():  

    72.     def __init__(self, enemy_image):  

    73.         self.enemy_image = enemy_image  

    74.         self.rect = enemy_image.get_rect()  

    75.    

    76.         self.width = self.rect[2]  

    77.         self.height = self.rect[3]  

    78.         self.x = random.choice(range(0, int(SCREEN_SIZE[0] - self.width/2), 71))  

    79.         self.y = 0  

    80.    

    81.     def update(self):  

    82.         self.y += 6  

    83.    

    84.     def draw(self, screen):  

    85.         screen.blit(self.enemy_image, (self.x, self.y, self.width, self.height))  

    86.    

    87.     def is_out(self):  

    88.         return True if self.y >= SCREEN_SIZE[1else False  

    89.    

    90. class Game():  

    91.     def __init__(self):  

    92.         pygame.init()  

    93.         self.screen = pygame.display.set_mode(SCREEN_SIZE)  

    94.         self.clock = pygame.time.Clock()  

    95.         pygame.display.set_caption('是AI就躲个飞机')  

    96.    

    97.         self.ai = neuro_evolution.NeuroEvolution()  

    98.         self.generation = 0  

    99.    

    100.         self.max_enemes = 1  

    101.                 # 加载飞机、敌机图片  

    102.         self.plane_image = pygame.image.load('plane.png').convert_alpha()  

    103.         self.enemy_image = pygame.image.load('enemy.png').convert_alpha()  

    104.    

    105.     def start(self):  

    106.         self.score = 0  

    107.         self.planes = []  

    108.         self.enemes = []  

    109.    

    110.         self.gen = self.ai.next_generation()  

    111.         for i in range(len(self.gen)):  

    112.             plane = Plane(self.plane_image)  

    113.             self.planes.append(plane)  

    114.    

    115.         self.generation += 1  

    116.         self.alives = len(self.planes)  

    117.    

    118.     def update(self, screen):  

    119.         for i in range(len(self.planes)):  

    120.             if self.planes[i].alive:  

    121.                 inputs = self.planes[i].get_inputs_values(self.enemes)  

    122.                 res = self.gen[i].feed_forward(inputs)  

    123.                 if res[0] < 0.45:  

    124.                     self.planes[i].move_x = -1  

    125.                 elif res[0] > 0.55:  

    126.                     self.planes[i].move_x = 1  

    127.    

    128.    

    129.                 self.planes[i].update()  

    130.                 self.planes[i].draw(screen)  

    131.    

    132.                 if self.planes[i].is_dead(self.enemes) == True:  

    133.                     self.planes[i].alive = False  

    134.                     self.alives -= 1  

    135.                     self.ai.network_score(self.score, self.gen[i])  

    136.                     if self.is_ai_all_dead():  

    137.                         self.start()  

    138.    

    139.           

    140.         self.gen_enemes()  

    141.    

    142.         for i in range(len(self.enemes)):  

    143.             self.enemes[i].update()  

    144.             self.enemes[i].draw(screen)  

    145.             if self.enemes[i].is_out():  

    146.                 del self.enemes[i]  

    147.                 break  

    148.    

    149.         self.score += 1  

    150.    

    151.         print("alive:{}, generation:{}, score:{}".format(self.alives, self.generation, self.score), end=' ')  

    152.    

    153.     def run(self, FPS=1000):  

    154.         while True:  

    155.             for event in pygame.event.get():  

    156.                 if event.type == QUIT:  

    157.                     pygame.quit()  

    158.                     sys.exit()  

    159.    

    160.             self.screen.fill(BACKGROUND)  

    161.    

    162.             self.update(self.screen)  

    163.    

    164.             pygame.display.update()  

    165.             self.clock.tick(FPS)  

    166.    

    167.     def gen_enemes(self):  

    168.         if len(self.enemes) < self.max_enemes:  

    169.             enemy = Enemy(self.enemy_image)  

    170.             self.enemes.append(enemy)  

    171.    

    172.     def is_ai_all_dead(self):  

    173.         for plane in self.planes:  

    174.             if plane.alive:  

    175.                 return False  

    176.         return True  

    177.    

    178.    

    179. game = Game()  

    180. game.start()  

    181. game.run()  

    AI的工作逻辑

    假设你是AI,你首先繁殖一个种群(50个个体),开始的个体大都是歪瓜裂枣(上来就被敌机撞)。但是,即使是歪瓜裂枣也有表现好的,在下一代,你会使用这些表现好的再繁殖一个种群,经过代代相传,存活下来的个体会越来越优秀。其实就是仿达尔文进化论,种群->自然选择->优秀个体->杂交、变异->种群->循环n世代。

    ai开始时候的表现:

    640?wx_fmt=gif图片被拉扁了 sorry

    经过几百代之后,ai开始娱乐的躲飞机:

    640?wx_fmt=gif

    已获作者授权转载,原文链接如下:

    http://blog.csdn.net/u014365862/article/details/54380422

  • 相关阅读:
    [Day01] Python基础
    Python数据结构与循环语句
    elementui级联下拉框怎么设置可选择任意一级选项以及设置后前面会出现1个单选按钮去掉单选按钮的方法和选好后下拉面板不自动收起的问题
    解决ElementUI中的Cascader 级联选择器高度过高的问题
    git切换分支提示:you need to resolve your current index first
    提交本地代码到git远程仓库时误操作让git代码覆盖了本地代码,找回本地代码的解决方法
    elementui在表格/下来列表等展示数据的区显示加载中
    vueshop
    elementui表单验证无效的解决方法
    elementui滑块开启和关闭状态动态绑定
  • 原文地址:https://www.cnblogs.com/finer/p/11895144.html
Copyright © 2011-2022 走看看