特稿 >

前沿热点 >

RNN会写自己的代码,你怎么看待机器自动编程? 程序员会下岗吗?

RNN会写自己的代码,你怎么看待机器自动编程? 程序员会下岗吗?

AI100原创 丨 前沿热点

15129
2188

2017-06-12

我们都知道,神经网络下围棋能赢柯洁、读X光照片好过医生、就连文本翻译上也快超过人类了……其实在写代码方面,神经网络也丝毫不落下风……用Linux源代码训练2小时,一个递归神经网络就能重写好它自己的代码,这是不是比程序员学得还快?


为了帮大家一窥究竟, AI100(rgznai100 )编译了AI开发者Thibault Neveu的这篇文章,手把手教你做一个这样的神经网络。


我认这很疯狂。开发者让神经网络学会了自己编程来重写它自己代码!好吧,咱们也试。


预备条件


1. Tensorflow + 基本的深度学习技能

2. 该项目的github代码库 - https://github.com/thibo73800/deep_generation/tree/master/c_code

3. 我会在本文中快速回顾一下递归神经网络。


我不会在本文中详解本项目的所有环节。但我会仔细阐述其中的基本要点来让你理解整个项目。花点时间,亲手运行下文中给出的每一段代码,理解其中的逻辑。这很重要,毕竟,实践出真知。


接下来是正题,让我们开始吧!


数据库


跟其他监督训练一样,我们需要为神经网络提供一个数据集。这里我们使用C语言(如果用太简单的语言,就不好玩了)。我们直接用Linux github代码库中的c语言脚本作为训练数据。我已经把我们会用到的.c代码提取到本项目中


首要问题:如何表示数据?


神经网络只能用于处理数字。对于其他形式的数据,它就无能为力了。因此,数据集中的每个字符都需要被翻译成这种形式(每个数字对应一个字符)。


640 (14).jpg

示例:把字符转换为整数(int)


举例来说,这里用数字7表示字符“=”。为了在反向传播期间获得更好的收敛性,我们稍后会在独热编码(One-Hot Encoding)编码中表示每个数字。


90.jpg


这里,需要记住的三个重要变量是:vocab_to_int、int_to_vocab和encoded。前两个变量是让我们能够字符和整数间随意转换。最后的变量是用编码器的形式来表示所有数据。(均已转换为数字)


第一个批函数


首先创建一个简单的批处理:由两个输入序列构成,每个序列10个数字。这一批处理将作为下文字符处理的一个示例。


97.jpg


这就是批函数所处理的内容,翻译成字符如下:


98.jpg


现在,我们需要来处理一些数值。我们希望神经网络能够在上一个字符"n"已知的条件下预测出下一个字符。而且,不只是上一个字符。如果我告诉神经网络上一个字符是“e” ,下一个字符的可能性空间会非常大。但如果我能告诉神经网络前几个字符分别是 “w” 、“h”、 “i” 、“l” 和 “e” ,下一个要输入的字符很显然就是“(“。


因此,我们必须构建一个能够考虑字符时间间隔的神经网络。这就是递归神经网络。


递归神经网络?


640 (15).jpg


为说明上述实例,我们用一个典型的分类器(上图左侧)来处理上一个字符;它被传递出蓝色的隐含层后,分类器就能推断出结果。递归神经网络在结构上则不同。每个红色的隐含层“细胞”不仅与输入相连,还与前一个“细胞”(instant t-1)相连。为了解决这里的问题,我们的“细胞”内部使用长短期记忆(LSTM)网络。


请花点时间来理解递归神经网络的原理,这样才能充分理解接下来的代码。


构建模型!


640 (16).jpg

Tensorboard图


接下来的内容,我们将详述这一神经网络的5大部分。占位符在这里用作模型的一个入口。LSTM神经元初始化后用于生成递归神经网络。


输出层各自相连,用于估量模型的误差。最后,我们会定义训练内容。


1)图形输入


96.jpg


这个批处理由两个大小为10的输入序列构成,因此输入的预期特征是[2, 10],批处理的每个入口都与单一输出相关联,目标的特征定义与此相同。最后,我们定义了一个用作概率值的占位符,用以表示后面的退出率(dropout)。


2)LSTM


95.jpg


让我们来学习这份代码的每一部分:


create_cell() 用于生成由4个隐神经元所构成的LSTM神经元。在返回结果前,该函数还在cell输出中添加了一个退出项(dropout)。


tf.contrib.rnn.MultiRNNCell用于实例化递归神经网络。我们把给出的create_cell()数组作为参数,是因为我们希望得到由多层网络构成的递归神经网络。本例为三层。


initial_state:已知递归神经网络的每个神经元都依赖于先前的状态,因此我们必须实例化一个全是零的初始状态,它将作为批处理首批入口的输入。


x_one_hot将batch转化为独热编码。


cell_outputs给出递归神经网络每个细胞的输出。在本例中,每个输出由4个数值(隐神经元个数)构成。


final_state返回最后一个细胞的状态,在训练期间可用作下一批处理的最新初始状态(假设下一个批处理是上一个批处理的逻辑延续)。


3)图形输出


94.jpg


细胞的输出值被储存在一个三维特征表内[序列数,序列大小,神经元数],或为 [2, 10, 4]。我们无需按序列来分离输出。然后,改变输出值的维度以储存在seq_out_reshape的数组[20, 4]内。


最后,使用一个简单的线性运算:tf.matmul (..) + b。最后以softmax结尾,为的是用概率形式来表示输出。


4)损失


93.jpg


为进行误差运算,我们的批处理目标必须要表示成跟模型输出值相同的方法和维度。使用与输入相同的编码方式,我们用tf.one_hot来表示输出值。然后将数组tf.reshape ()的维度重写为与tf.matmul (..) + b的线性输出一样。而后,我们就可以用该函数来计算模型的误差。


5)训练


92.jpg


我们简单用AdamOptimize来最小化误差。


结果!


这是最值得庆祝的环节:训练结果。我所用到的参数如下:


序列大小:100 

批处理大小:200 

每个细胞的神经元数: 512 

递归神经网络深度:2 

学习速度:0.0005 

Dropout:0.5


在我的GPU(GeForce GTX 1060)上训练大约两小时后,所得结果如下图所示:


我们先来观察误差的变化:


640 (17).jpg


最后,我们来阅读模型所生成的代码:


89.jpg


从结果上看,模型清楚地理解了该程序的一般结构,非常酷:一个函数、参数、变量初始化……条件,等等。


我们注意到,所用数据集中绝对没有那个名为“super_fold”的函数。因此,我很难理解这个函数的具体作用,一个较为合理的解释,是该模型要比我聪明……天哪!!


【本文来自投稿,文中观点不代表Xtecher立场。】

打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮

账号登录

重置密码

还没有账号?立即注册>

账号注册

已有账号?立即登录>注册企业会员

重置密码

返回

绑定手机