GPU 上的 Keras 模型:在自定义损失函数中使用 Pandas

Posted

技术标签:

【中文标题】GPU 上的 Keras 模型:在自定义损失函数中使用 Pandas【英文标题】:Keras model on GPU: using Pandas in a custom loss function 【发布时间】:2021-12-14 02:10:49 【问题描述】:

我正在尝试在 Keras 中定义以下(玩具)自定义损失函数:

def flexed_distance_loss(y_true, y_pred):
    y_true_df = pd.DataFrame(y_true, columns=my_columns)

    # do something with y_true_df

    return categorical_crossentropy(y_true_df.values, y_pred)

我正在使用tf.distribute.MirroredStrategy() 在 GPU 上运行此模型。

编译模型没有报错,但是在运行model.fit()时,出现如下错误:

>>> y_true_df = pd.DataFrame(y_true, columns=my_columns)

OperatorNotAllowedInGraphError: iterating over `tf.Tensor` is not allowed:
AutoGraph did convert this function. This might indicate you are trying to use an unsupported feature.

Pandas 似乎正在尝试迭代张量 y_true,这在图形模式(在 GPU 上训练时的首选模式)中是被禁止的。

我必须明白,在 GPU 上训练时,不可能在损失函数中使用 Pandas 吗?

除了直接在 TensorFlow 本身中进行所有操作之外,还有哪些可行的替代方案?我正在做一些繁重的重新索引和合并,我无法想象在原生 TensorFlow 代码中做这一切的痛苦。

注意:

作为参考,这是我正在尝试进行的操作:

def flexed_distance_loss(y_true, y_pred):
    y_true_df = pd.DataFrame(y_true, columns=my_columns)
    y_true_custom = y_true_df.idxmax(axis=1).to_frame(name='my_name')

    y_true_df = pd.concat([y_true_custom, y_true_df], axis=1)

    y_true_df = y_true_df.where(y_true_df != 0, np.NaN)
    y_true_df = y_true_df.reset_index().set_index('my_name')

    nearby = y_true_df.fillna(pivoted_df.reindex(y_true_df.index)) \
                            .fillna(0) \
                            .set_index('index').sort_index()

    nearby = np.expm1(nearby).div(np.sum(np.expm1(nearby), axis=1), axis=0)

    y_true_flexed = nearby.values

    return categorical_crossentropy(y_true_flexed, y_pred)

【问题讨论】:

您能否提供一些示例数据和所需的输出? 【参考方案1】:

实际上我意识到我在自定义损失函数中所做的只是转换y_true。在实际情况中,我根据一些随机数对其进行转换(if random.random() > 0.1 然后应用转换)。

最合适的地方不是损失函数,而是批处理生成器。

class BatchGenerator(tf.keras.utils.Sequence):

    def __init__(self, indices, batch_size, mode):
        self.indices = indices
        self.batch_size = batch_size
        self.mode = mode

    def __len__(self):
        return math.ceil(len(self.indices) / self.batch_size)

    def __getitem__(self, idx):
        batch = self.indices[idx * self.batch_size:(idx + 1) * self.batch_size]
        X_batch = X[batch, :]
        y_batch = y[batch, :]

        if self.mode == 'train' and random.random() > 0.3:
            # pick y from regular batch
            return X_batch, y_batch
        else:
            # apply flex-distancing to y
            return X_batch, flex_distance_batch(y_batch)

batch_size = 512*4

train_generator = BatchGenerator(range(0, test_cutoff), batch_size, 'train')
test_generator = BatchGenerator(range(test_cutoff, len(y_df)), batch_size, 'test')

这种方式直接从批处理生成器应用转换,这里完全允许使用 Pandas,因为我们只处理 CPU 上的 NumPy 数组。

【讨论】:

以上是关于GPU 上的 Keras 模型:在自定义损失函数中使用 Pandas的主要内容,如果未能解决你的问题,请参考以下文章

如何在自定义损失函数中迭代张量?

Keras 中具有样本权重的自定义损失函数

Keras 中的 .fit() 方法触发损失函数多少次

Keras 上的自定义损失函数

如何为 keras 模型使用 tensorflow 自定义损失?

使用自定义损失函数编译 Keras 模型时出现 TypeError