Tensorflow与Keras中的RNN,tf.nn.动态折旧
我的问题是:和Tensorflow与Keras中的RNN,tf.nn.动态折旧,tensorflow,keras,tf.keras,Tensorflow,Keras,Tf.keras,我的问题是:和keras.layers.RNN(cell)是否与文档中所述的完全相同 我正在计划建立一个RNN,然而,它似乎是有利于Keras的 它特别指出: 警告:此函数已弃用。它将在将来被移除 版本更新说明:请使用keras.layers.RNN(单元格), 这相当于这个API 但我不知道在可变序列长度的情况下,API是如何等价的 在原始TF中,我们可以指定形状(批次大小,序列长度)的张量。这样,如果我们的序列是[0,1,2,3,4],并且批次中最长的序列的大小是10,我们可以用0和[0,1
keras.layers.RNN(cell)
是否与文档中所述的完全相同
我正在计划建立一个RNN,然而,它似乎是有利于Keras的
它特别指出:
警告:此函数已弃用。它将在将来被移除
版本更新说明:请使用keras.layers.RNN(单元格),
这相当于这个API
但我不知道在可变序列长度的情况下,API是如何等价的
在原始TF中,我们可以指定形状(批次大小,序列长度)
的张量。这样,如果我们的序列是[0,1,2,3,4]
,并且批次中最长的序列的大小是10,我们可以用0和[0,1,2,3,4,0,0,0,0,0,0,0,0]
,我们可以说seq_length=5
来处理[0,1,2,3,4]
然而,在Keras中,这不是它的工作方式!我们可以做的是,在以前的层(例如嵌入层)中指定mask_zero=True
。这也将掩盖第一个零
我可以通过向整个向量中添加一个来解决这个问题,但是在使用tft.compute\u词汇()
进行处理之后,我需要做额外的预处理,它将词汇映射到0索引向量。不,但是它们(或者可以被设置成)也没有太大的不同
TL;博士
tf.nn.dynamic\u rnn
将序列结束后的元素替换为0。据我所知,这不能用tf.keras.layers.*
复制,但你可以用RNN(掩蔽(…)
方法得到类似的行为:它只是停止计算并向前携带最后的输出和状态。你将得到与tf.nn.dynamic\u RNN
相同的(非填充)输出
实验
下面是一个简单的工作示例,演示了使用层和不使用层之间的差异
将numpy导入为np
导入tensorflow作为tf
测试_输入=np.array([
[1, 2, 1, 0, 0],
[0, 1, 2, 1, 0]
],dtype=int)
seq_length=tf.constant(np.array([3,4],dtype=int))
emb_权重=(np.one(shape=(3,2))*np.transpose([[0.37,1,2]]).astype(np.float32)
emb=tf.keras.layers.emb(
*emb_.shape,
权重=[emb_权重],
可训练=错误
)
掩模=tf.keras.layers.Masking(掩模_值=0.37)
rnn=tf.keras.layers.GRU(
1.
return_sequences=True,
激活=无,
反复激活=无,
kernel_初始值设定项='ones',
循环_初始值设定项='零',
使用_bias=True,
偏差\u初始值设定项='one'
)
def old_rnn(输入):
rnn_输出,rnn_状态=tf.nn.dynamic_(
rnn.cell,
投入,
dtype=tf.32,
序列长度=序列长度
)
返回rnn_输出
x=tf.keras.layers.Input(shape=test\u Input.shape[1:])
m0=tf.keras.Model(输入=x,输出=emb(x))
m1=tf.keras.Model(输入=x,输出=rnn(emb(x)))
m2=tf.keras.Model(输入=x,输出=rnn(掩码(emb(x)))
打印(m0.predict(test\u input.squence())
打印(m1.predict(test_输入).squence())
打印(m2.predict(test_input.squence())
sess=tf.keras.backend.get_session()
打印(sess.run(old_rnn(mask(emb(x))),feed_dict={x:test_input}).square())
m0
的输出显示应用嵌入层的结果。
请注意,根本没有零条目:
[[[1. 1. ] [[0.37 0.37]
[2. 2. ] [1. 1. ]
[1. 1. ] [2. 2. ]
[0.37 0.37] [1. 1. ]
[0.37 0.37]] [0.37 0.37]]]
下面是来自m1
、m2
和旧体系结构的实际输出:
m1: [[ -6. -50. -156. -272.7276 -475.83362]
[ -1.2876 -9.862801 -69.314 -213.94202 -373.54672 ]]
m2: [[ -6. -50. -156. -156. -156.]
[ 0. -6. -50. -156. -156.]]
old [[ -6. -50. -156. 0. 0.]
[ 0. -6. -50. -156. 0.]]
总结
- 旧的
tf.nn.dynamic\u rnn
用于用零屏蔽填充元素
- 没有屏蔽的新RNN层在填充元素上运行,就像它们是数据一样
- 新的
rnn(mask(…)
方法只是停止计算并向前携带最后的输出和状态。请注意,我为此方法获得的(非填充)输出与tf.nn.dynamic\u rnn
中的输出完全相同
无论如何,我不能涵盖所有可能的边缘情况,但我希望您可以使用此脚本进一步解决问题。您是在谈论keras
还是tf.keras
?我想问,您是否应该真正关心这一点(即前面的seq_长度
).从文档中…所以这更多是为了性能而不是正确性。@MPękalski我使用tf。keras@rst我实际上不理解正确性的问题。如果我输入0,矩阵乘法也将是0,但随后我将添加一个1偏差,该偏差通过一个激活函数与其权重一起传递。我很可能会得到一个非零输出由于偏差项。因此偏差权重将继续训练?或者我的理解不正确吗?@rst假设它们的意思是将剩余的“填充”0传递到RNN或屏蔽它们之间没有区别,例如不在它们上训练。我对此进行了扩展,以显示没有嵌入层的屏蔽。回答很好,这对我帮助很大。今晚我有了一个有趣的发现——如果将GRU单元封装在一个双向层中,它会将携带的输出转换为零,从而获得与旧实现相同的输出,而无需预定义序列长度。