手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

栏目: 编程工具 · 发布时间: 7年前

内容简介:手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

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

接下来的文章,AI开发者Thibault Neveu就要手把手教你做一个这样的神经网络。

作者 |  Thibault Neveu

编译 | AI100

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

预备条件

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

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

  3. 我会在本文中快速回顾一下递归神经网络。但是,如果你对这个课题不甚了解,我相信以下两个资源能让你弄懂递归神经网络:

视频 –  https://www.youtube.com/watch?v=iX5V1WpxxkY&t=2652s

文章 –  http://colah.github.io/posts/2015-08-Understanding-LSTMs/

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

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

数据库

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

代码地址- https://github .com/thibo73800/deep_generation/tree/master/c_code/dataset

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

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

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

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

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

# List all file in the dataset directory

all_file = os.listdir(“dataset”)

# Filter : Select only c file

all_file_name = np.array([f for f in all_file if f.find(“.c”) != -1])

content = “”

for name in all_file_name:

with open(os.path.join(“dataset”, name), “r”) as f:

content += f.read() + “n”

# Convert the string into a list of interger

vocab = set(content)

vocab_to_int = {c: i for i, c in enumerate(vocab)}

int_to_vocab = dict(enumerate(vocab))

encoded = np.array([vocab_to_int[c] for c in content], dtype=np.int32)

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

第一个批函数

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

batch = {

“x” : [

encoded[:10],

encoded[20:30]

],

“y” : [

encoded[1:11],

encoded[21:31]

]

}

Batch Inputs : 

[20  6 58 27  6 27 97 86 56 49]

[ 36  32  32  37  27  12  94  60  89 101]

Batch Targets : 

[ 6 58 27  6 27 97 86 56 49 57]

[ 32  32  37  27  12  94  60  89 101  77]

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

['/', '*', 'n', ' ', '*', ' ', 'C', 'o', 'p', 'y']

['2', '0', '0', '4', ' ', 'E', 'v', 'g', 'e', 'n']

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

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

递归神经网络?

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

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

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

构建模型!

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

Tensorboard图

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

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

1)图形输入

with tf.name_scope(“graph_inputs”):

inputs = tf.placeholder(tf.int32, [2, 10], name='placeholder_inputs')

targets = tf.placeholder(tf.int32, [2, 10], name='placeholder_targets')

keep_prob = tf.placeholder(tf.float32, name='placeholder_keep_prob')

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

2)LSTM

with tf.name_scope(“LSTM”):

def create_cell():

lstm = tf.contrib.rnn.BasicLSTMCell(4)

drop = tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob)

return drop

cell = tf.contrib.rnn.MultiRNNCell([create_cell() for _ in range(3)])

initial_state = cell.zero_state(2, tf.float32)

io_size = len(vocab)

x_one_hot = tf.one_hot(inputs, io_size)

cell_outputs, final_state = tf.nn.dynamic_rnn(cell, x_one_hot, initial_state=initial_state)

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

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

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

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

  • x_one_hot将batch转化为独热编码。

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

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

3)图形输出

with tf.name_scope(“graph_outputs”):

seq_output_reshape = tf.reshape(cell_outputs, [-1, 4], name=”reshape_x”)

with tf.name_scope('output_layer'):

w = tf.Variable(tf.truncated_normal((4, io_size), stddev=0.1), name=”weights”)

b = tf.Variable(tf.zeros(io_size), name=”bias”)

logits = tf.add(tf.matmul(seq_output_reshape , w), b, name= “logits”)

softmax = tf.nn.softmax(logits, name='predictions')

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

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

4)损失

with tf.name_scope(“Loss”):

y_one_hot = tf.one_hot(targets, io_size, name=”y_to_one_hot”)

y_reshaped = tf.reshape(y_one_hot, logits.get_shape(), name=”reshape_one_hot”)

loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped)

loss = tf.reduce_mean(loss)

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

5)训练

with tf.name_scope(“train”):

adam = tf.train.AdamOptimizer(0.0001)

optimizer = adam.minimize(loss)

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

结果!

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

  • 序列大小:100 

  • 批处理大小:200 

  • 每个细胞的神经元数: 512 

  • 递归神经网络深度:2 

  • 学习速度:0.0005 

  • Dropout:0.5

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

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

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

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

static int super_fold(struct mddev *mddev, void __user * *rd)

{

struct md_rdev *rdev;

if (!tryet &  gcov_ntreef(*stint)) {

if (gc_th->max_sectors)

if (task)

goto next_start;

if (!list_empty(&mddev->disks) {

if (mddev->dev_sectors == 0 ||

mddev->chunk_sectors == 0 && mddev->minor_version !=

mddev->max_disks && mddev->dev_sectors

rdev2->rescan_recovnr != 0)

rdev->recovery_offset = mddev->curr_resync_completed;

}

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

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

原文地址:

https://becominghuman.ai/how-to-train-a-neural-network-to-code-by-itself-a432e8a120df

XGBboost已火热开课,已经参加过课程的同学反馈良好, 不过 还可以继续报名哦 ~~

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

AI100学院特请在机器学习领域深耕10余年的中科院副教授冒老师带来干货课程——《XGBoost从基础到实战》,从XGBoost的 原理 讲解到 代码实战 ,一步步带领大家从XGBoost的安装到一行行 Python 代码实现各类算法任务, 不需要有很强的数学基础,直接从实战入手 。通过4节XGBoost的专题课程,大家可以零基础理解XGBoost原理,掌握XGBoost调参,并能融会贯通地学习其他机器学习算法,学习如何用机器学习算法解决实际问题。如果你足够优秀,还能进击Kaggle竞赛哦。

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码

手把手教你自制编程AI:训练2小时,RNN就能写自己的代码    点击下方“阅读原文”查看更多内容。

[广告]赞助链接: 舆情监测,互联网舆情首选查舆情:http://www.chayuqing.com/ 四季很好,只要有你,文娱排行榜:http://www.yaopaiming.com/

关注公众号:Mcbang_com 了解更多精彩,关注:chayuqing_com 娱乐资讯早知道!


以上所述就是小编给大家介绍的《手把手教你自制编程AI:训练2小时,RNN就能写自己的代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ruby for Rails

Ruby for Rails

David Black / Manning Publications / 2006-05-11 / USD 44.95

What's Inside * How Ruby and Rails work, separately and together * Extensive Ruby language tutorial * Ruby techniques for Rails applications * Explore the Rails framework source code A new level of pr......一起来看看 《Ruby for Rails》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具