王小新 编译自 KDnuggets 量子位 出品 | 公众号 QbitAI 本文作者Erik Hallström是一名深度学习研究工程师,他的这份教程以Echo-RNN为例,介绍了如何在TensorFlow环境中构建一个简单的循环神经网络。 什么是RNN? RNN是循环神经网络(Recurrent Neural Network)的英文缩写,它能结合数据点之间的特定顺序和幅值大小等多个特征,来处理序列数据。更重要的是,这种网络的输入序列可以是任意长度的。 举一个简单的例子:数字时间序列,具体任务是根据先前值来预测后续值。在每个时间步中,循环神经网络的输入是当前值,以及一个表征该网络在之前的时间步中已经获得信息的状态向量。该状态向量是RNN网络的编码记忆单元,在训练网络之前初始化为零向量。
图1:RNN处理序列数据的步骤示意图。 本文只对RNN做简要介绍,主要专注于实践:如何构建RNN网络。如果有网络结构相关的疑惑,建议多看看说明性文章。 关于RNN的介绍,强烈推荐《A Critical Review of Recurrent Neural Networks for Sequence Learning》,这篇出自加州大学圣地亚哥分校研究人员的文章介绍了几乎所有最新最全面的循环神经网络。(地址:https://arxiv.org/pdf/1506.00019.pdf) 在了解RNN网络的基本知识后,就很容易理解以下内容。 构建网络 我们先建立一个简单的回声状态网络(Echo-RNN)。这种网络能记忆输入数据信息,在若干时间步后将其回传。我们先设定若干个网络常数,读完文章你就能明白它们的作用。 from__future__ importprint_function, division importnumpy asnp importtensorflow astf importmatplotlib.pyplot aspltnum_epochs = 100total_series_length = 50000truncated_backprop_length = 15state_size = 4num_classes = 2echo_step = 3batch_size = 5num_batches = total_series_length//batch_size//truncated_backprop_length 生成数据 现在生成随机的训练数据,输入为一个随机的二元向量,在echo_step个时间步后,可得到输入的“回声”,即输出。 defgenerateData():x = np.array(np.random.choice( 2, total_series_length, p=[ 0.5, 0.5])) y = np.roll(x, echo_step) y[ 0:echo_step] = 0x = x.reshape((batch_size, - 1)) # The first index changing slowest, subseries as rowsy = y.reshape((batch_size, - 1)) return(x, y) 包含batch_size的两行代码,将数据重构为新矩阵。神经网络的训练,需要利用小批次数据(mini-batch),来近似得到关于神经元权重的损失函数梯度。在训练过程中,随机批次操作能防止过拟合和降低硬件压力。整个数据集通过数据重构转化为一个矩阵,并将其分解为多个小批次数据。
图2:重构数据矩阵的示意图,箭头曲线指示了在不同行上的相邻时间步。浅灰色矩形代表“0”,深灰色矩形代表“1”。 构建计算图 首先在TensorFlow中建立一个计算图,指定将要执行的运算。该计算图的输入和输出通常是多维数组,也被称为张量(tensor)。我们可以利用CPU、GPU和远程服务器的计算资源,在会话中迭代执行该计算图。 变量和占位符 本文所用的基本TensorFlow数据结构是变量和占位符。占位符是计算图的“起始节点”。在运行每个计算图时,批处理数据被传递到占位符中。另外,RNN状态向量也是存储在占位符中,在每一次运行后更新输出。 batchX_placeholder = tf.placeholder(tf.float32, [batch_size, truncated_backprop_length])batchY_placeholder = tf.placeholder(tf.int32, [batch_size, truncated_backprop_length])init_state = tf.placeholder(tf.float32, [batch_size, state_size]) 网络的权重和偏差作为TensorFlow的变量,在运行时保持不变,并在输入批数据后进行逐步更新。 W = tf.Variable(np.random.rand(state_size+ 1, state_size), dtype=tf.float32)b = tf.Variable(np.zeros(( 1,state_size)), dtype=tf.float32)W2 = tf.Variable(np.random.rand(state_size, num_classes),dtype=tf.float32)b2 = tf.Variable(np.zeros(( 1,num_classes)), dtype=tf.float32) 下图表示了输入数据矩阵,以及虚线窗口指出了占位符的当前位置。在每次运行时,这个“批处理窗口”根据箭头指示方向,以定义好的长度从左边滑到右边。在示意图中,batch_size(批数据数量)为3,truncated_backprop_length(截断反传长度)为3,total_series_length(全局长度)为36。这些参数是用来示意的,与实际代码中定义的值不一样。在示意图中序列各点也以数字标出。
图3:训练数据的示意图,用虚线矩形指示当前批数据,用数字标明了序列顺序。 拆分序列 现在开始构建RNN计算图的下个部分,首先我们要以相邻的时间步分割批数据。 # Unpack columnsinputs_series = tf.unpack(batchX_placeholder, axis= 1)labels_series = tf.unpack(batchY_placeholder, axis= 1)view raw (责任编辑:本港台直播) |