如何用遗传算法进化出一只聪明的小鹦鹉

问题

现在有一些样本数据,如下表所示。你是否能找到其中的规律,然后计算出新样本的output是多少?

input

output

样本1

5, 8, 7

9

样本2

2, 8, 4

6

样本3

3, 0, 5

3

样本4

9, 12, 13

15

新样本

10, 6, 8

?

乍一看,规律似乎并不明显。

仔细看,可能会发现其中的规律:output=input1+input2/2+input3*0,因此问号处的值应该是13。

现在,我们想让一只小鹦鹉来做这个事情。这当然不是现实中的小鹦鹉,而是我们用代码写的小鹦鹉。

小鹦鹉

小鹦鹉要想解出上面的题目,必须会“思考”。这里的思考,我们可以理解为:具有将input转换成output的能力。我们选择神经网络作为鹦鹉的大脑。

神经网络

我们知道,人脑中有无数个神经元,神经元之间通过轴突连接。当某个神经元接收到足够多的信号后,就会被“触发”。而被“触发”的神经元会发送信号到临近的神经元,临近的神经元接收到足够的信号后,又会被“触发”。这样的过程被称之为“思考”。

我们可以用程序模拟这个过程。为了简化,这里只使用一层网络。我们给每个轴突(连接神经元的线)设置一个权重,每一个input乘以相应的轴突权重会得出一个值,然后对这些值再求和,得出output。即output=input1*w1+input2*w2+input3*w3

这就是一个简单的“大脑”。大脑是否聪明,取决于[w1,w2,w3]的值的组合。如果这三个权重值能够满足提出的问题,那它就是“聪明”的,否则就是“笨”的。于是,刚才的问题就转换成:如何找到一组“聪明”的权重组合。

对于文章开头的问题,我们已经知道,[w1=1,w2=0.5,w3=0]这种组合是最好的。那,如何生成这样的“大脑”呢?

上帝之手

现在,我们可以扮演上帝的角色,随性的创造物种。假设我们创造了一只鹦鹉,它的脑子就是一个有3个权重的神经网络。这只鹦鹉只会做上面的题(但不一定能做好)。它的大脑是随机生成的,假设他的权重组合为[0.5,0.3,1.2]。

此时,这只鹦鹉就可以用大脑去“思考”上面的问题了。它会先看样本数据,从样本1开始看。这只鹦鹉根据input算出来的output是:0.5*5+0.3*8+1.2*7=13.3,而样本给出的output是9。于是它的误差(error1)是13.3-9=4.3。同样,还可以知道这只鹦鹉计算其它样本时的误差,它们分别是:

error2=2.2

error3=4.5

error4=8.7

我们知道,鹦鹉计算得越准(误差越小),就越聪明。因此,我们可以给鹦鹉的智商设定一个计算方法:

根据这个公式,可以算出这只鹦鹉的智商(intelligence)为9.15

我们再随机创建第二只鹦鹉。假设它的大脑的神经网络权重组合为[0.8,0.7,0.1]。

根据同样的方法,可以算出它的智商为35.65。它比第一支鹦鹉“聪明”!

进化

种群

我们可以创建一个鹦鹉种群,这个种群里有若干只鹦鹉,比如有100只。每个鹦鹉的智商也各不相同。下一步就是让这个种群进行自我进化。

进化

物竞天择、适者生存!大自然的这个法则,让地球上的物种不断进化,诞生了越来越高级的物种,乃至出现了我们人类。我们的这个鹦鹉种群也可以通过进化变得越来越聪明。

种群中的鹦鹉比拼的是智商。每一次比拼,我们把低智商的鹦鹉淘汰掉,把高智商鹦鹉留下来。然后,让留下来的鹦鹉繁衍下一代,这样它们和下一代的个体会组成一个新群体。然后再来一次全员智商比拼,再把低智商鹦鹉淘汰掉,高智商留下。留下的鹦鹉再次繁殖。这样不断迭代,经过若干代的筛选后,最后留下的就是特别聪明的鹦鹉。

在最后留下来的鹦鹉中,找到最聪明的那个。让它去“思考”文章开头提到的问题,它会给出一个不错的答案!

繁衍

现实中的鹦鹉是双性繁殖,那是长期进化的结果。我们的鹦鹉还很原始,只能单性繁殖:)

繁殖的方式是把自己复制一份,再做一次“基因突变”。所谓“基因突变”就是对神经网络的权重进行微调。比如有一只鹦鹉,它的大脑神经网络是[2, 3, 3.5],它繁衍的某一个后代可能是[2, 3.01, 3.5]或[1.98, 3, 3.5]等。

这样,后代基本保留了父代智商,又做了微调。这种微调可能是正向的(更聪明),也可能是负向的(更笨)。

代码

import random
import copy
import numpy as np

class Parrot():
    brain = 2 * np.random.random((3, 1)) - 1
    intelligence = 0

    def think(self,inputs):
        return np.dot(inputs,self.brain)

    '''
    基因变异
    '''    
    def mutation(self,max=0.05):
        #随机选中一个神经网络权重,进行微调
        index = np.random.randint(0,len(self.brain))
        adjustment = np.random.uniform(-max,max)
        self.brain[index] +=adjustment

    def copy(self):
        child = Parrot()
        child.brain = copy.copy(self.brain)
        child.intelligence = self.intelligence
        return child


class GA():
    def __init__(self, count):
        #进化的代数
        self.gen_num = 0
        # 种群中个体数量
        self.count = count
        # 种群个体要尽可能得去满足input和output关系
        self.inputs,self.outputs=self.load_data()
        # 随机生成初始种群
        self.population = self.gen_population(count)

    def load_data(self):
        inputs = np.array([[5, 8, 7], [2, 8, 4], [3, 0, 5], [9, 12, 13]])
        outputs = np.array([[9, 6, 3, 15]]).T
        return inputs,outputs

    def create_parrot(self):
        parrot = Parrot()
        parrot.brain = 2 * np.random.random((3, 1)) - 1
        parrot.intelligence = self.calc_intelligence(parrot)
        return parrot

    """
    获取初始种群
    """    
    def gen_population(self,count):
        return [self.create_parrot() for i in range(count)]    

    #计算适应度
    def calc_intelligence(self, parrot):
        errors = self.outputs - parrot.think(self.inputs)
        intelligence = 1/np.sum(np.sqrt(np.square(errors)))
        return intelligence

    '''
    繁殖
    '''
    def reproduction(self, mothers):
        # 新出生的孩子,最终会被加入存活下来的父母之中,形成新一代的种群。
        children = []
        # 需要繁殖的孩子的量
        target_count = len(self.population) - len(mothers)
        # 开始根据需要的量进行繁殖
        while len(children) < target_count:
            mother = mothers[np.random.randint(0,len(mothers))]
            child = mother.copy()
            child.mutation()
            children.append(child)
        self.population = mothers + children
    
    '''
    选择
    '''
    def selection(self, retain_rate, random_select_rate):
        # 计算每一个鹦鹉的智商
        graded = [(self.calc_intelligence(parrot), parrot) for parrot in self.population]
        # 智商从大到小进行排序
        graded = [x[1] for x in sorted(graded, key = lambda graded: graded[0], reverse=True)]
        # 选出智商最高的一部分鹦鹉
        retain_length = int(len(graded) * retain_rate)
        retain_parrots = graded[:retain_length]
        # 选出智商不高,但是幸存的鹦鹉
        for parrot in graded[retain_length:]:
            if random.random() < random_select_rate:
                retain_parrots.append(parrot)
        return retain_parrots        
    
    '''
    进化
    retain_rate:保留最聪明个体的比例
    random_select_rate:不够聪明的个体中,也要保留一定比例的个体,以保持物种的多样性。
    '''    
    def evolve(self,retain_rate=0.2, random_select_rate=0.2):
        self.gen_num += 1
        mothers = self.selection(retain_rate, random_select_rate)
        self.reproduction(mothers)

    def smartest_parrot(self):
        graded = [(self.calc_intelligence(parrot), parrot) for parrot in self.population]
        graded = [x[1] for x in sorted(graded, key = lambda graded: graded[0], reverse=True)]
        return graded[0]    

if __name__ == '__main__':
    #种群数量为100
    ga = GA(100)
    for x in range(300):
        ga.evolve()
    winner = ga.smartest_parrot()
    print("brain=",winner.brain.T)
    print("output=",winner.think(np.array([10, 6, 8])))

运行

python3 ga.py 

运行结果

brain= [[0.99293629 0.498883   0.00599333]]
output= [12.97060759]

新样本中的output应该是13,进化出来的鹦鹉给出的答案是12.97060759,已经相当接近!

它的大脑[0.99293629, 0.498883, 0.00599333]与最优解[1,0.5,0]非常接近!

这就是自然选择的力量!

让我们向大自然的规则致敬!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AI科技大本营的专栏

从模型到应用,一文读懂因子分解机

作者在上篇文章中讲解了《矩阵分解推荐算法》,我们知道了矩阵分解是一类高效的嵌入算法,通过将用户和标的物嵌入低维空间,再利用用户和标的物嵌入向量的内积来预测用户对...

14920
来自专栏机器之心

AI做八年级试卷得90多分,艾伦研究所问答系统已达中学水平

当地时间周三,西雅图艾伦人工智能研究所正式推出新 AI 系统 Aristo,该系统在八年级的科学测试中答对了 90%以上的问题,并在十二年级的测试中答对了 80...

18130
来自专栏机器之心

寻找最佳的神经网络架构,韩松组两篇论文解读

第二篇则是利用强化学习自动寻找在特定 latency 标准上精度最好的量化神经网络结构,它分别为网络的每一层搜索不同 bit 的权值和激活,得到一个经过优化的混...

11610
来自专栏AI科技大本营的专栏

取代Python?Rust凭什么

【导语】Rust 也能实现神经网络?在前一篇帖子中,作者介绍了MNIST数据集以及分辨手写数字的问题。在这篇文章中,他将利用前一篇帖子中的代码,通过Rust实现...

13310
来自专栏机器之心

用AI打个电话骗走22万欧元,克隆你的语音只需5秒录音

AI 技术的应用门槛正在不断降低,换脸、换声音、生成各种不存在的人像都变得非常容易,但与此同时,犯罪的门槛也降低了。

18430
来自专栏毛利学Python

机器学习之kNN算法

邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的...

14440
来自专栏村雨

自然语言处理NLP(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

7940
来自专栏机器之心

拍照太糊?你需要了解下美图人像画质修复技术

在美图秀秀推出的小程序中,用户只需上传一张老照片,就能使用 AI 还原旧时光,把模糊照片变得更高清。

30020
来自专栏机器之心

今年NeurIPS门票不用抢,靠运气抽

大会表示,为了确保门票获取的公平性,今年不拼手速和网速,而是随机抽取申请者发放邀请函,以确保不同时区、不同网速和那些需要上传学生证的同学都能抢到票。根据新规则,...

10310
来自专栏村雨

第1章 导论

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

9710

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励