纯Python实现人工智能

    xiaoxiao2022-06-30  91

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

    本文的AI基于neuro-evolution,首先简单科普一下neuro-evolution。从neuro-evolution这个名字就可以看出它由两部分组成-neuro and evolution,它是使用进化算法(遗传算法是进化算法的一种)提升人工神经网络的机器学习技术,其实就是用进化算法改进并选出最优的神经网络。如果你觉得这篇文章看起来稍微还有些吃力,或者想要系统地学习人工智能,那么推荐你去看床长人工智能教程。非常棒的大神之作,教程不仅通俗易懂,而且很风趣幽默。点击这里可以查看教程。

    neuro-evolution

    定义一些变量:

    import math import random # 神经网络3层, 1个隐藏层; 4个input和1个output network = [ 4, [ 16], 1] # 遗传算法相关 population = 50 elitism = 0.2 random_behaviour = 0.1 mutation_rate = 0.5 mutation_range = 2 historic = 0 low_historic = False score_sort = -1 n_child = 1 1

     

    定义神经网络:

     

    # 激活函数 def sigmoid(z): return 1.0/( 1.0+math.exp(-z)) # random number def random_clamped(): return random.random() 2-1 # "神经元" class Neuron(): def init(self):   self.biase = 0   self.weights = [] def init_weights(self, n):   self.weights = []   for i in range(n):    self.weights.append(random_clamped()) def repr(self):   return ‘Neuron weight size:{}  biase value:{}’.format(len(self.weights), self.biase) # 层 class Layer(): def init(self, index):   self.index = index   self.neurons = [] def init_neurons(self, n_neuron, n_input):   self.neurons = []   for i in range(n_neuron):    neuron = Neuron()    neuron.init_weights(n_input)    self.neurons.append(neuron) def repr(self):   return ‘Layer ID:{}  Layer neuron size:{}’.format(self.index, len(self.neurons)) # 神经网络 class NeuroNetwork(): def init(self):   self.layers = [] # input:输入层神经元数 hiddens:隐藏层 output:输出层神经元数 def init_neuro_network(self, input, hiddens , output):   index = 0   previous_neurons = 0   # input   layer = Layer(index)   layer.init_neurons(input, previous_neurons)   previous_neurons = input   self.layers.append(layer)   index += 1   # hiddens   for i in range(len(hiddens)):    layer = Layer(index)    layer.init_neurons(hiddens[i], previous_neurons)    previous_neurons = hiddens[i]    self.layers.append(layer)    index += 1   # output   layer = Layer(index)   layer.init_neurons(output, previous_neurons)   self.layers.append(layer) def get_weights(self):   data = { ‘network’:[], ‘weights’:[] }   for layer in self.layers:    data[ ‘network’].append(len(layer.neurons))    for neuron in layer.neurons:     for weight in neuron.weights:      data[ ‘weights’].append(weight)   return data def set_weights(self, data):   previous_neurons = 0   index = 0   index_weights = 0   self.layers = []   for i in data[ ‘network’]:    layer = Layer(index)    layer.init_neurons(i, previous_neurons)    for j in range(len(layer.neurons)):     for k in range(len(layer.neurons[j].weights)):      layer.neurons[j].weights[k] = data[ ‘weights’][index_weights]      index_weights += 1    previous_neurons = i    index += 1    self.layers.append(layer) # 输入游戏环境中的一些条件(如敌机位置), 返回要执行的操作 def feed_forward(self, inputs):   for i in range(len(inputs)):    self.layers[ 0].neurons[i].biase = inputs[i]   prev_layer = self.layers[ 0]   for i in range(len(self.layers)):    # 第一层没有weights    if i == 0:     continue    for j in range(len(self.layers[i].neurons)):     sum = 0     for k in range(len(prev_layer.neurons)):      sum += prev_layer.neurons[k].biase * self.layers[i].neurons[j].weights[k]     self.layers[i].neurons[j].biase = sigmoid(sum)    prev_layer = self.layers[i]   out = []   last_layer = self.layers[ -1]   for i in range(len(last_layer.neurons)):    out.append(last_layer.neurons[i].biase)   return out def print_info(self):   for layer in self.layers:    print(layer) 1

    遗传算法:

    # "基因组" class Genome(): def init(self, score, network_weights):   self.score = score   self.network_weights = network_weights class Generation(): def init(self):   self.genomes = [] def add_genome(self, genome):   i = 0   for i in range(len(self.genomes)):    if score_sort < 0:     if genome.score > self.genomes[i].score:      break    else:     if genome.score < self.genomes[i].score:      break   self.genomes.insert(i, genome)         # 杂交+突变 def breed(self, genome1, genome2, n_child):   datas = []   for n in range(n_child):    data = genome1    for i in range(len(genome2.network_weights[ ‘weights’])):     if random.random() <= 0.5:      data.network_weights[ ‘weights’][i] = genome2.network_weights[ ‘weights’][i]    for i in range(len(data.network_weights[ ‘weights’])):     if random.random() <= mutation_rate:      data.network_weights[ ‘weights’][i] += random.random() * mutation_range * 2 - mutation_range    datas.append(data)   return datas         # 生成下一代 def generate_next_generation(self):   nexts = []   for i in range(round(elitismpopulation)):    if len(nexts) < population:     nexts.append(self.genomes[i].network_weights)   for i in range(round(random_behaviour population)):    n = self.genomes[ 0].network_weights    for k in range(len(n[ ‘weights’])):     n[ ‘weights’][k] = random_clamped()    if len(nexts) < population:     nexts.append(n)   max_n = 0   while True:    for i in range(max_n):     childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1)     for c in range(len(childs)):      nexts.append(childs[c].network_weights)      if len(nexts) >= population:       return nexts    max_n += 1    if max_n >= len(self.genomes) -1:     max_n = 0 1

    NeuroEvolution:

    class Generations(): def init(self):   self.generations = [] def first_generation(self):   out = []   for i in range(population):    nn = NeuroNetwork()    nn.init_neuro_network(network[ 0], network[ 1], network[ 2])    out.append(nn.get_weights())   self.generations.append(Generation())   return out   def next_generation(self):   if len(self.generations) == 0:    return False   gen = self.generations[ -1].generate_next_generation()   self.generations.append(Generation())   return gen def add_genome(self, genome):   if len(self.generations) == 0:    return False   return self.generations[ -1].add_genome(genome) class NeuroEvolution(): def init(self):   self.generations = Generations() def restart(self):   self.generations = Generations() def next_generation(self):   networks = []   if len(self.generations.generations) == 0:    networks = self.generations.first_generation()   else:    networks = self.generations.next_generation()   nn = []   for i in range(len(networks)):    n = NeuroNetwork()    n.set_weights(networks[i])    nn.append(n)   if low_historic:    if len(self.generations.generations) >= 2:     genomes = self.generations.generations[len(self.generations.generations) - 2].genomes     for i in range(genomes):      genomes[i].network = None   if historic != -1:    if len(self.generations.generations) > historic+ 1:     del self.generations.generations[ 0:len(self.generations.generations)-(historic+ 1)]   return nn def network_score(self, score, network):   self.generations.add_genome(Genome(score, network.get_weights())) 1

    是AI就躲个飞机

    import pygame import sys from pygame.locals import import random import math import neuro_evolution BACKGROUND = ( 200, 200, 200) SCREEN_SIZE = ( 320, 480) class Plane(): def init(self, plane_image):   self.plane_image = plane_image   self.rect = plane_image.get_rect()   self.width = self.rect[ 2]   self.height = self.rect[ 3]   self.x = SCREEN_SIZE[ 0]/ 2 - self.width/ 2   self.y = SCREEN_SIZE[ 1] - self.height   self.move_x = 0   self.speed = 2   self.alive = True def update(self):   self.x += self.move_x * self.speed def draw(self, screen):   screen.blit(self.plane_image, (self.x, self.y, self.width, self.height)) def is_dead(self, enemes):   if self.x < -self.width or self.x + self.width > SCREEN_SIZE[ 0]+self.width:    return True   for eneme in enemes:    if self.collision(eneme):     return True   return False def collision(self, eneme):   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):    return True   else:    return False def get_inputs_values(self, enemes, input_size=4):   inputs = []   for i in range(input_size):    inputs.append( 0.0)   inputs[ 0] = (self.x 1.0 / SCREEN_SIZE[ 0])   index = 1   for eneme in enemes:    inputs[index] = eneme.x 1.0 / SCREEN_SIZE[ 0]    index += 1    inputs[index] = eneme.y* 1.0 / SCREEN_SIZE[ 1]    index += 1   #if len(enemes) > 0:    #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));   if len(enemes) > 0 and self.x < enemes[ 0].x:    inputs[index] = -1.0    index += 1   else:    inputs[index] = 1.0   return inputs class Enemy(): def init(self, enemy_image):   self.enemy_image = enemy_image   self.rect = enemy_image.get_rect()   self.width = self.rect[ 2]   self.height = self.rect[ 3]   self.x = random.choice(range( 0, int(SCREEN_SIZE[ 0] - self.width/ 2), 71))   self.y = 0 def update(self):   self.y += 6 def draw(self, screen):   screen.blit(self.enemy_image, (self.x, self.y, self.width, self.height)) def is_out(self):   return True if self.y >= SCREEN_SIZE[ 1] else False class Game(): def init(self):   pygame.init()   self.screen = pygame.display.set_mode(SCREEN_SIZE)   self.clock = pygame.time.Clock()   pygame.display.set_caption( ‘是AI就躲个飞机’)   self.ai = neuro_evolution.NeuroEvolution()   self.generation = 0   self.max_enemes = 1                 # 加载飞机、敌机图片   self.plane_image = pygame.image.load( ‘plane.png’).convert_alpha()   self.enemy_image = pygame.image.load( ‘enemy.png’).convert_alpha() def start(self):   self.score = 0   self.planes = []   self.enemes = []   self.gen = self.ai.next_generation()   for i in range(len(self.gen)):    plane = Plane(self.plane_image)    self.planes.append(plane)   self.generation += 1   self.alives = len(self.planes) def update(self, screen):   for i in range(len(self.planes)):    if self.planes[i].alive:     inputs = self.planes[i].get_inputs_values(self.enemes)     res = self.gen[i].feed_forward(inputs)     if res[ 0] < 0.45:      self.planes[i].move_x = -1     elif res[ 0] > 0.55:      self.planes[i].move_x = 1     self.planes[i].update()     self.planes[i].draw(screen)     if self.planes[i].is_dead(self.enemes) == True:      self.planes[i].alive = False      self.alives -= 1      self.ai.network_score(self.score, self.gen[i])      if self.is_ai_all_dead():       self.start()     self.gen_enemes()   for i in range(len(self.enemes)):    self.enemes[i].update()    self.enemes[i].draw(screen)    if self.enemes[i].is_out():     del self.enemes[i]     break   self.score += 1   print( “alive:{}, generation:{}, score:{}”.format(self.alives, self.generation, self.score), end= ’\r’) def run(self, FPS=1000):   while True:    for event in pygame.event.get():     if event.type == QUIT:      pygame.quit()      sys.exit()    self.screen.fill(BACKGROUND)    self.update(self.screen)    pygame.display.update()    self.clock.tick(FPS) def gen_enemes(self):   if len(self.enemes) < self.max_enemes:    enemy = Enemy(self.enemy_image)    self.enemes.append(enemy) def is_ai_all_dead(self):   for plane in self.planes:    if plane.alive:     return False   return True game = Game() game.start() game.run() 1

     

    AI的工作逻辑

     

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

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

     

     

     

                         

    最新回复(0)