[技术]使用人工智能玩微信跳一跳
周六玩跳一跳小游戏,人工模式下只能到三十来分,玩了一会儿颇感气馁,决定挑战一下自我,写了一个人工智能程序来玩跳一跳。
一、人工智能-人工神经网络
人工神经网络目前是AI的主流发展方向之一,是模拟生物神经网络的突触联接的结构进行信息处理的数学模型。
生物科学家认为:神经元的基本功能是通过接受、整合、传导和输出信息实现信息交换。通过树突与其他神经元连接,通过突触来传递数据。
以下是人工神经网络的历史
1943年,基于生物神经网络莫克罗-彼特氏神经模型(McCulloch-Pitts′neuronmodel)诞生。
McCulloch-Pitts模型的基本思想是抽象和简化生物神经元的特征性成分。这个模型不需要捕捉神经元的所有属性和行为,但要足以捕获它执行计算的方式。McCulloch-Pitts模型的6个特点中前面4点和之前总结的生物神经元一致,具体对应请见下图:
1.每个神经元都是一个多输入单输出的信息处理单元;2.神经元输入分兴奋性输入和抑制性输入两种类型;3.神经元具有空间整合特性和阈值特性;4.神经元输入与输出间有固定的时滞,主要取决于突触延搁;5.忽略时间整合作用和不应期;6.神经元本身是非时变的,即其突触时延和突触强度均为常数。
似乎上图就是人工神经网络的鼻祖了,是的,它比计算机行业还要古老。
从上述模型中可以依稀看到生物神经网络的原理:某个神经元,接收到不同突触传来的信号,将信号进行加工,最终转换为输出。
80年代,各方研究室都在研究如何制造人工神经网络,1986年出版了《Learning representations by back-propagating errors》,将BP算法运用在神经网络上,自此之后BP神经网络开始大行其道,直至今日,采用了BP算法的前馈式神经网络成为了运用最广泛的人工神经网络。
人工神经网络
人工神经网络是模拟生物神经网络的数学模型,最早的时候只有一些数学家在模拟,近来由于学术界与工业界的互相渗透,人工神经网络的使用场景也越来越丰富,现在已有遍地皆是之感。
以上就是人工神经网络的核心部分:一个输入层,一到多个隐含层,一个输出层,输入层与隐含层的连接有各自的权重,隐含层的每一个节点都有其**函数,隐含层与输出层之间也有其连接权重。
常见的情况是:
1、初始化一批训练数据,包含【输入值,期望输出】
2、将输入值输入“输入层”
3、输入层根据连接权重将输入值分解到各“隐含层”节点
4、隐含层节点接受到各个输入层传递来的数据,通过**函数,计算输出
5、将输出根据权重输出到“输出层”
6、输出层汇总输出
其中关键的地方在于“**函数”+“连接权重”。
**函数是一种特殊的函数,具有如下的性质:y越接近0.5,其导数越大,y越接近0或者1,其导数越小。图形如下:
左侧的即为:Sigmoid**函数,算法是:σ(x)=1/(1+e−x),即var value = 1 / (1 + Math.exp(-x));
如果大家看不懂,那么我们换一种说法:**函数是逻辑斯蒂函数的变种,逻辑斯蒂方程又名生物增长自我抑制方程:
逻辑斯蒂方程是初中生物的知识,用于描述生物数量的增长曲线:
1.开始期,由于种群个体数很少,密度增长缓慢,又称潜伏期。
2.加速期,随个体数增加,密度增长加快。
3.转折期,当个体数达到饱和密度一半(K/2),密度增长最快。
4.减速期,个体数超过密度一半(K/2)后,增长变慢。
5.饱和期,种群个体数达到K值而饱和。
当把逻辑斯蒂方程运用在人工神经网络的隐含层节点时,就会发生一个十分奇妙的现象:隐含层节点的输出总是趋于1或者趋于0的。(其原理为通过一定的数学设计,当y=0.5时,输出结果趋于不稳定,仅有当y=1或者0时,输出结果趋于稳定。这样就使得在重复运算中,隐含层节点的输出总是趋于1或者趋于0,通过1和0的状态来保留输入值的特征)在漫长的训练中,隐含层节点最终通过**函数把“**神经元的特征”通过函数形式保留并映射出来。据此,人工神经网络可以成功解决很多“非线性问题”。
什么是非线性问题?举个例子:F=ma 这个就是线性问题;而给出一张照片,判断这张照片上是否有一只猫就是非线性问题。
非线性问题是十分常见的,如照片识别,音纹识别,人工AI等等。
刚才提到了一个概念“漫长的训练中”,为什么人工智能或者机器学习都需要漫长训练?此处涉及到了概率论的知识:贝叶斯公式
贝叶斯老爷子和牛顿是同一个时代的人,不同的是:牛顿是个物理学家,而贝叶斯是一名职(wai)业(guo)牧(he)师(shang),既然是牧师,自然需要虔诚的研究上帝以及和上帝相关的东西。贝叶斯老爷子研究的是“信念”,即信念是如何产生的。
他的研究结果即是贝叶斯公式,也即:先验概率修正公式。
举个例子:你去A医院体检,医生说你得了癌症,一半情况你不信;再换B医院体检,医生还是说你得了癌症,你会半信半疑;再换C医院体检,医生依旧说你得了癌症,那你肯定就信了。
贝叶斯公式就是这样的原理:根据经验制定一个先验概率,然后根据不断出现的事实,对此概率进行修正,重复一定的次数,修正的概率最终会达到其实际的概率。这就是信念修正法则。
在机器学习和人工智能中,贝叶斯法则比比皆是,通过长期不停的训练,最终你的机器和brain将会拥有匹配你提供数据的智能。
例如在BR前馈式神经网络中,通过每一个节点训练足够的次数,最终贝叶斯会告诉你真实的结果。
以上就是铺垫:生物神经网络,人工神经网络模型,**函数,连接权重,贝叶斯法则。
接下来我们实现一个可用的神经网络;
二、人工神经网络
人工神经网络无外乎:数据的输入,隐含层节点的确定,隐含层**函数,输出层输出等等。
前些年出现了新的卷积神经网络CNN,在图像识别上应用比较广泛。我们从简单的开始入手。
业内神经网络的语言一般有四种:Matlab数学家专用,Python工业界常用,C语言混合使用,其他语言偶发性使用。
抛开语言的不同,其实代码实现原理基本是相同的,对于一个顶级IT从业者来说,其实现其实区别不大。
我们找了一个Nodejs版本的神经网络brain.js,参见https://github.com/harthur/brain
选择该版本的原因为:小,且五脏俱全。
其实业内标准做法是Python,因为基础设施健全。但因为我不太想费心去找代码了,因此选择了brain.js。
brain.js是一个裸的人工智能核心,具有训练、测试、反馈等功能,代码只有五百余行,有兴趣的可以拜读一下。
另:可以考虑把brain.js翻译为C语言版本的,或者CUDA语言,可以适用于通用CPU或者GPU上运行。
关于brain.js的使用方法如下:
var net = new brain.NeuralNetwork(); net.train([{input: [0, 0], output: [0]}, {input: [0, 1], output: [1]}, {input: [1, 0], output: [1]}, {input: [1, 1], output: [0]}]); var output = net.run([1, 0]); // [0.987]
内部代码的翻译可见:
[KANMARS原创]-人工神经网络brain.js算法解析
http://www.kanmars.com/2016/07/13/2016-07-13-neuralnetwork_analysis/
三、人工智能工程化
在学习了人工智能原理之后,我们需要构建一个人工智能工程了。如果上上面的brain.js是一条龙虾,那么将人工智能工程化的步骤就是做满汉全席了。
上图是一个人工神经网络工程化的模型。brain.js是核心部位的关键组成,负责对数据训练,生成brain,提供brain的存取与恢复。
左侧部分为人工神经网络的训练和测试部分
右侧为将训练出的神经网络运用在实际场景中,并根据实际场景的结果决定是否要加载到知识库中。
纵向来看,人工神经网络包含:
1)原始数据采集:采集照片、音频、特征码等数据
2)数据转化层:将单个原始数据转化为数字型数据,例如:将照片进行灰度、压缩处理,提取特征,提取音频转化为数字信号等
3)数据清洗层:将单个或者多个数据转化层的数据,清洗合并为统一格式的人工神经网络可识别的输入输出值
4)训练层:将数据清洗层生成的大批量数据交由人工智能核心训练,并生成新的brain
5)测试层:使用新的brain对测试数据进行测试,判断新brain是否符合实际需求
6)训练数据采集工具:辅助性工具,帮助操作人员批量获取训练数据
7)运用层:当brain已经训练好,则可交付外部使用,外部可以通过“执行工具-》原始数据采集层-》数据转化层-》运用层-》人工神经网络”的顺序发起调用,其中的“原始数据采集层”和“数据转化层”可以与训练阶段共享。(但没有“数据清洗层”,因为在实际运用中,往往是对单条数据进行运用)
8)结果汇总层:brain的输出结果往往有很多个,需要在结果汇总层进行数据汇总
9)结果处理层:结果处理层是根据汇总的结果进行下一步实际操作的步骤,并且最终产生了“响应”
10)结果反馈层:记录每一次的输入输出到监督学习区
11)监督学习:在此步骤判断正确的“输入输出”,并录入到训练阶段的“原始数据采集层”中
可以看到,按照此模型,仅需适当的“引导”(训练数据采集层),即可让人工神经网络运转起来。
-----------------------------------------------------------------------------------------------------
项目如下:
-----------------------------------------------------------------------------------------------------
上图为一个可运行的神经网络工程化项目:
1)traintools_000_main.js:训练数据采集工具,用于在手机上截屏,并且记录每次截屏的跳一跳需要按下时间
2)traintools_001_getPixs.js:数据转化层,将采集到的图片进行解码,编码为灰度图片,压缩35*35倍生成小图片特征
3)traintools_002_getCleanData.js:数据清洗层,将小图片特征与每张小图片的按下时间进行汇总,最终生成批量清洗数据
4)traintools_003_startTrain.js:训练层,将批量清洗数据灌入brain.js,并生成最终的brain
5)traintools_004_startTest.js:测试层,将生成的brain对测试数据进行测试,判断最终命中率
读到这边,估计很多人纳闷:生成的brain是什么?
brain就是:受过训练的大脑。你可以把它想象成一颗泡在福尔马林中的标本。
截图如下:
图中这一串串串串串绿油油的数据就是brain,模拟了神经元模型中,每个神经元与其他神经元的连接点,连接权重等信息。
6)main.js:执行工具,用于触发每一次实际的操作
7)sh_use_001_getPixs.js:数据转化层,将采集到的图片进行解码,编码为灰度图片,压缩35*35倍生成小图片特征
与traintools_001_getPixs.js基本类似,代码共用。共用部分放在common.js和common.pixs.js中
8)sh_use_002_startBrain.js:运用层,数据汇总层,将上个步骤采集到的“实时数据”灌注到生成的brain中,并获取结果,将结果进汇总为可识别的数据
9)sh_use_003_dosth.js:结果处理层,根据可识别的数据执行后续操作。在本跳一跳示例中,是实现了:往前跳 的操作。
此外在sh_use_003_dosth.js中兼职了结果反馈层,监督学习的工作,可以将每一跳都作为 下一次的学习数据,大大提升了系统的闭环性。
通过以上步骤你就看到了一个可用于“微信跳一跳”小程序的人工神经网络。通过对跳一跳进行训练,使它可以初步运行,然后投入实际生产环境,在不断的使用中学习前进,最终可以达到:
具有自我意识,能自动判断前进距离,自动向前跳跃的能力。
(受限于时间、CPU性能、算法等因素,这个跳一跳程序目前只能达到三岁小孩的智力,能往前跳三步左右,相信只要有充足的时间,可以将这个程序训练为跳一百、一千步的高手)
另外我比较欣慰的是:有以上程序,我仅需把数据采集层和结果处理层进行适当修改,以上程序可以运用在各种场景中:验证码识别、身份证识别、音频采集等等,应用场景十分广阔。
----------------------------------------------------------------------------------------------------------------------
缺陷:任何事物都有缺陷,人工神经网络也不例外,它的缺陷如下,也是目前世界正在努力解决的问题:
1)原始数据采集问题:人工智能驾驶使用的是激光采集器,十分昂贵。而人工智能至今未能制造出可媲美人类眼睛、耳朵、皮肤的器官。因此原始数据不纯净的问题严重阻碍了人工智能发展。本例中采用了手机视频截图,adb shell 截屏
2)层与层数据传输问题:本例使用的是文件式传输,但是文件式传输速度略慢,将来可以改成共享内存或者消息队列,或者流式计算
3)brain.js性能问题:js性能,比c还是略差一点的,比GPU运算更是慢了不止一点。当前人工神经网络的重点研究方向就是计算效能的提升,又分为空间效率和时间效率:
3.1)时间效率:同一批数据,A神经网络用一天可以学习完成,B神经网络用三天可以学习完成,则A的效率高于B
3.2)空间效率:同一批数据,A神经网络学习十分之一即可完成99.99%识别,而B神经网络学习二分之一才能完成99.99%识别,则A的效率高于B
这两个方向是神经网络专家的研究方向,我见过不少专家的算法,都是在这两个方面努力的
4)监督学习问题:人为监督还是机器自我监督,使用机器自我监督会更加节省。
全文完。