获取批次中样本之间的随机加权平均值,具有任意样本形状

Get randomly weighted averages between samples in a batch, with arbitrary sample shape

本质上,我想要一个 this custom Keras layer:

的实现
class RandomWeightedAverage(_Merge):
    """Provides a (random) weighted average between real and generated image samples"""
    def _merge_function(self, inputs):
        alpha = K.random_uniform((32, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

但批量大小任意且不依赖于数据的形状。该层的目的是通过取每对样本的平均值来合并两个批次,但随机加权每个平均值。该实施的问题是:

  1. 它的硬编码批量大小为 32。在我的模型中,批量大小当前在我创建层时未定义。我可以更改它以便更早定义批处理大小,但我真的不想这样做。
  2. If 假设批处理中的每个样本都是 3 阶张量,因为它最初是用于图像的。我有两种类型的数据将在我的模型中使用,一种是形状为 (28, 28, 1) 的图像,另一种是形状为 (100,) 的矢量。我不想做两个 RandomWeightedAverage 层实现。

如何制作形状为 [batch_size] + [1] * rank_of_samplesrandom_uniform 张量?或者,更抽象地说,是否有另一种方法可以通过对每对样本取随机加权平均值来实现合并两个批次的相同目标?

我尝试过的事情:

  1. alpha = K.random_uniform(K.shape(inputs[0])[0])
    
    任何此类操作都行不通,因为两个张量必须具有相同的阶数才能相乘,即使它们的形状不完全相同。例如,形状像 (32,)(32, 28, 28, 1) 的张量不能相乘,但 (32, 1, 1, 1)(32, 28, 28, 1) 可以。
  2. in_shape = K.shape(inputs[0])
    shape = K.concatenate([in_shape[0], K.ones_like(in_shape[1:], dtype='int32')], axis=0)
    alpha = K.random_uniform(shape)
    
    不起作用,给出稍微令人困惑的错误:
    ValueError: Can't concatenate scalars (use tf.stack instead) for 'random_weighted_average_1/concat' (op: 'ConcatV2') with input shapes: [], [3], [].
    
  3. in_shape = K.shape(inputs[0])
    shape = K.ones_like(in_shape, dtype='int32')
    shape[0] = in_shape[0]
    alpha = K.random_uniform(shape)
    
    不起作用,给出错误:
    TypeError: 'Tensor' object does not support item assignment
    

凯拉斯 2.3.0,TF 1.14.0

事实证明,我接近尝试 #2。在问题的代码中,in_shape[0] 是一个标量,我试图将它与 K.ones_like(in_shape[1:], dtype='int32') 连接起来,后者是一个向量。只需将 in_shape[0] 更改为 in_shape[0:1] 就足以修复错误并成功编译我的模型。

最终代码:

class RandomWeightedAverage(layers.merge._Merge):
    """Provides a (random) weighted average between real and generated image samples"""
    def _merge_function(self, inputs):
        in_shape = K.shape(inputs[0])
        shape = K.concatenate([in_shape[0:1], K.ones_like(in_shape[1:], dtype='int32')], axis=0)
        alpha = K.random_uniform(shape)
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

我不确定这是执行此操作的最佳方法,但至少它似乎有效。