TensorFlow中实现RNN,彻底弄懂time_step
这篇博客不是一篇讲解原理的博客,这篇博客主要讲解tnesorlfow的RNN代码结构,通过代码来学习RNN,以及讲解time_steps,如果这篇博客没有让你明白time_steps,欢迎博客下面评论交流。
我曾翻阅各大网站,各大博客,他们的对RNN中time_steps的讲解,都没有一个让人醍醐灌顶的答案,甚至让人越看模糊。有的博主在博客中讲的看似他懂了,一问他自己他答不上来。在这里,我向全中国还迷糊在time_step的学者答疑,立此博文。
学习RNNCell要重点关注三个地方:
- 类方法 call
- 类属性 state_size
- 类属性 output_size
RNN_Cell
想要看懂tensorflow RNN代码,我们必须要先了解RNNCell,RNNcell 是 tensorlfow中实现RNN的基本单元。我们平时在代码中用的是RNNcell的子类,BasicRNNCell(RNN的基础类)和BasicLSTMCell(LSTM的基础类)。
注意:RNNCell是抽象类不能进行实例化,可以使用它的子类BasicRNNCell或BasicLSTMCell进行实例化,得到cell。
所有的RNNCell的之类都会实现一个__call__函数,利用call函数可以实现RNN的单步计算
使用方式是:(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(输出的大小)。output_size一般等于最后一层RNN的state_size。
举例:设输入数据的形状为(batch_size, input_size),那么计算时得到的隐层状态就是(batch_size, state_size),输出就是(batch_size, output_size)=(batch_size, 最后一层state_size)。
BaseRNNCell
在TensorFlow中定义一个基本RNN单元:
import tensorflow as tf rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128
# cell = tf.keras.layers.SimpleRNNCell(units=128)
print(rnn_cell.state_size) # # 32 是 batch_size
inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 通过zero_state得到一个全0的初始状态,形状为(batch_size, state_size)
h0 = rnn_cell.zero_state(32, tf.float32) # h0.shape=(32, 128) # 调用call函数
output, h1 = rnn_cell.__call__(inputs, h0) print(output.shape) # (32, 128)
print(h1.shape) # (32, 128)
注意:隐藏层的初始化cell.zero_state(batch),shape=(batch_size,state_size)
BaseLSTMCell
在TensorFlow中定义一个基本LSTM单元:
import tensorflow as tf lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128)
print(lstm_cell.state_size) # LSTMStateTuple(c=128, h=128) inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 32 是 batch_size
h0 = lstm_cell.zero_state(32, tf.float32) # (32,128) # 调用call函数
output, h1 = lstm_cell.__call__(inputs, h0) print(output.shape) # shape=(32, 128)
print(h1.h.shape) # shape=(32, 128)
print(h1.c.shape) # shape=(32, 128)
对于BasicLSTMCell,因为LSTM可以看做有两个隐状态h和c,对应的隐层就是一个Tuple,每个都是(batch_size, state_size)的形状
时间维度静态展开: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()函数。
时间维度动态展开:dynamic_rnn
tf.nn.dynamic_rnn——随时间动态展开。基础的RNNCell有一个很明显的问题:对于单个的RNNCell,我们使用它的call函数进行运算时,只是在序列时间上前进了一步。如果我们的序列长度为10,就要调用10次call函数,比较麻烦。对此,TensorFlow提供了一个tf.nn.dynamic_rnn函数,该函数就相当于调用了n次call函数,即通过${h_0,x_1, x_2, …., x_n}$直接得${h_1,h_2…,h_n}$。
具体来说,设输入数据的格式为 (batch_size, time_steps, input_size),
- batch_size:表示batch的大小,即一个batch中序列的个数,
- time_steps:表示序列本身的长度,如在Char RNN中,长度为10的句子对应的time_steps就等于10。
- input_size:表示输入数据单个序列单个时间维度上固有的长度。
举例:假设输入数据的格式为(batch_size, time_steps, input_size),其中time_steps表示序列本身的长度,如在NLP中,一句话有25个字,每个字的向量维度为300,那么time_steps就是句子的长度=25,input_size=300。
假设我们已经定义好了一个RNNCell,调用time_steps该RNNCell的call函数次,对应的代码是:
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)
import tensorflow as tf rnn_cell = tf.contrib.rnn.BasicRNNCell(num_units=128) # states_size=128
X = tf.placeholder(tf.float32, [32, 10, 100]) # input_shape=(batch_size, time_steps,input_size) outputs, states = tf.nn.dynamic_rnn(rnn_cell, X, dtype=tf.float32) print(outputs.shape) # (batch_size,time_size, cell.output_size)=(32, 10, 128)
print(states.shape) # (batch_size, output_size)=(batch_size, states_size)=(32, 128)
变长输入序列
前面我们处理的输入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})
堆叠RNN: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
Multi_cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 3层RNN
# 得到的cell实际也是RNNCell的子类,它的state_size是(128, 128, 128),
# 这里并不是128x128x128的意思,而是表示共有3个隐层状态,每个隐层状态的大小为128
print(Multi_cell.state_size) # (128, 128, 128)
# 使用对应的call函数
inputs = tf.placeholder(tf.float32, shape=(32, 100)) # 32 是 batch_size
h0 = Multi_cell.zero_state(32, tf.float32) # 通过zero_state得到一个全0的初始状态
output, h1 = Multi_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)。
音频数据
假如训练数据有225段语音,每段语音对其进行分帧处理,每段语音有480帧,每一帧数据shape=(8910,),则输入shape=(225, 480 8910),batch_size=225,time_steps就是,每段语音的帧数,time_steps=480,input_size=8910
我们使用RNN永远只需要记住,输入数据一定要是时序的,不能用这一段语音的语音帧,接下一段语音的语音帧,因为这两段语音之间没有时域连续性。
RNN数据一定要是三维的,第一维是batch_size,第二维是time_steps,第三位是数据input_size。
参考文献
知乎-何之源:TensorFlow中RNN实现的正确打开方式
TensorFlow中实现RNN,彻底弄懂time_step的更多相关文章
- 在TensorFlow中基于lstm构建分词系统笔记
在TensorFlow中基于lstm构建分词系统笔记(一) https://www.jianshu.com/p/ccb805b9f014 前言 我打算基于lstm构建一个分词系统,通过这个例子来学习下 ...
- 【TensorFlow】一文弄懂CNN中的padding参数
在深度学习的图像识别领域中,我们经常使用卷积神经网络CNN来对图像进行特征提取,当我们使用TensorFlow搭建自己的CNN时,一般会使用TensorFlow中的卷积函数和池化函数来对图像进行卷积和 ...
- 彻底弄懂AngularJS中的transclusion
点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...
- 第二十二节,TensorFlow中RNN实现一些其它知识补充
一 初始化RNN 上一节中介绍了 通过cell类构建RNN的函数,其中有一个参数initial_state,即cell初始状态参数,TensorFlow中封装了对其初始化的方法. 1.初始化为0 对于 ...
- 一文弄懂神经网络中的反向传播法——BackPropagation【转】
本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法——BackPropagation 最近在看深度学习 ...
- 【转】彻底弄懂Java中的equals()方法以及与"=="的区别
彻底弄懂Java中的equals()方法以及与"=="的区别 一.问题描述:今天在用Java实现需求的时候,发现equals()和“==”的功能傻傻分不清,导致结果产生巨大的偏差. ...
- python中self与__init__怎么解释能让小白弄懂?
python中self与__init__怎么解释能让小白弄懂? 这个问题其实没那么简单. 只说一下自己的理解. python 里所有的 object 都有三个属性, 标识(identity), 类型( ...
- TensorFlow中的通信机制——Rendezvous(二)gRPC传输
背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 本篇是TensorFlow通信机制系列的第二篇文章,主要梳理使用gRPC网络传 ...
- 彻底弄懂LSH之simHash算法
马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说.这种说法同样适用于“经典”的计算机书籍. 最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂.最近看的 ...
随机推荐
- Geoserver发布服务
Geoserver发布服务的数据源很多样化 在数据存储中选择要发布的数据来源,这里以POSTGIS为例 1. 2.如果成功,就会读取出库里面的表,你可以在这里添加图层,发布服务 3.点击发布,进行服务 ...
- Python输出16进制不带0x补零,整数转16进制,字符串转16进制
Python输出16进制不带0x补零,整数转16进制,字符串转16进制 在开发中,我们偶尔会遇到需要将数据通过控制台打印出来,以检查数据传输的准确性.例如调试服务端刚接到的二进制数据(里面包含很多 ...
- Harbor 清理镜像(此方法比较粗暴,但是有效)
0x00 事件 Harbor 私有仓库中占有的存储慢慢越来越大,使用官方的清理工具以及 UI 上的垃圾清理,都似乎也不能清理掉-- 后来吾用了一种简单粗暴的方法清理镜像--删除 harbor regi ...
- sql语句中给列参数取别名及相关注意事项
1.使用双引号 select count(*) "总数" from table: 2.使用单引号 select count(*) '总数' from table: 3.直接加别名, ...
- Cocos2d-x.3.0开发环境搭建之—— 极简式环境搭建
配置:win7 + VS2012 + Cocos2d-x.3.0 + Cocos Studio v1.4.0.1 使用此法可以方便的创建Cocos2d-x项目.如果需要运行Cocos2d-x引擎自带的 ...
- Cocos2d-x 3.2 的内存管理详解
目标读者:了解 Cocos2d-x 中的节点以及节点树,了解引用计数,了解游戏主循环等概念. 本文首先介绍 Cocos2d-x 3.2 中内存管理的作用,以及各个作用的应用.借由通俗易懂的解释来了解内 ...
- 开发一个这样的 APP 要多长时间?
作者:蒋国刚 www.cnblogs.com/guogangj/p/4676836.html 这是一个“如有雷同,纯属巧合”的故事,外加一些废话,大家请勿对号入座.开始了…… 我有些尴尬地拿着水杯,正 ...
- [考试反思]1114csp-s模拟测试115:零迟
最后一次了,允许自己混进榜里吧. 没有心态,原题不会做(真的忘了) T2的搜索没有分. 「 零 · 迟 」:酷刑 只有在最后的时刻才开始意识到,一切的一切都已经晚了. 就在眼前了.没有机会了. 退役, ...
- IT兄弟连 HTML5教程 HTML5的基本语法 小结及习题
小结 一个完整的HTML文件由标题.段落.列表.表格.文本,即嵌入的各种对象所组成,这些逻辑上统一的对象称为元素.HTML文档主体结构分为两部分,一部分是定义文档类型,另一部分则是定义文档主体的结构框 ...
- 案例:使用dbms_xplan.display_cursor无法获取执行计划
案例:使用dbms_xplan.display_cursor无法获取执行计划 环境:RHEL 6.5 + Oracle 11.2.0.4 在一次测试中发现使用dbms_xplan.display_cu ...