【问题标题】:Keras implementation of Siamese like network sharing layersKeras 实现类似连体的网络共享层
【发布时间】:2019-12-05 10:55:54
【问题描述】:

我尝试在这里实现网络架构:Architecture of the network I try to implement (from Zhenyu et.al. 2019) using Keras framework with Tensorflow backend。

该网络是一个类似连体的网络,具有共享层 Conv1、Conv2、Conv3。目的是在 2 个不同的输入之间调整域,但这目前不是问题,我在此之前被卡住了。问题是我面临无法实现模型的问题。

所以我目前定义的模型如下:

为两个输入(源、目标)定义输入层:

source_domain_input = keras.layers.Input(shape=(None, None, 160, 1),name="SourceDomainInput")
target_domain_input = keras.layers.Input(shape=(None, None, 160, 1),name="TargetDomainInput")

然后我定义了共享层部分(Conv1、Conv2 和 Conv3)——为了缩短示例,我删除了池化层:

model_shared_part = keras.models.Sequential()
model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=16,
                                                                       kernel_size=3,
                                                                       activation='relu'),
                                                   input_shape=(None, None, 160, 1)))

model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=32,
                                                                       kernel_size=3,
                                                                       activation='relu')))

model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=64,
                                                                       kernel_size=3,
                                                                       activation='relu')))

然后我将输入连接到共享层以成为连体(并行)结构:

featureOutput_conv3_target = model_shared_part(target_domain_input)
featureOutput_conv3_source = model_shared_part(source_domain_input)

然后我将剩余的层添加到源部分(图像中的上部分支)以缩短示例我只添加了一些层而不是全部:

model_source_single_part = keras.models.Sequential()

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=64,
                                                                              kernel_size=3,
                                                                              activation='relu'),
                                                         )
                            )

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.MaxPooling1D(pool_size=2)
                                                          )
                             )

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.Flatten()
                                                         )
                            )

model_source_single_part.add(keras.layers.LSTM(units=60)
                            )

model_source_single_part.add(keras.layers.Dense(100,
                                                activation='relu')
                             )

model_source_single_part.add(keras.layers.Dense(units=4,
                                                activation='softmax'
                                               )
                            )

final_source_layer = model_source_single_part(featureOutput_conv3_source)

然后我将创建的架构合并到最终模型中:

dwcDAN_model = keras.models.Model(inputs=[source_domain_input,
                                          target_domain_input],
                                  outputs = final_source_layer
                                  )

# Model compilation
dwcDAN_model.compile(
        loss='categorical_crossentropy',
        optimizer='adam',
        metrics=['accuracy'])

但是模型图给出了以下内容:

Model Plot

我所期望的是,名为sequential_2 的顺序模型是共享层部分,它连接到两个输入。但它只连接到源输入。

如何在上面的实现中找到错误?

【问题讨论】:

  • 你想用featureOutput_conv3_target做什么?在连体网络中,计算提取的源和目标特征向量之间的距离或相似度(使用欧几里得距离等度量)。但是,您刚刚从目标中提取了特征,但以后没有使用。我猜你想在featureOutput_conv3_targetfeatureOutput_conv3_source 之间执行一些操作(例如相似性测量),然后你可能希望将该融合功能传递给model_source_single_part(fused_feature) 而不是model_source_single_part(featureOutput_conv3_source)
  • 亲爱的@bit01 感谢您的回复。我的目标如下。我想计算两层的特征输出之间的最大平均差异。因此,我正在寻找一种计算 MMD 并计算相对于 MMD 值的最终损失的方法。因此,不仅使用来自 softmax 分类器的预测交叉熵进行优化,而且还使用了 MMD 值。有了这个,我的目标是减少域差异。你能帮帮我吗?
  • 请分享参考论文链接。

标签: python keras


【解决方案1】:

想法很简单。连接 featureOutput_conv3_sourcefeatureOutput_conv3_target 并将此连接功能与您的 final_source_layer 一起用作输出。现在您可能会问连接层的标签是什么。好吧,只需发送任何虚拟值,因为它永远不会被使用。我在下面给出一个大纲。请检查mmd损失函数中连接层的形状。

def compute_kernel(x, y):
    x_size = tf.shape(x)[0]
    print(x_size.shape)
    y_size = tf.shape(y)[0]
    print(y_size.shape)
    dim = tf.shape(x)[1]*tf.shape(x)[2]*tf.shape(x)[3]
    print(dim.shape)
    tiled_x = tf.tile(tf.reshape(x, tf.stack([x_size, 1, dim])), tf.stack([1, y_size, 1]))
    print(tiled_x.shape)
    tiled_y = tf.tile(tf.reshape(y, tf.stack([1, y_size, dim])), tf.stack([x_size, 1, 1]))
    print(tiled_y.shape)
    ret =  tf.exp(-tf.reduce_mean(tf.square(tiled_x - tiled_y), axis=2) / tf.cast(dim, tf.float32))
    print(ret.shape)
    return ret


def mmd(y_true, y_pred):
    print(y_pred.shape)
    #FEATURE_LENGTH = int(y_pred.shape[3]/2) # length of each is 64
    x1 = y_pred[:,:,:,:64]  # x1 represents feature output of conv3 from source
    x2 = y_pred[:,:,:,64:] # x2 represents feature output of conv3 from source
    x1x1 = compute_kernel(x1, x1)
    x1x2 = compute_kernel(x1, x2)
    x2x2 = compute_kernel(x2, x2)
    diff = keras.backend.mean(x1x1) - 2 * keras.backend.mean(x1x2) + keras.backend.mean(x2x2)
    return diff


model_shared_part = keras.models.Sequential()
model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=16,
                                                                       kernel_size=3,
                                                                       activation='relu'),
                                                   input_shape=(5, 160, 1)))

model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=32,
                                                                       kernel_size=3,
                                                                       activation='relu')))

model_shared_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=64,
                                                                       kernel_size=3,
                                                                       activation='relu')))


source_domain_input = keras.layers.Input(shape=(5, 160, 1),name="SourceDomainInput")
target_domain_input = keras.layers.Input(shape=(5, 160, 1),name="TargetDomainInput")
featureOutput_conv3_target = model_shared_part(target_domain_input)
featureOutput_conv3_source = model_shared_part(source_domain_input)


feature_concat = keras.layers.Concatenate()([featureOutput_conv3_source,featureOutput_conv3_target])
print(feature_concat.shape)



model_source_single_part = keras.models.Sequential()

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.Conv1D(filters=64,
                                                                              kernel_size=3,
                                                                              activation='relu'),
                                                         )
                            )

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.MaxPooling1D(pool_size=2)
                                                          )
                             )

model_source_single_part.add(keras.layers.TimeDistributed(keras.layers.Flatten()
                                                         )
                            )

model_source_single_part.add(keras.layers.LSTM(units=60)
                            )

model_source_single_part.add(keras.layers.Dense(100,
                                                activation='relu')
                             )

model_source_single_part.add(keras.layers.Dense(units=4,
                                                activation='softmax'
                                               )
                            )

final_source_layer = model_source_single_part(featureOutput_conv3_source)

print(final_source_layer.shape)


# Model build
dwcDAN_model = keras.models.Model(inputs=[source_domain_input, target_domain_input], outputs = [final_source_layer, feature_concat])
dwcDAN_model.compile(optimizer='adam', loss=['categorical_crossentropy', mmd])

print(dwcDAN_model.summary())


x1_train = np.random.rand(100, 5, 160, 1)
x2_train = np.random.rand(100, 5, 160, 1)
y_train1 = np.eye(100, 4)
y_train2 = np.random.rand(100, 5, 154, 128)


dwcDAN_model.fit([x1_train, x2_train], [y_train1, y_train2], epochs=1, batch_size=2, validation_split=.2)

【讨论】:

  • 亲爱的@bit01 非常感谢您的回复。如果我尝试上面的 sn-p,我会得到一个错误。我用与 theanos dimshuffle 等效的 tensorflow 替换了 r = x1.dimshuffle(0,'x',1)r = tf.expand_dims(tf.transpose(x1,[0,1]), 1) 我对此不是很熟悉,所以请您验证替换是否给出了预期的结果?我想是的,在这里找到描述:link 如果我运行代码,我会收到错误:ValueError: Dimension must be 4 but is 2 for 'loss_13/concatenate_loss/...
  • 在您的代码中,您使用 check with shape 注释了我认为会导致错误的行。我不太明白 mmd 函数的前两行是做什么的。你能给我解释一下吗? y_pred 和 y_true 的长度为 4,因为有 4 个类可用。我不知道 FEATURE_LENGTH 变量的作用是什么?我在两行上方用 1 定义了它,但我不知道它是什么意思。你能解释一下吗?非常感谢您的帮助。
  • FEATURE_LENGTH = 64(我想让你明白)是model_shared_part最后一层的特征。由于我们连接源和目标特征只是为了计算 MMD,在mmd loss function 我们通过切片分离/提取这两个特征,以便x1 & x2 has same size 并计算 MMD。
  • 感谢您的解释,我编辑了您的代码功能,但仍然存在尺寸不匹配,我将其发布在上面的答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
相关资源
最近更新 更多