Keras后端flatten出问题

6

Keras.backend.flatten为什么不能正确显示维度?我的代码如下:

x是<tf.Tensor 'concat_8:0' shape=(?, 4, 8, 62) dtype=float32>

之后使用Keras.backend.flatten:

Keras.backend.flatten(x)

x的形状变成了:<tf.Tensor 'Reshape_22:0' shape=(?,) dtype=float32>

x为什么不是形状为(?, 4*8*62)

编辑-1

如果我使用batch_flatten(下面的branch3x3branch5x5都是来自之前卷积的张量),那么我会得到(?, ?):

x = Lambda(lambda v: K.concatenate([v[0], v[1]], axis=3))([branch3x3, branch5x5])
x = Lambda(lambda v: K.batch_flatten(v))(x)

第一个Lambda的结果是<tf.Tensor 'lambda_144/concat:0' shape=(?, 4, 8, 62) dtype=float32>

第二个Lambda的结果是<tf.Tensor 'lambda_157/Reshape:0' shape=(?, ?) dtype=float32>

编辑-2

尝试使用batch_flatten,但在构建模型输出时遇到错误(改用reshape似乎可以解决)。branch3x3是<tf.Tensor 'conv2d_202/Elu:0' shape=(?, 4, 8, 30) dtype=float32>,而branch5x5是<tf.Tensor 'conv2d_203/Elu:0' shape=(?, 4, 8, 32) dtype=float32>:

from keras import backend as K
x = Lambda(lambda v: K.concatenate([v[0], v[1]], axis=3))([branch3x3, branch5x5])
x = Lambda(lambda v: K.batch_flatten(v))(x)
y = Conv1D(filters=2, kernel_size=4)(Input(shape=(4, 1)))
y = Lambda(lambda v: K.batch_flatten(v))(y)
z = Lambda(lambda v: K.concatenate([v[0], v[1]], axis=1))([x, y])
output = Dense(32, kernel_initializer=TruncatedNormal(), activation='linear')(z)
cnn = Model(inputs=[m1, m2], outputs=output)
< p >对于< code >kernel_initializer,输出语句导致以下错误:< strong >类型错误:无法将类型转换为张量的对象。内容:(无,32)。考虑将元素强制转换为支持的类型。

请在发布代码之前检查其是否可执行。当代码错误时,很难重现错误。您正在使用仅包含两个输入[branch3x3,branch5x5]的调用K.concatenate([v[0], v[1], v[2]], axis=3) - Yu-Yang
此外,使用Keras中实现的ConcatenateFlatten层而不是Lambda层有什么原因吗? - Yu-Yang
抱歉,那是个打错字。我的真实代码更长,所以在这里简化了它以便关注主要问题。根据您在 https://stackoverflow.com/questions/45309236/keras-backend-modeling-issue 的建议,我正在使用Lambda层来创建模型(遇到了与该案例类似的问题)。 - csankar69
我已经编辑并添加了一个示例,以使其更清晰 :). 请看看是否适合您。 - Yu-Yang
1个回答

6

来自flatten的文档字符串:

def flatten(x):
    """Flatten a tensor.
    # Arguments
        x: A tensor or variable.
    # Returns
        A tensor, reshaped into 1-D
    """

因此,它将形状为(batch_size, 4, 8, 62)的张量转换为形状为(batch_size * 4 * 8 * 62,)的一维张量。这就是为什么您的新张量具有一维形状(?,)

如果要保留第一维,请使用batch_flatten

def batch_flatten(x):
    """Turn a nD tensor into a 2D tensor with same 0th dimension.
    In other words, it flattens each data samples of a batch.
    # Arguments
        x: A tensor or variable.
    # Returns
        A tensor.
    """

编辑:你看到的形状是(?, ?),因为形状在运行时动态确定。如果你输入一个numpy数组,你可以轻松验证形状是否正确。

input_tensor = Input(shape=(4, 8, 62))
x = Lambda(lambda v: K.batch_flatten(v))(input_tensor)
print(x)

Tensor("lambda_1/Reshape:0", shape=(?, ?), dtype=float32)

model = Model(input_tensor, x)
out = model.predict(np.random.rand(32, 4, 8, 62))
print(out.shape)

(32, 1984)

编辑-2: 从错误信息来看,似乎TruncatedNormal需要上一层的固定输出形状。因此,batch_flatten的动态形状(None, None)不起作用。
我可以想到两个选项:
  1. Lambda层手动计算output_shape
x = Lambda(lambda v: K.concatenate([v[0], v[1]], axis=3))([branch3x3, branch5x5])
x_shape = (np.prod(K.int_shape(x)[1:]),)
x = Lambda(lambda v: K.batch_flatten(v), output_shape=x_shape)(x)

input_y = Input(shape=(4, 1))
y = Conv1D(filters=2, kernel_size=4)(input_y)
y_shape = (np.prod(K.int_shape(y)[1:]),)
y = Lambda(lambda v: K.batch_flatten(v), output_shape=y_shape)(y)

z = Lambda(lambda v: K.concatenate([v[0], v[1]], axis=1))([x, y])
output = Dense(32, kernel_initializer=TruncatedNormal(), activation='linear')(z)
cnn = Model(inputs=[m1, m2, input_y], outputs=output)
  1. 使用Flatten层(调用batch_flatten并在其中计算输出形状):
x = Concatenate(axis=3)([branch3x3, branch5x5])
x = Flatten()(x)

input_y = Input(shape=(4, 1))
y = Conv1D(filters=2, kernel_size=4)(input_y)
y = Flatten()(y)

z = Concatenate(axis=1)([x, y])
output = Dense(32, kernel_initializer=TruncatedNormal(), activation='linear')(z)
cnn = Model(inputs=[m1, m2, input_y], outputs=output)

我更喜欢后者,因为它可以使代码更简洁。

  • 您可以使用Concatenate层代替包装K.concatenate()Lambda层。
  • 请记得将Input(shape=(4, 1))移出,并在Model(inputs=...)中提供它。

1
非常感谢,我会尝试使用Flatten()选项。使用reshape似乎也可以:x = Lambda(lambda v: K.reshape(v, (-1, product_of_dimensions)))(x) - csankar69

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接