本篇文章7619字,读完约19分钟

雷锋。(公开号码:雷锋。艾科技评论出版社:何致远,这篇文章的作者,原文是在智湖专栏《艾洞察》,和雷锋。《科技评论》被授权出版。

上周写的文章“充分说明rnn,rnn变体,seq2seq,注意机制”介绍了rnn的几种结构,今天我们将讨论如何在张量流中实现这些结构。本文的主要内容如下:

一种在张量流中学习rnn实现的完整而逐步的方法。这条学习道路的曲线相对平缓,应该会减少很多学习能量,帮助人们少走弯路。

一些可能被踩的坑

张量流源代码分析

Char rnn实现示例,可以用来写诗,生成歌词,甚至可以用来写网络小说!(项目地址:github/hzy 46/char-rnn-tensorflow)

1.学习一步rnn:RNC如果你想在张量流中学习rnn,第一步应该是理解“RNC ell ”,它是在张量流中实现rnn的基本单位。每个rnncell都有一个call方法,其使用模式是:(output,next _ state) = call (input,state)。

TensorFlow中RNN实现的正确打开方式

借助图片可能更容易理解。假设我们有一个初始状态h0和输入x1。呼叫呼叫(x1,h0)后,我们可以得到(output1,h1):

amp;amp;lt;img src= amp;amp;quot;getimg.jrj/images/2017/09/leiphone/one_20170904144804133.jpg amp;amp;quot; data-rawwidth= amp;amp;quot;2856 amp;amp;quot; data-rawheight= amp;amp;quot;1110 amp;amp;quot; >

再调用一次call(x2, h1)就可以得到(output2, h2):amp。amp。lt。img src= amp。amp。quot。getig . jrj/images/2017/09/leiphone/one _ 20170904144804133 . jpg amp;amp。quot。数据-rawwidth= amp。amp。quot。2856安培。amp。quot。数据-rawheight= amp。amp。quot。1110安培。amp。quot。>再次调用(x2,h1)获取(output2,h2):

TensorFlow中RNN实现的正确打开方式

amp;amp;lt;img src= amp;amp;quot;static.leiphone/uploads/new/article/pic/201709/ded387b7b2fb9fbb097aa57e922c3516.jpg amp;amp;quot; data-rawwidth= amp;amp;quot;3320 amp;amp;quot; data-rawheight= amp;amp;quot;1110 amp;amp;quot; >

也就是说,每调用一次rnncell的call方法,就相当于在时间上“推进了一步”,这就是rnncell的基本功能。amp。amp。lt。img src= amp。amp。quot。static . leiphone/uploads/new/article/pic/201709/ded 387 b 7 B2 FB 9 FB 097 aa 57 e 922 c 3516 . jpg amp;amp。quot。数据-rawwidth= amp。amp。quot。3320安培。amp。quot。数据-rawheight= amp。amp。quot。1110安培。amp。quot。也就是说,rnncell的每一次调用都相当于时间上的一次前进,这是rnncell的基本功能。

TensorFlow中RNN实现的正确打开方式

在代码实现中,rnncell只是一个抽象类。当我们使用它的时候,我们使用了它的两个子类,basicrnncell和basiclstmcell。顾名思义,前者是rnn的基本类,后者是lstm的基本类。在这里,我们建议您阅读它的源代码实现(地址:t/rnjrfml)。你不需要一开始就全部读完,只要看一下rnncell、basicrnncell和basiclstmcell的注释部分,你就应该能够理解它们的功能。

TensorFlow中RNN实现的正确打开方式

除了调用方法,rnncell还有两个更重要的类属性:

state_size

输出大小

前者是隐藏层的大小,后者是输出的大小。例如,我们通常会将一批发送到模型中进行计算。如果输入数据的形状为(批处理大小,输入大小),则计算过程中获得的隐藏层状态为(批处理大小,状态大小),输出为(批处理大小,输出大小)。

TensorFlow中RNN实现的正确打开方式

您可以使用以下代码进行验证(请注意,以下代码基于最新版本的1.2 tensorflow):

将张量流作为tf导入

将numpy作为np导入

cell = TF . nn . rnn _ cell . basicrncell(num _ units = 128)# state _ size = 128

打印(cell.state_size)# 128

输入= TF。占位符。float32,shape = (32,100)) # 32是批量大小

H0 =细胞。零状态(32,NP。float32) #通过zero _ state获取全零的初始状态,其形状为(batch_size,state_size)

输出,h1 =单元。呼叫(输入,h0) #呼叫呼叫功能

打印(h1.shape)# (32,128)

对于基本单元,情况略有不同,因为lstm可以被视为具有两个隐藏状态h和c,并且对应的隐藏层是一个元组,每个元组的形状为(batch_size,state_size):

将张量流作为tf导入

将numpy作为np导入

lstm _ cell = TF . nn . rnn _ cell . basiclsmtcell(num _ units = 128)

输入= TF。占位符。float32,shape = (32,100)) # 32是批量大小

H0 = lstm _ cell。零状态(32,NP。float32) #通过zero _ state获取全零的初始状态

输出,h1 = lstm_cell.call(输入,h0)

打印(h1.h)# shape=(32,128)

打印(h1.c) # shape=(32,128)

其次,学习如何一次执行多个步骤:基于tf.nn.dynamic_rnn的rnncell有一个明显的问题:当我们使用它的调用函数来执行操作时,我们只是在时序上向前迈出了一步。例如,h1通过使用x1和h0获得,h2通过使用x2和h1获得。在这种情况下,如果我们的序列长度是10,那么调用函数10次是很麻烦的。张量流提供了一个tf.nn.dynamic_rnn函数,这相当于调用函数n次。也就是说,{h1,H2...,HN}直接通过{h0,x1,x2,...,xn}。

TensorFlow中RNN实现的正确打开方式

具体来说,让我们的输入数据的格式为(批处理大小、时间步长、输入大小),其中时间步长代表序列本身的长度。例如,在char rnn中,对应于长度为10的句子的时间步长等于10。最终输入大小表示单个时间维度中的单个输入数据序列的固有长度。另外,我们已经定义了一个RNC ell,并多次调用了这个RNC ell的调用函数time_steps,相应的代码是:

TensorFlow中RNN实现的正确打开方式

#输入:shape = (batch_size,time_steps,input_size)

# cell:RNC ell

# initial _ state:shape =(batch _ size,cell.state_size).初始状态。通常,可以采用零矩阵

输出,状态= tf.nn.dynamic_rnn(单元,输入,初始状态=初始状态)

此时,获得的输出是时间步长步骤中的所有输出。它的形状是(批量大小,时间步长,单元格。output _ size)。状态是最后一个隐藏的状态,它的形状是(批处理大小,单元格。状态大小)。

TensorFlow中RNN实现的正确打开方式

我建议您阅读tf.nn.dynamic_rnn的文档(地址:tensorflow/API _ docs/python/TF/nn/dynamic _ rnn)以进一步了解。

第三,学习如何堆叠网络单元:多层网络单元在很多情况下,单层网络单元的能力是有限的,所以我们需要多层网络单元。在将X输入到第一层rnn之后,获得隐藏层状态H,其等同于第二层rnn的输入,第二层rnn又等同于第三层rnn的输入,以此类推。在张量流中,可以使用TF . nn . rnn _ cell . multi rncel函数来堆叠rnncell,相应的示例程序如下:

TensorFlow中RNN实现的正确打开方式

将张量流作为tf导入

将numpy作为np导入

#每次调用此函数时,它都会返回一个basicrnncell

def get_a_cell():

返回TF . nn . rnn _ cell . basicrncell(num _ units = 128)

#用tf.nn.rnn_cell创建三层rnn

cell = TF . nn . rnn _ cell . multi rncel([get _ a _ cell()for _ in range(3)]# 3层rnn

#结果单元格实际上是rnncell的子类。

#它的state_size是(128,128,128)

# (128,128,128)并不意味着128x128x128

#表示有3个隐藏层状态,每个隐藏层状态的大小为128

打印(cell.state_size)# (128,128,128)

#使用相应的调用函数

输入= TF。占位符。float32,shape = (32,100)) # 32是批量大小

H0 =细胞。零状态(32,NP。float32) #通过zero _ state获取全零的初始状态

输出,h1 = cell.call(输入,h0)

打印(h1) #元组包含32x128的三个向量

multirnncell获得的细胞并不新鲜。它实际上是rnncell的一个子类,所以它也有call方法、state_size和output_size属性。您也可以通过tf.nn.dynamic_rnn一次运行多个步骤..

TensorFlow中RNN实现的正确打开方式

建议阅读mutirnncell源代码(地址:t/rnjrfml)中的注释,以了解更多关于其功能的信息。

第四,可能遇到的凹坑1:输出显示在经典的rnn结构中有这样一个图:

在上面的代码中,我们似乎有意忽略了在调用call或dynamic_rnn函数后输出的引入。将上图与张量流的基本单元进行比较。h对应于基本单元的状态大小。那么,y是否对应于基本单元格的输出大小?答案是否定的。

TensorFlow中RNN实现的正确打开方式

在源代码中找到basicrnncell的调用函数实现:

def调用(自身、输入、状态):

" " "最基本的rnn:output = new _ state = act(w * input+u * state+b)。"""

输出=自我。_激活(_线性([输入,状态],自。_num_units,true))

返回输出,输出

“返回输出,输出”这句话表明,在basicrnncell中,输出的值与隐藏状态的值相同。因此,我们需要为输出定义一个新的转换,以获得图中的实际输出y。输出和隐藏状态是一样的,所以state_size总是等于output_size。Tensorflow定义basicrnncell的目的是尽可能简洁,因此省略了输出参数。我们必须找出张量流和图中原始rnn定义之间的联系和区别。

TensorFlow中RNN实现的正确打开方式

让我们来看看basiclstmcell的调用函数定义(函数的最后几行):

新_c =(

c * sigmoid(f + self)。_遗忘_偏差)+ sigmoid(i) *自我。激活(_ j))

new_h = self。_激活(新_c) * sigmoid(o)

如果赛尔夫。_state_is_tuple:

new_state = lstmstatetuple(new_c,new_h)

否则:

new _ state = array _ ops . concat([new _ c,new_h],1)

返回new_h,new_state

我们只需要关注自我的情况。_state_is_tuple == true,因为self的情况。_state_is_tuple == false将在将来被丢弃。返回的隐藏状态是new_c和new_h的组合,输出是new_h。如果我们正在处理分类问题,我们需要给new_h添加一个单独的softmax层,以获得最终的分类概率输出。

TensorFlow中RNN实现的正确打开方式

我仍然建议您亲自查看源代码实现(地址:t/rnjsjoh)以了解细节。

V.可能遇到的凹坑2:版本导致的错误当我们前面谈到堆叠rnn时,使用的代码是:

#每次调用此函数时,它都会返回一个basicrnncell

def get_a_cell():

返回TF . nn . rnn _ cell . basicrncell(num _ units = 128)

#用tf.nn.rnn_cell创建三层rnn

cell = TF . nn . rnn _ cell . multi rncel([get _ a _ cell()for _ in range(3)]# 3层rnn

该代码可以在张量流1.2中正确使用。但是,在以前的版本(以及许多相关的在线教程)中,实现如下:

one _ cell = TF . nn . rnn _ cell . basicrncell(num _ units = 128)

cell = TF . nn . rnn _ cell . multi RNC all([one _ cell]* 3)# 3层rnn

如果在张量流1.2中以原来的方式定义,将会导致错误!

六.手训项目:上面的内容实际上是在张量流中实现rnn的基础知识。这时,我建议你用一个项目来练习和巩固。这里特别推荐Char rnn项目。这个项目对应于经典的rnn结构。上面刚刚提到了用来实现它的张量流函数。这个项目本身很有趣,可以用来生成文本。人们通常用它来写诗和歌词。

TensorFlow中RNN实现的正确打开方式

char rnn有很多实现,所以你可以自己在github上找到它。我也在这里做了一个实现供你参考。项目地址为hzy46/char-rnn-tensorflow(地址:git hub/hzy 46/char-rnn-tensorflow)。代码的部分实现来自安娜·卡列尼娜文本生成:使用张量流构建lstm模型

TensorFlow中RNN实现的正确打开方式

这篇专栏,多亏了@天宇的苏。

我主要是在代码中增加了嵌入层来支持中文,并重组了代码结构,将api改为最新的tensorflow 1.2版本。

您可以使用此项目来写诗(以下诗会自动生成):

不管是谁失踪了,这个地方就是它。

连夜去山坡,连夜返回江山。

山风春草色,秋水夜声深。

当你们见面时,你们应该认识老人。

什么时候不见面,在哪里看河。

一片树叶在云里生长,一个春风从竹厅里出来。

当有拜访时,它不在你心里。

您还可以生成代码:

静态int page _ CPU(struct flags * str)

{

int rc

结构rq * do _ init

};

/*

* core_trace_periods中的时间是所支持的时间,

*/

#endif

/*

* intendifint to state anded .

*/

int print_init(结构优先级*rt)

{ /*注释sighind if see task so和各节*/

控制台(字符串,

{}

此外,生成英语不是问题(使用莎士比亚的文本训练):

劳伦斯:

他的错误,你有她是

对她来说,我们会成为什么样的人

上帝和所有的犯规,还有,说,

我们在这里和我的和平共处。

palina:

为什么,你是呼吸还是呼吸,

我已经受够了他也不想要我了

我去野营。

最后,如果你的大脑足够大,你可以做一些更有趣的事情。例如,我用著名的在线小说《打破天空》训练了一个rnn模型,它可以生成以下文本:

闻言,郑晓燕立刻将目光转向了身旁的灰袍青年,然后目光在老者身上扫过,在那里,一个巨大的石凳上,有一个巨大的弹坑,一些黑色的光束,正从它的身上,一条巨大的黑色巨蟒,一股极度恐怖的气息,从空的天空中散发出来,然后,它有了让一些强壮的人窒息的感觉。在他们面前,这个身影就像一个黑影。在道路的眼睛里,在这片天地里,在巨大的空里,它蔓延开来...

TensorFlow中RNN实现的正确打开方式

“这是斗尊阶别,但是不管你,也不能出手,那些家伙,可以对这里下手,这里也可以有一些例外,而且他,也不能把别人的灵魂交给你,所以,这些东西,我也不能吞下这条强蟒,这一次,我们的力量,是能够杀死它的……”

TensorFlow中RNN实现的正确打开方式

“这里的人也可以和灵堂里的强者竞争。”

萧炎的眼中也掠过一丝惊恐,他立即笑了笑,立即喝了一口冷饮。他身后的主魂殿是萧炎,一具冰冷的饮料尸体,突然从空的天空中喷射而出,一股可怕的力量从空.的天空中溢出

TensorFlow中RNN实现的正确打开方式

“冷笑!”

这很有趣,我也试着创造日语等等。

第七,学习lstmcell的完整版本,它只说基本单元和基本单元的基本版本。张量流也有一个“全身”lstm:lstmcell。lstm的完整版本可以定义窥视孔,添加输出的投影层,为lstm的遗忘单位设置偏差等。你可以参考它的源代码(地址:github/tensorflow/tensorflow/blob/master/tensorflow/python/ops/RNN _ cell _ impl . py # l 417)来知道如何使用它。

TensorFlow中RNN实现的正确打开方式

八.了解最新的seq2seq apigoogle在tensorflow 1.2版中更新了seq 2 seq API(RC 1 . 3 . 0版已经发布,官方版本似乎即将发布,更新速度非常快)。我们可以使用这个api来定义seq2seq模型中的编码器和解码器,而无需手动操作。此外,它与数据集兼容,数据集是1.2版中的一种新的数据读取方法。你可以在这里阅读文档(地址:tensorflow/API _ docs/python/TF/contrib/seq2seq)来学习如何使用它。

TensorFlow中RNN实现的正确打开方式

九.总之,本文提供了一个学习tensorflow rnn实现的详细路径,包括学习顺序、可能的步骤、源代码分析和一个示例项目hzy46/char-rnn-tensorflow(地址:github/hzy 46/char-rnn-TensorFlow),希望对大家有所帮助。

TensorFlow中RNN实现的正确打开方式

雷锋文章版权所有。严禁擅自转载。详情请参考转载说明。

标题:TensorFlow中RNN实现的正确打开方式

地址:http://www.hcsbodzyz.com/hcxw/10312.html