Keras 不会将模型输出与为整个小批量设计的掩码进行广播相乘

Keras won't broadcast-multiply the model output with a mask designed for the entire mini batch

我有一个数据生成器,可以生成批量输入数据 (X) 和目标 (Y),还有一个应用于模型的掩码 (batch_mask)输出(相同的掩码适用于批次中的所有数据点;不同的批次有不同的掩码,数据生成器负责执行此操作)。

因此,batch_mask 的第一个维度可能具有 1batch_size 的形状(通过沿第一个维度重复相同的掩码 batch_size 次)。我期待 Keras 让我使用其中任何一个,我想简单地创建在第一维上具有 1 形状的蒙版。

但是,当我尝试这样做时,出现错误:

ValueError: Data cardinality is ambiguous:
  x sizes: 128, 1
  y sizes: 128
Make sure all arrays contain the same number of samples.

为什么Keras不会沿第一维度广播?看来这个应该不复杂。

下面是一些观察此行为的最小示例代码

import tensorflow.keras as tfk
import numpy as np

#######################
# 1. model definition #
#######################

# model parameters
nfeatures_in = 6
target_size = 8

# model inputs
input = tfk.layers.Input(nfeatures_in)
input_mask = tfk.layers.Input(target_size)

# model graph
out = tfk.layers.Dense(target_size)(input)
out_masked = tfk.layers.Multiply()((out,input_mask)) # multiply all model outputs in the batch by the same mask
model = tfk.Model(inputs=(input, input_mask), outputs=out_masked)

##########################
# 2. dummy data creation #
##########################

batch_size = 32

# create masks the batch
zeros_vector = np.zeros((1,target_size)) # "batch_size"==1
zeros_vector[0,:6] = 1
batch_mask = zeros_vector

# dummy data creation
X = np.random.randn(batch_size, 6)
Y = np.random.randn(batch_size, target_size)*batch_mask # the target is masked by design in each batch


############################
# 3. compile model and fit #
############################

model.compile(optimizer="Adam", loss="mse")
model.fit((X, batch_mask),Y, batch_size=batch_size)

我知道我可以通过以下任一方式完成这项工作:

如何使用 Keras 进行这项工作?

谢谢!

您可以创建一个 IdentityLayer 接收作为外部输入参数的 batch_mask 和 returns 它作为张量。

class IdentityLayer(tfk.layers.Layer):
    def __init__(self, my_mask, **kwargs):
        super(IdentityLayer, self).__init__()
        self.my_mask = my_mask
    def call(self, _):
        my_mask = tf.convert_to_tensor(self.my_mask, dtype=tf.float32)
        return my_mask
    def get_config(self):
        config = super().get_config()
        config.update({
            "my_mask": self.my_mask,
        })
        return config

IdentityLayer 在模型中的用法很简单:

# model inputs
input = tfk.layers.Input(nfeatures_in)
input_mask = IdentityLayer(batch_mask)(input) 

# model graph
out = tfk.layers.Dense(target_size)(input)
out_masked = tfk.layers.Multiply()((out,input_mask)) 
model = tfk.Model(inputs=input, outputs=out_masked)

其中 batch_mask 是按照您报告的方式创建的 numpy 数组:

zeros_vector = np.zeros((1,target_size)) # "batch_size"==1
zeros_vector[0,:6] = 1
batch_mask = zeros_vector

解决方案是(正确地)使用 DataGenerator.

使用工作代码查看要点:https://gist.github.com/iranroman/2aaecf5b5621051df6b1b6b5394e5ef3

感谢 @Marco Cerliani 为找出解决方案而进行的讨论。