首页新闻动态正文

纯Python实现人工智能【黑马python培训】

更新时间:2019年07月26日 11时10分26秒 来源:黑马程序员论坛

很久以前微信流行过一个小游戏:打飞机,这个游戏简单又无聊。在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
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
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_behaviourpopulation)):
   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
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
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.x1.0 / SCREEN_SIZE[0])
  index = 1
  for eneme in enemes:
   inputs[index] = eneme.x1.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
1


AI的工作逻辑



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

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


推荐了解热门学科

java培训 Python人工智能 Web前端培训 PHP培训
区块链培训 影视制作培训 C++培训 产品经理培训
UI设计培训 新媒体培训 产品经理培训 Linux运维
大数据培训 智能机器人软件开发




传智播客是一家致力于培养高素质软件开发人才的科技公司“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。

传智播客从未停止思考

传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”

中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。

何为中高级程序员课程?

传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。




黑马程序员热门视频教程【点击播放】

Python入门教程完整版(懂中文就能学会) 零起点打开Java世界的大门
C++| 匠心之作 从0到1入门学编程 PHP|零基础入门开发者编程核心技术
Web前端入门教程_Web前端html+css+JavaScript 软件测试入门到精通


在线咨询 我要报名
和我们在线交谈!