在Keras中通过卷积合并两个张量

时间:2018-07-03 08:46:52

标签: merge keras

我正在尝试在Keras中卷积两个1D张量。 我从其他模型中得到了两个输入:

  1. x-长度为100
  2. ker-长度为5

我想使用内核x获得ker的一维卷积。 我写了一个Lambda层来做到这一点:

import tensorflow as tf
def convolve1d(x):
    y = tf.nn.conv1d(value=x[0], filters=x[1], padding='VALID', stride=1)
    return y

x = Input(shape=(100,))
ker = Input(shape=(5,))
y = Lambda(convolve1d)([x,ker])
model = Model([x,ker], [y])

我收到以下错误:

ValueError: Shape must be rank 4 but is rank 3 for 'lambda_67/conv1d/Conv2D' (op: 'Conv2D') with input shapes: [?,1,100], [1,?,5].

有人可以帮助我了解如何解决此问题吗?

3 个答案:

答案 0 :(得分:1)

从给定的代码中很难指出您说的意思

  

有可能

但是,如果您的意思是合并两层并将合并的层馈送给转换,是可以的。

x = Input(shape=(100,))
ker = Input(shape=(5,))
merged = keras.layers.concatenate([x,ker], axis=-1)
y = K.conv1d(merged, 'same')
model = Model([x,ker], y)

编辑:

@ user2179331感谢您澄清您的意图。现在,您错误地使用了Lambda类,这就是显示错误消息的原因。 但是,您可以尝试使用keras.backend层​​来实现。 尽管要注意的是,在使用较低级别的层时,您将失去一些较高级别的抽象。例如,当使用keras.backend.conv1d时,您需要输入形状为(BATCH_SIZE,宽度,通道)和内核形状为(kernel_size,input_channels,output_channels)。因此,在您的情况下,假设x的通道数为1(输入通道== 1),而y的通道数也相同(输出通道== 1)。

因此您的代码现在可以按以下方式重构

from keras import backend as K
def convolve1d(x,kernel):
    y = K.conv1d(x,kernel, padding='valid', strides=1,data_format="channels_last")
    return y
input_channels = 1
output_channels = 1
kernel_width = 5
input_width = 100
ker = K.variable(K.random_uniform([kernel_width,input_channels,output_channels]),K.floatx())
x = Input(shape=(input_width,input_channels)
y = convolve1d(x,ker)

答案 1 :(得分:1)

这比我想象的要困难得多,因为Keras和Tensorflow在卷积内核中不希望有任何批处理维,因此我不得不自己为批处理维编写循环,这需要指定batch_shape而不是仅仅shape层中的Input。这是:

import numpy as np
import tensorflow as tf
import keras
from keras import backend as K
from keras import Input, Model
from keras.layers import Lambda

def convolve1d(x):
    input, kernel = x
    output_list = []
    if K.image_data_format() == 'channels_last':
        kernel = K.expand_dims(kernel, axis=-2)
    else:
        kernel = K.expand_dims(kernel, axis=0)
    for i in range(batch_size): # Loop over batch dimension
        output_temp = tf.nn.conv1d(value=input[i:i+1, :, :],
                                   filters=kernel[i, :, :],
                                   padding='VALID',
                                   stride=1)
        output_list.append(output_temp)
        print(K.int_shape(output_temp))
    return K.concatenate(output_list, axis=0)

batch_input_shape = (1, 100, 1)
batch_kernel_shape = (1, 5, 1)

x = Input(batch_shape=batch_input_shape)
ker = Input(batch_shape=batch_kernel_shape)
y = Lambda(convolve1d)([x,ker])
model = Model([x, ker], [y])

a = np.ones(batch_input_shape)
b = np.ones(batch_kernel_shape)
c = model.predict([a, b])

当前状态:

  • 它不适用于具有多个通道的输入(x)。
  • 如果提供几个过滤器,则将获得尽可能多的输出,每个输出都是输入与相应内核的卷积。

答案 2 :(得分:0)

我想我已经理解你的意思了。鉴于以下错误的示例代码:

input_signal = Input(shape=(L), name='input_signal')
input_h = Input(shape=(N), name='input_h')
faded= Lambda(lambda x: tf.nn.conv1d(input, x))(input_h) 

您想用不同的衰落系数矢量对每个信号矢量进行卷积。 TensorFlow等tf.nn.conv1d中的'conv'操作仅支持固定值内核。因此,上面的代码无法按您希望的方式运行。

我也不知道。您提供的代码可以正常运行,但是它太复杂且效率不高。在我的想法中,另一种可行但效率低下的方法是与Toeplitz矩阵相乘​​,该矩阵的行向量是移位的衰落系数向量。当信号矢量过长时,矩阵将非常大。