【问题标题】:Implementing a batch dependent loss in Keras在 Keras 中实现批次相关的损失
【发布时间】:2019-04-05 21:56:47
【问题描述】:

我在 Keras 中设置了一个自动编码器。我希望能够根据预定的“精度”向量对输入向量的特征进行加权。这个连续值向量与输入的长度相同,每个元素都在[0, 1]范围内,对应输入元素的置信度,其中1表示完全置信,0表示不置信。

我为每个示例都有一个精度向量。

我已经定义了一个考虑到这个精度向量的损失。在这里,低置信度特征的重建被降低权重。

def MAEpw_wrapper(y_prec):
    def MAEpw(y_true, y_pred):
        return K.mean(K.square(y_prec * (y_pred - y_true)))
    return MAEpw

我的问题是精度张量 y_prec 取决于批次。我希望能够根据当前批次更新y_prec,以便每个精度向量与其观察正确关联。

我做了以下事情:

global y_prec
y_prec = K.variable(P[:32])

这里的P 是一个 numpy 数组,其中包含所有精度向量,其索引对应于示例。我将y_prec 初始化为具有32 批大小的正确形状。然后我定义以下DataGenerator

class DataGenerator(Sequence):

    def __init__(self, batch_size, y, shuffle=True):

        self.batch_size = batch_size

        self.y = y

        self.shuffle = shuffle
        self.on_epoch_end()

    def on_epoch_end(self):
        self.indexes = np.arange(len(self.y))

        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __len__(self):
        return int(np.floor(len(self.y) / self.batch_size))

    def __getitem__(self, index):
        indexes = self.indexes[index * self.batch_size: (index+1) * self.batch_size]

        # Set precision vector.
        global y_prec
        new_y_prec = K.variable(P[indexes])
        y_prec = K.update(y_prec, new_y_prec)

        # Get training examples.
        y = self.y[indexes]

        return y, y

我的目标是在生成批处理的同一函数中更新y_prec。这似乎正在按预期更新y_prec。然后我定义我的模型架构:

dims = [40, 20, 2]

model2 = Sequential()
model2.add(Dense(dims[0], input_dim=64, activation='relu'))
model2.add(Dense(dims[1], input_dim=dims[0], activation='relu'))
model2.add(Dense(dims[2], input_dim=dims[1], activation='relu', name='bottleneck'))
model2.add(Dense(dims[1], input_dim=dims[2], activation='relu'))
model2.add(Dense(dims[0], input_dim=dims[1], activation='relu'))
model2.add(Dense(64, input_dim=dims[0], activation='linear'))

最后,我编译并运行:

model2.compile(optimizer='adam', loss=MAEpw_wrapper(y_prec))
model2.fit_generator(DataGenerator(32, digits.data), epochs=100)

digits.data 是一个 numpy 观察数组。

但是,这最终会定义单独的图表:

StopIteration: Tensor("Variable:0", shape=(32, 64), dtype=float32_ref) must be from the same graph as Tensor("Variable_4:0", shape=(32, 64), dtype=float32_ref).

我已经搜索了 SO 来解决我的问题,但我没有找到任何工作。任何有关如何正确执行此操作的帮助表示赞赏。

【问题讨论】:

    标签: python tensorflow keras loss-function


    【解决方案1】:

    使用Keras functional API 可以轻松实现此自动编码器。这将允许有一个额外的输入占位符y_prec_input,它将被输入“精度”向量。完整的源代码可以在here找到。


    数据生成器

    首先,让我们重新实现您的数据生成器,如下所示:

    class DataGenerator(Sequence):
        def __init__(self, batch_size, y, prec, shuffle=True):
            self.batch_size = batch_size
            self.y = y
            self.shuffle = shuffle
            self.prec = prec
            self.on_epoch_end()
    
        def on_epoch_end(self):
            self.indexes = np.arange(len(self.y))
            if self.shuffle:
                np.random.shuffle(self.indexes)
    
        def __len__(self):
            return int(np.floor(len(self.y) / self.batch_size))
    
        def __getitem__(self, index):
            indexes = self.indexes[index * self.batch_size: (index + 1) * self.batch_size]
            y = self.y[indexes]
            y_prec = self.prec[indexes]
            return [y, y_prec], y
    

    请注意,我摆脱了全局变量。现在,精度向量 P 作为输入参数 (prec) 提供,并且生成器产生一个额外的输入,该输入将馈送到精度占位符 y_prec_input(参见模型定义)。


    型号

    最后,您的模型可以定义和训练如下:

    y_input = Input(shape=(input_dim,))
    y_prec_input = Input(shape=(1,))
    h_enc = Dense(dims[0], activation='relu')(y_input)
    h_enc = Dense(dims[1], activation='relu')(h_enc)
    h_enc = Dense(dims[2], activation='relu', name='bottleneck')(h_enc)
    h_dec = Dense(dims[1], activation='relu')(h_enc)
    h_dec = Dense(input_dim, activation='relu')(h_dec)
    model2 = Model(inputs=[y_input, y_prec_input], outputs=h_dec)
    model2.compile(optimizer='adam', loss=MAEpw_wrapper(y_prec_input))
    
    # Train model
    model2.fit_generator(DataGenerator(32, digits.data, P), epochs=100)
    

    在哪里input_dim = digits.data.shape[1]。请注意,我还将解码器的输出维度更改为input_dim,因为它必须与输入维度匹配。

    【讨论】:

    • 这比我尝试的更有意义。假设我没有问题,我将在一两天内实现它并将其标记为已接受。谢谢!
    【解决方案2】:

    在调用 fit_generator 时尝试使用 worker=0 测试您的代码,如果它正常工作,那么线程就是您的问题。

    如果线程是原因,试试这个:

    # In the code that executes on the main thread
    graph = tf.get_default_graph()
    
    # In code that executes in other threads(e.g. your generator)
    with graph.as_default():
        ...
        ...
        new_y_prec = K.variable(P[indexes])
        y_prec = K.update(y_prec, new_y_prec)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-02
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      相关资源
      最近更新 更多