纯Python实现人工智能

                                   
               

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

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

neuro-evolution

定义一些变量:


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

 

定义神经网络:

 


  
  
  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. class Neuron():
  9. def init(self):
  10.   self.biase = 0
  11.   self.weights = []
  12. def init_weights(self, n):
  13.   self.weights = []
  14.   for i in range(n):
  15.    self.weights.append(random_clamped())
  16. def repr(self):
  17.   return ‘Neuron weight size:{}  biase value:{}’.format(len(self.weights), self.biase)
  18. # 层
  19. class Layer():
  20. def init(self, index):
  21.   self.index = index
  22.   self.neurons = []
  23. def init_neurons(self, n_neuron, n_input):
  24.   self.neurons = []
  25.   for i in range(n_neuron):
  26.    neuron = Neuron()
  27.    neuron.init_weights(n_input)
  28.    self.neurons.append(neuron)
  29. def repr(self):
  30.   return ‘Layer ID:{}  Layer neuron size:{}’.format(self.index, len(self.neurons))
  31. # 神经网络
  32. class NeuroNetwork():
  33. def init(self):
  34.   self.layers = []
  35. # input:输入层神经元数 hiddens:隐藏层 output:输出层神经元数
  36. def init_neuro_network(self, input, hiddens , output):
  37.   index = 0
  38.   previous_neurons = 0
  39.   # input
  40.   layer = Layer(index)
  41.   layer.init_neurons(input, previous_neurons)
  42.   previous_neurons = input
  43.   self.layers.append(layer)
  44.   index += 1
  45.   # hiddens
  46.   for i in range(len(hiddens)):
  47.    layer = Layer(index)
  48.    layer.init_neurons(hiddens[i], previous_neurons)
  49.    previous_neurons = hiddens[i]
  50.    self.layers.append(layer)
  51.    index += 1
  52.   # output
  53.   layer = Layer(index)
  54.   layer.init_neurons(output, previous_neurons)
  55.   self.layers.append(layer)
  56. def get_weights(self):
  57.   data = { ‘network’:[], ‘weights’:[] }
  58.   for layer in self.layers:
  59.    data[ ‘network’].append(len(layer.neurons))
  60.    for neuron in layer.neurons:
  61.     for weight in neuron.weights:
  62.      data[ ‘weights’].append(weight)
  63.   return data
  64. def set_weights(self, data):
  65.   previous_neurons = 0
  66.   index = 0
  67.   index_weights = 0
  68.   self.layers = []
  69.   for i in data[ ‘network’]:
  70.    layer = Layer(index)
  71.    layer.init_neurons(i, previous_neurons)
  72.    for j in range(len(layer.neurons)):
  73.     for k in range(len(layer.neurons[j].weights)):
  74.      layer.neurons[j].weights[k] = data[ ‘weights’][index_weights]
  75.      index_weights += 1
  76.    previous_neurons = i
  77.    index += 1
  78.    self.layers.append(layer)
  79. # 输入游戏环境中的一些条件(如敌机位置), 返回要执行的操作
  80. def feed_forward(self, inputs):
  81.   for i in range(len(inputs)):
  82.    self.layers[ 0].neurons[i].biase = inputs[i]
  83.   prev_layer = self.layers[ 0]
  84.   for i in range(len(self.layers)):
  85.    # 第一层没有weights
  86.    if i == 0:
  87.     continue
  88.    for j in range(len(self.layers[i].neurons)):
  89.     sum = 0
  90.     for k in range(len(prev_layer.neurons)):
  91.      sum += prev_layer.neurons[k].biase * self.layers[i].neurons[j].weights[k]
  92.     self.layers[i].neurons[j].biase = sigmoid(sum)
  93.    prev_layer = self.layers[i]
  94.   out = []
  95.   last_layer = self.layers[ -1]
  96.   for i in range(len(last_layer.neurons)):
  97.    out.append(last_layer.neurons[i].biase)
  98.   return out
  99. def print_info(self):
  100.   for layer in self.layers:
  101.    print(layer)
  • 1

遗传算法:


  
  
  1. # "基因组"
  2. class Genome():
  3. def init(self, score, network_weights):
  4.   self.score = score
  5.   self.network_weights = network_weights
  6. class Generation():
  7. def init(self):
  8.   self.genomes = []
  9. def add_genome(self, genome):
  10.   i = 0
  11.   for i in range(len(self.genomes)):
  12.    if score_sort < 0:
  13.     if genome.score > self.genomes[i].score:
  14.      break
  15.    else:
  16.     if genome.score < self.genomes[i].score:
  17.      break
  18.   self.genomes.insert(i, genome)
  19.         # 杂交+突变
  20. def breed(self, genome1, genome2, n_child):
  21.   datas = []
  22.   for n in range(n_child):
  23.    data = genome1
  24.    for i in range(len(genome2.network_weights[ ‘weights’])):
  25.     if random.random() <= 0.5:
  26.      data.network_weights[ ‘weights’][i] = genome2.network_weights[ ‘weights’][i]
  27.    for i in range(len(data.network_weights[ ‘weights’])):
  28.     if random.random() <= mutation_rate:
  29.      data.network_weights[ ‘weights’][i] += random.random() * mutation_range * 2 - mutation_range
  30.    datas.append(data)
  31.   return datas
  32.         # 生成下一代
  33. def generate_next_generation(self):
  34.   nexts = []
  35.   for i in range(round(elitismpopulation)):
  36.    if len(nexts) < population:
  37.     nexts.append(self.genomes[i].network_weights)
  38.   for i in range(round(random_behaviour population)):
  39.    n = self.genomes[ 0].network_weights
  40.    for k in range(len(n[ ‘weights’])):
  41.     n[ ‘weights’][k] = random_clamped()
  42.    if len(nexts) < population:
  43.     nexts.append(n)
  44.   max_n = 0
  45.   while True:
  46.    for i in range(max_n):
  47.     childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1)
  48.     for c in range(len(childs)):
  49.      nexts.append(childs[c].network_weights)
  50.      if len(nexts) >= population:
  51.       return nexts
  52.    max_n += 1
  53.    if max_n >= len(self.genomes) -1:
  54.     max_n = 0
  • 1

NeuroEvolution:


  
  
  1. class Generations():
  2. def init(self):
  3.   self.generations = []
  4. def first_generation(self):
  5.   out = []
  6.   for i in range(population):
  7.    nn = NeuroNetwork()
  8.    nn.init_neuro_network(network[ 0], network[ 1], network[ 2])
  9.    out.append(nn.get_weights())
  10.   self.generations.append(Generation())
  11.   return out
  12.  
  13. def next_generation(self):
  14.   if len(self.generations) == 0:
  15.    return False
  16.   gen = self.generations[ -1].generate_next_generation()
  17.   self.generations.append(Generation())
  18.   return gen
  19. def add_genome(self, genome):
  20.   if len(self.generations) == 0:
  21.    return False
  22.   return self.generations[ -1].add_genome(genome)
  23. class NeuroEvolution():
  24. def init(self):
  25.   self.generations = Generations()
  26. def restart(self):
  27.   self.generations = Generations()
  28. def next_generation(self):
  29.   networks = []
  30.   if len(self.generations.generations) == 0:
  31.    networks = self.generations.first_generation()
  32.   else:
  33.    networks = self.generations.next_generation()
  34.   nn = []
  35.   for i in range(len(networks)):
  36.    n = NeuroNetwork()
  37.    n.set_weights(networks[i])
  38.    nn.append(n)
  39.   if low_historic:
  40.    if len(self.generations.generations) >= 2:
  41.     genomes = self.generations.generations[len(self.generations.generations) - 2].genomes
  42.     for i in range(genomes):
  43.      genomes[i].network = None
  44.   if historic != -1:
  45.    if len(self.generations.generations) > historic+ 1:
  46.     del self.generations.generations[ 0:len(self.generations.generations)-(historic+ 1)]
  47.   return nn
  48. def network_score(self, score, network):
  49.   self.generations.add_genome(Genome(score, network.get_weights()))
  • 1

是AI就躲个飞机


  
  
  1. import pygame
  2. import sys
  3. from pygame.locals import
  4. import random
  5. import math
  6. import neuro_evolution
  7. BACKGROUND = ( 200, 200, 200)
  8. SCREEN_SIZE = ( 320, 480)
  9. class Plane():
  10. def init(self, plane_image):
  11.   self.plane_image = plane_image
  12.   self.rect = plane_image.get_rect()
  13.   self.width = self.rect[ 2]
  14.   self.height = self.rect[ 3]
  15.   self.x = SCREEN_SIZE[ 0]/ 2 - self.width/ 2
  16.   self.y = SCREEN_SIZE[ 1] - self.height
  17.   self.move_x = 0
  18.   self.speed = 2
  19.   self.alive = True
  20. def update(self):
  21.   self.x += self.move_x * self.speed
  22. def draw(self, screen):
  23.   screen.blit(self.plane_image, (self.x, self.y, self.width, self.height))
  24. def is_dead(self, enemes):
  25.   if self.x < -self.width or self.x + self.width > SCREEN_SIZE[ 0]+self.width:
  26.    return True
  27.   for eneme in enemes:
  28.    if self.collision(eneme):
  29.     return True
  30.   return False
  31. def collision(self, eneme):
  32.   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):
  33.    return True
  34.   else:
  35.    return False
  36. def get_inputs_values(self, enemes, input_size=4):
  37.   inputs = []
  38.   for i in range(input_size):
  39.    inputs.append( 0.0)
  40.   inputs[ 0] = (self.x 1.0 / SCREEN_SIZE[ 0])
  41.   index = 1
  42.   for eneme in enemes:
  43.    inputs[index] = eneme.x 1.0 / SCREEN_SIZE[ 0]
  44.    index += 1
  45.    inputs[index] = eneme.y* 1.0 / SCREEN_SIZE[ 1]
  46.    index += 1
  47.   #if len(enemes) > 0:
  48.    #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));
  49.   if len(enemes) > 0 and self.x < enemes[ 0].x:
  50.    inputs[index] = -1.0
  51.    index += 1
  52.   else:
  53.    inputs[index] = 1.0
  54.   return inputs
  55. class Enemy():
  56. def init(self, enemy_image):
  57.   self.enemy_image = enemy_image
  58.   self.rect = enemy_image.get_rect()
  59.   self.width = self.rect[ 2]
  60.   self.height = self.rect[ 3]
  61.   self.x = random.choice(range( 0, int(SCREEN_SIZE[ 0] - self.width/ 2), 71))
  62.   self.y = 0
  63. def update(self):
  64.   self.y += 6
  65. def draw(self, screen):
  66.   screen.blit(self.enemy_image, (self.x, self.y, self.width, self.height))
  67. def is_out(self):
  68.   return True if self.y >= SCREEN_SIZE[ 1] else False
  69. class Game():
  70. def init(self):
  71.   pygame.init()
  72.   self.screen = pygame.display.set_mode(SCREEN_SIZE)
  73.   self.clock = pygame.time.Clock()
  74.   pygame.display.set_caption( ‘是AI就躲个飞机’)
  75.   self.ai = neuro_evolution.NeuroEvolution()
  76.   self.generation = 0
  77.   self.max_enemes = 1
  78.                 # 加载飞机、敌机图片
  79.   self.plane_image = pygame.image.load( ‘plane.png’).convert_alpha()
  80.   self.enemy_image = pygame.image.load( ‘enemy.png’).convert_alpha()
  81. def start(self):
  82.   self.score = 0
  83.   self.planes = []
  84.   self.enemes = []
  85.   self.gen = self.ai.next_generation()
  86.   for i in range(len(self.gen)):
  87.    plane = Plane(self.plane_image)
  88.    self.planes.append(plane)
  89.   self.generation += 1
  90.   self.alives = len(self.planes)
  91. def update(self, screen):
  92.   for i in range(len(self.planes)):
  93.    if self.planes[i].alive:
  94.     inputs = self.planes[i].get_inputs_values(self.enemes)
  95.     res = self.gen[i].feed_forward(inputs)
  96.     if res[ 0] < 0.45:
  97.      self.planes[i].move_x = -1
  98.     elif res[ 0] > 0.55:
  99.      self.planes[i].move_x = 1
  100.     self.planes[i].update()
  101.     self.planes[i].draw(screen)
  102.     if self.planes[i].is_dead(self.enemes) == True:
  103.      self.planes[i].alive = False
  104.      self.alives -= 1
  105.      self.ai.network_score(self.score, self.gen[i])
  106.      if self.is_ai_all_dead():
  107.       self.start()
  108.  
  109.   self.gen_enemes()
  110.   for i in range(len(self.enemes)):
  111.    self.enemes[i].update()
  112.    self.enemes[i].draw(screen)
  113.    if self.enemes[i].is_out():
  114.     del self.enemes[i]
  115.     break
  116.   self.score += 1
  117.   print( “alive:{}, generation:{}, score:{}”.format(self.alives, self.generation, self.score), end= ’\r’)
  118. def run(self, FPS=1000):
  119.   while True:
  120.    for event in pygame.event.get():
  121.     if event.type == QUIT:
  122.      pygame.quit()
  123.      sys.exit()
  124.    self.screen.fill(BACKGROUND)
  125.    self.update(self.screen)
  126.    pygame.display.update()
  127.    self.clock.tick(FPS)
  128. def gen_enemes(self):
  129.   if len(self.enemes) < self.max_enemes:
  130.    enemy = Enemy(self.enemy_image)
  131.    self.enemes.append(enemy)
  132. def is_ai_all_dead(self):
  133.   for plane in self.planes:
  134.    if plane.alive:
  135.     return False
  136.   return True
  137. game = Game()
  138. game.start()
  139. game.run()
  • 1

 

AI的工作逻辑

 

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

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

 

 

 

                     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值