【问题标题】:Keras/Tensorflow Input to RNN layersKeras/Tensorflow 输入到 RNN 层
【发布时间】:2019-07-31 15:58:53
【问题描述】:

我正在尝试在 Keras 中构建一个 RNN。我不太了解所需的输入格式。我可以构建密集网络没问题,但我认为 RNN 层期望输入维度 x 批次 x 时间步长?任何人都可以验证这一点吗?

这是我要更新的代码:

原码:

def get_generative(G_in, dense_dim=200, out_dim=50, lr=1e-3):
   x = Dense(dense_dim)(G_in)
   x = Activation('tanh')(x)
   G_out = Dense(out_dim, activation='tanh')(x)
   G = Model(G_in, G_out)
   opt = SGD(lr=lr)
   G.compile(loss='binary_crossentropy', optimizer=opt)
   return G, G_out

G_in = Input(shape=[10])
G, G_out = get_generative(G_in)
G.summary()

使用 GRU 层和一些稍微不同的维度进行修改:

def get_generative(G_in, dense_dim=10, out_dim=37, lr=1e-3):
   clear_session()
   x = GRU(dense_dim, activation='tanh',return_state=True)(G_in)
   G_out = GRU(out_dim, return_state=True)(x)
   G = Model(G_in, G_out)
   opt = SGD(lr=lr)
   G.compile(loss='binary_crossentropy', optimizer=opt)
   return G, G_out

G_in = Input(shape=(None,3))
G, G_out = get_generative(G_in)
G.summary()

我在这段代码中看到的错误是:

ValueError: Tensor("gru_1/strided_slice:0", shape=(3, 10), dtype=float32) 必须来自同一图表 张量("strided_slice_1:0", shape=(?, 3), dtype=float32).

如果我删除上面的None,我会得到:

ValueError:输入 0 与层 gru_1 不兼容:预期 ndim=3, 发现 ndim=2

这里的任何解释都会有所帮助。

【问题讨论】:

    标签: python tensorflow keras keras-layer


    【解决方案1】:

    这里的问题是,RNN 层需要以下形式的 3D 张量输入:[num samples, time steps, features]。

    所以我们可以将上面的代码修改为:

    def get_generative(G_in, dense_dim=10, out_dim=37, lr=1e-3):
       x = GRU(dense_dim, activation='tanh',return_state=True)(G_in)
       G_out = GRU(out_dim, return_state=True)(x)
       G = Model(G_in, G_out)
       opt = SGD(lr=lr)
       G.compile(loss='binary_crossentropy', optimizer=opt)
       return G, G_out
    
    G_in = Input(shape=(1,3))
    G, G_out = get_generative(G_in)
    G.summary()
    

    所以我们的意思是,我们期望输入任意数量的样本,每个样本有 1 个时间步长,具有 3 个特征。

    安娜是正确的,clear_session() 不应该在生成器函数中。

    最后,如果你真的想将数据输入到网络中,它的形状也应该与我们刚才讨论的一致。您可以使用 numpy reshape 来做到这一点:

    X = np.reshape(X, (X.shape[0], 1, X.shape[1]))

    【讨论】:

    • 形状为(None, 3) 的输入与(1, 3) 一样有效。这只是意味着您的输入可以具有可变的序列长度,而您的固定大小会强制输入的序列长度为 1。我认为我的回答为您的问题提供了正确的答案。
    【解决方案2】:

    您收到一个错误,因为您在创建输入张量后清除了会话。这就是为什么输入张量与网络其他部分不来自同一个图的原因。要解决此问题,只需省略 clear_session() 行。

    您的代码的另一个问题:第二个 GRU 层需要一个序列输入,因此您应该在第一个 GRU 层内使用return_sequences=True。您可能希望省略参数return_state=True,因为这会使层返回张量元组(输出和状态),而不仅仅是一个输出张量。

    总结一下,下面的代码应该可以做到:

    def get_generative(G_in, dense_dim=10, out_dim=37, lr=1e-3):
       x = GRU(dense_dim, activation='tanh', return_sequences=True)(G_in)
       G_out = GRU(out_dim)(x)
       G = Model(G_in, G_out)
       opt = SGD(lr=lr)
       G.compile(loss='binary_crossentropy', optimizer=opt)
       return G, G_out
    

    【讨论】:

    • 不幸的是,我已经尝试过这些建议。这是我收到的代码错误值:ValueError: Input 0 is incompatible with layer gru_1: expected ndim=3, found ndim=2
    • 它对我有用。你在用G_in = Input(shape=(None,3))吗? G_in 的形状有 2 个维度(不包括批量大小),这一点很重要
    • 嗨安娜,我刚刚提出了一个关注答案。我发布的代码对我有用。谢谢您的帮助。您对清除会话的看法是对的,我认为我现在对 RNN 层的输入形状有了更好的理解。