Keras 后端扁平化的问题

csa*_*r69 6 flatten keras tensorflow

为什么 Keras.backend.flatten 没有显示正确的尺寸?我有以下几点:

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

后:

Keras.backend.flatten(x)
Run Code Online (Sandbox Code Playgroud)

x 变为:<tf.Tensor 'Reshape_22:0' shape=(?,) dtype=float32>

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

编辑-1

我得到 (?, ?) 如果我使用batch_flattenbranch3x3&branch5x5下面是来自先前卷积的张量):

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

第一个 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而不是batch_flatten似乎有效)。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)
Run Code Online (Sandbox Code Playgroud)

output语句导致以下错误kernel_initializerTypeError: Failed to convert object of type to Tensor。内容:(无,32)。考虑将元素转换为支持的类型。

Yu-*_*ang 5

从文档字符串flatten

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

因此,它将具有 shape 的张量(batch_size, 4, 8, 62)转换为具有 shape的一维张量(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.
    """
Run Code Online (Sandbox Code Playgroud)

编辑:您看到形状是(?, ?)因为形状是在运行时动态确定的。如果输入 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)
Run Code Online (Sandbox Code Playgroud)

编辑-2:

从错误消息来看,似乎TruncatedNormal需要上一层的固定输出形状。所以动态形状(None, None)frombatch_flatten将不起作用。

我能想到两个选择:

  1. 提供手动计算output_shapeLambda层:
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)
Run Code Online (Sandbox Code Playgroud)
  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)
Run Code Online (Sandbox Code Playgroud)

我更喜欢后者,因为它使代码不那么混乱。还,

  • 您可以替换Lambda层包裹K.concatenate()Concatenate一层。
  • 请记住将其Input(shape=(4, 1))移出并在Model(inputs=...)通话中提供。