史无前例的RNN讲解
这篇博客不是一篇讲解原理的博客,这篇博客主要讲解time_steps,如果这篇博客没有让你明白time_steps,那么算我无能。
我曾翻阅各大网站,各大博客,他们的对RNN中time_steps的讲解,都没有一个让人醍醐灌顶的答案,甚至让人越看模糊。有的博主在博客中讲的看似他懂了,一问他自己他答不上来。在这里,我向全中国还迷糊在time_step的学者答疑,立此博文。
RNNCell
想要看懂tensorflow RNN代码,我们必须要先了解RNNCell,RNNcell 是 tensorlfow中实现RNN的基本单元。我们平时在代码中用的是RNNcell的子类,BasicRNNCell(RNN的基础类)和BasicLSTMCell(LSTM的基础类)。为了方便,我用cell对这两个类进行统称。
使用方式是:(output, next_state) = call(input, state)
理解例子:输入序列是:$x_1、x_2、x_3$,RNN的初始状态为$h_0$
t=1时刻,$(output_1, h_1) = cell(x_1,h_0)$
t=2时刻,$(output_2, h_2) = cell(x_2,h_1)$
t=3时刻,$(output_3, h_3) = cell(x_3,h_2)$
每调用一次RNNCell的call方法,就相当于在时间上推进了一步。
RNNCell中还有两个输出比较重要,state_size(隐层的大小),output_size(输出的大小)。
设输入数据的形状为(batch_size, input_size),那么计算时得到的隐层状态就是(batch_size, state_size),输出就是(batch_size, output_size)。
import tensorflow as tf cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128 # cell = tf.keras.layers.SimpleRNNCell(units=128) # 32 是 batch_size inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 通过zero_state得到一个全0的初始状态,形状为(batch_size, state_size) h0 = cell.zero_state(32, tf.float32) # (32, 128) # 调用call函数 output, h1 = cell.__call__(inputs, h0) print(h1.shape) # (32, 128)
对于BasicLSTMCell,因为LSTM可以看做有两个隐状态h和c,对应的隐层就是一个Tuple,每个都是(batch_size, state_size)的形状:
import tensorflow as tf lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128) inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 32 是 batch_size h0 = lstm_cell.zero_state(32, tf.float32) # (32,128) output, h1 = lstm_cell.__call__(inputs, h0) print(h1.h.shape) # shape=(32, 128) print(h1.c.shape) # shape=(32, 128)
tf.nn.static_rnn
tf.nn.static_rnn——随时间静态展开。static_rnn() 返回两个对象,第一个是每一时刻time_steps RNN输出的列表,另一个是RNN网络的最终状态state。下面代码举例time_steps=2的输入。
X0 = tf.placeholder(tf.float32, [None, n_inputs]) X1 = tf.placeholder(tf.float32, [None, n_inputs]) basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) output_seqs, states = tf.contrib.rnn.static_rnn(basic_cell, [X0, X1], dtype=tf.float32) Y0, Y1 = output_seqs
如果有50个tiime_steps时刻,操作50个输入占位符实在太繁琐了,假如输入shape=(None, time_steps, imput_size),可以用如下方法一并输入
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) X = tf.transpose(X, perm=[1, 0, 2]) # shape=(n_steps, batchs ,n_inputs) X_seqs = tf.unstack(X) # time_steps个(batchs, n_inputs)的列表 basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) output_seqs, states = tf.contrib.rnn.static_rnn(basic_cell, X_seqs, dtype=tf.float32) outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2])
最终的outputs是一个包含所有实例、任一时刻、所有神经元的输出的张量。幸运的是,还有更好的解决方案,那就是dynamic_rnn()函数。
tf.nn.dynamic_rnn
tf.nn.dynamic_rnn——随时间动态展开。基础的RNNCell有一个很明显的问题:对于单个的RNNCell,我们使用它的call函数进行运算时,只是在序列时间上前进了一步。如果我们的序列长度为10,就要调用10次call函数,比较麻烦。对此,TensorFlow提供了一个tf.nn.dynamic_rnn函数,该函数就相当于调用了n(输入数据的格式为(batch_size, time_steps, input_size),其中time_steps表示序列本身的长度,如在Char RNN中,长度为10的句子对应的time_steps就等于10。最后的input_size就表示输入数据单个序列单个时间维度上固有的长度。另外我们已经定义好了一个RNNCell,调用该RNNCell的call函数time_steps次,对应的代码就是:)次call函数。即通过${h_0,x_1, x_2, …., x_n}$直接得${h_1,h_2…,h_n}$。
举个例子:假设输入数据的格式为(batch_size, time_steps, input_size),其中time_steps表示序列本身的长度,如在NLP中,一句话有25个字,每个字的向量维度为300,那么time_steps就是句子的长度=25,input_size=300。另外我们已经定义好了一个RNNCell,调用该RNNCell的call函数time_steps次,对应的代码就是:
outputs, state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state)
参数:
inputs: 输入序列 shape = (batch_size, time_steps, input_size)
cell: RNNCell
initial_state: 初始状态。一般可以取零矩阵shape = (batch_size, cell.state_size)。
返回:
- outputs:time_steps步里所有输出,shape=(batch_size, time_steps, cell.output_size)
- state:最后一步的隐状态,它的形状为(batch_size, cell.state_size)
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) # (batch_size, time_steps,input_size) basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
变长输入序列
前面我们处理的输入shape=(batch_size, time_step, input_size),输入序列是定长的,拿我们做自然一样处理为例子,如果数据有1000段时序的句子,每句话有25个字,对每个字进行向量化,每个字的向量维度为300,那么batch_size=1000,time_steps=25,input_size=300。但是每句话的句子长度都是不一样的,这时候我们就需要在调用dynamic_rnn()(或者static_rnn)时使用sequence_length参数。指明了每一实例输入序列的长度。例如:
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) # (batch_size, time_steps,input_size) seq_length = tf.placeholder(tf.int32, [None]) basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, sequence_length=seq_length, dtype=tf.float32)
假设我们输入的第二个实例只有一个时刻的输入,表示该实例张量的第二维需要补零,如下所示:
X_batch = np.array([ # step 0 step 1 [[0, 1, 2], [9, 8, 7]], # instance 0 [[3, 4, 5], [0, 0, 0]], # instance 1 (padded with a zero vector) [[6, 7, 8], [6, 5, 4]], # instance 2 [[9, 0, 1], [3, 2, 1]], # instance 3 ]) seq_length_batch = np.array([2, 1, 2, 2]) with tf.Session() as sess: init.run() outputs_val, states_val = sess.run([outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
tf.nn.rnn_cell.MultiRNNCell
单层RNN能力有限,我们需要多层的RNN。将x输入第一层RNN的后得到隐层状态h,这个隐层状态就相当于第二层RNN的输入,第二层RNN的隐层状态又相当于第三层RNN的输入,以此类推。在TensorFlow中,可以使用tf.nn.rnn_cell.MultiRNNCell函数对RNNCell进行堆叠
import tensorflow as tf # 每调用一次这个函数就返回一个BasicRNNCell def get_a_cell(): return tf.nn.rnn_cell.BasicRNNCell(num_units=128) # 用tf.nn.rnn_cell MultiRNNCell创建3层RNN cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 3层RNN # 得到的cell实际也是RNNCell的子类 # 它的state_size是(128, 128, 128) # (128, 128, 128)并不是128x128x128的意思 # 而是表示共有3个隐层状态,每个隐层状态的大小为128 print(cell.state_size) # (128, 128, 128) # 使用对应的call函数 inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 32 是 batch_size h0 = cell.zero_state(32, tf.float32) # 通过zero_state得到一个全0的初始状态 output, h1 = cell.__call__(inputs, h0) print(h1) # tuple中含有3个32x128的向量 # (<tf.Tensor 'multi_rnn_cell/cell_0/basic_rnn_cell/Tanh:0' shape=(32, 128) dtype=float32>, # <tf.Tensor 'multi_rnn_cell/cell_1/basic_rnn_cell/Tanh:0' shape=(32, 128) dtype=float32>, # <tf.Tensor 'multi_rnn_cell/cell_2/basic_rnn_cell/Tanh:0' shape=(32, 128) dtype=float32>)
RNN的其他变种
### ------------ LSTM ------------- ### lstm_cell = tf.contrib.rnn.BasicLSTMCell(num_units=n_neurons) # peephole connections # 让长期记忆也参与控制门的管理可能会更好 lstm_cell = tf.contrib.rnn.LSTMCell(num_units=n_neurons, use_peepholes=True) ### ------------ GRU ------------- ### gru_cell = tf.contrib.rnn.GRUCell(num_units=n_neurons)
time_steps专栏
有的人学习到RNN的时候,死活都弄不清batch、input_size、time_steps。在这篇博文中,我做一个专栏。
文字数据
如果数据有1000段时序的句子,每句话有25个字,对每个字进行向量化,每个字的向量维度为300,那么batch_size=1000,time_steps=25,input_size=300。
解析:time_steps一般情况下就是等于句子的长度,input_size等于字量化后向量的长度。
图片数据
拿MNIST手写数字集来说,训练数据有6000个手写数字图像,每个数字图像大小为28*28,batch_size=6000没的说,time_steps=28,input_size=28,我们可以理解为把图片图片分成28份,每份shape=(1, 28)。
音频数据
如果是单通道音频数据,那么音频数据是一维的,假如shape=(8910,)。使用RNN的数据必须是二维的,这样加上batch_size,数据就是三维的,第一维是batch_size,第二维是time_steps,第三位是数据input_size。我们可以把数据reshape成三维数据。这样就能使用RNN了。
参考文献
知乎-何之源:TensorFlow中RNN实现的正确打开方式
史无前例的RNN讲解的更多相关文章
- 使用Keras进行深度学习:(五)RNN和双向RNN讲解及实践
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 笔者:Ray 介绍 通过对前面文章的学习,对深度神经网络(DNN) ...
- JAVA MemCache 史无前例的详细讲解【转】
非原创转自:http://nhy520.iteye.com/blog/1775893 这篇文章是我看到的介绍的比较详细的,入门级别算是足足够了 Memcach什么是Memcache Memcache集 ...
- 使用Keras搭建cnn+rnn, BRNN,DRNN等模型
Keras api 提前知道: BatchNormalization, 用来加快每次迭代中的训练速度 Normalize the activations of the previous layer a ...
- 使用Keras进行深度学习:(七)GRU讲解及实践
####欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 介绍 GRU(Gated Recurrent Unit) ...
- 【深度学习篇】---CNN和RNN结合与对比,实例讲解
一.前述 CNN和RNN几乎占据着深度学习的半壁江山,所以本文将着重讲解CNN+RNN的各种组合方式,以及CNN和RNN的对比. 二.CNN与RNN对比 1.CNN卷积神经网络与RNN递归神经网络直观 ...
- RNN(2) ------ “《A Critical Review of Recurrent Neural Networks for Sequence Learning》RNN综述性论文讲解”(转载)
原文链接:http://blog.csdn.net/xizero00/article/details/51225065 一.论文所解决的问题 现有的关于RNN这一类网络的综述太少了,并且论文之间的符号 ...
- RNN、LSTM介绍以及梯度消失问题讲解
写在最前面,感谢这两篇文章,基本上的框架是从这两篇文章中得到的: https://zhuanlan.zhihu.com/p/28687529 https://zhuanlan.zhihu.com/p/ ...
- lecture7-序列模型及递归神经网络RNN
Hinton 第七课 .这里先说下RNN有recurrent neural network 和 recursive neural network两种,是不一样的,前者指的是一种人工神经网络,后者指的是 ...
- 循环神经网络(RNN, Recurrent Neural Networks)介绍(转载)
循环神经网络(RNN, Recurrent Neural Networks)介绍 这篇文章很多内容是参考:http://www.wildml.com/2015/09/recurrent-neur ...
随机推荐
- 28岁,转行学 IT 靠谱吗?
前几天在知乎上,刷到这么一个问题 鉴于有不少人看了我的blog给我私信一些职业规划相关的问题,讨论很多的就是担心自己年龄是否还适合转行. 于是决定静心下来码了一篇回答, 同时搬到博客园来供大家消遣.. ...
- 容易上手搭建vue2.0开发环境
第一步:安装node 前端开发框架和环境都是需要 Node.js ,先安装node.js开发环境,vue的运行是要依赖于node的npm的管理工具来实现,下载https://nodejs.org/en ...
- 100天搞定机器学习|Day 30-32 微积分的本质
3blue1brown系列课程,精美的动画,配上生动的讲解,非常适合帮助建立数学的形象思维,非常值得反复观看: http://www.3blue1brown.com/ 哔哩哔哩: https://sp ...
- 2.php语言基础
HP简介 PHP超文本预处理器.是嵌入HTML文件中的服务器端脚本程序.换句话:PHP只能运行在服务器上. 一个HTML文件中,可以包含的代码:HTML代码.CSS代码.JS代码.PHP代码等. PH ...
- Powered by .NET Core 进展0819:高速开车车况汇报
继续以流水账的方式向大家汇报,自从上周六上午将 .net core 版博客站点从 windows 部署切换到 linux 上的 docker-compose 部署后,到目前一直在线. Linux 上没 ...
- github的详细使用,非常简单!
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/
- Ribbon实现客户端负载均衡
什么是Ribbon? 客户端负载均衡组件. 前期准备: 搭建一个Eureka集群和一个注册服务 https://www.cnblogs.com/noneplus/p/11374883.html 创建服 ...
- unity shader 纹理&透明效果
1.纹理映射基础 (1)纹理映射通过(u,v)坐标实现.注意:这句话时博主当时面试一家外企被问到的问题. (2)添加纹理属性:——MainTex("Main Tex",2D)=&q ...
- 信道估计系列之LS
在无线通信系统中,系统的性能主要受到无线信道的制约.基站和接收机之间的传播路径复杂多变,从简单的视距传输到受障碍物反射.折射.散射影响的传播.在无线传输环境中,接收信号会存在多径时延,时间选择性衰落和 ...
- Vue+webpack项目的多环境打包配置
背景:由于需要将应用部署到线上开发环境.线上测试环境.线上预发环境.线上生产环境,而每个环境的访问地址是不同的.如果每次更改请求地址未免有些繁琐,就考虑在本地进行一次性配置. 代码管理工具:git 代 ...