简体   繁体   English

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

[英]Keras model on GPU: using Pandas in a custom loss function

I'm trying to define the following (toy) custom loss function in Keras:我正在尝试在 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)

I'm running this model on GPU with tf.distribute.MirroredStrategy() .我正在使用tf.distribute.MirroredStrategy()在 GPU 上运行这个模型。

Compiling the model generates no error, but when running model.fit() , the following error happens:编译模型不会产生错误,但是在运行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.

It seems that Pandas is trying to iterate over the tensor y_true , which is forbidden in graph mode (the preferred mode when training on GPU).似乎 Pandas 正在尝试迭代张量y_true ,这在图形模式(在 GPU 上训练时的首选模式)中是禁止的。

Must I understand that this is not possible to use Pandas within a loss function when training on GPU?我是否必须明白在 GPU 上训练时无法在损失函数中使用 Pandas?

What would be some plausible alternatives, other than doing all the manipulations directly in TensorFlow itself?除了直接在 TensorFlow 本身中进行所有操作之外,还有哪些看似合理的替代方案? I'm doing quite some heavy re-indexing and merging and I can't begin to imagine the pain of doing all this in native TensorFlow code.我正在做一些繁重的重新索引和合并,我无法想象在原生 TensorFlow 代码中做这一切的痛苦。

Note:笔记:

For reference, this is the kind of manipulation I'm trying to make:作为参考,这是我试图进行的那种操作:

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)

Actually I realised that all I'm doing within the custom loss function is transforming y_true .实际上,我意识到我在自定义损失函数中所做的只是转换y_true In the real case, I'm transforming it based on some random number ( if random.random() > 0.1 then apply the transformation).在实际情况中,我根据一些随机数对其进行转换( if random.random() > 0.1然后应用转换)。

The most appropriate place to do this is not in a loss function, but in the batch generator instead.最合适的地方不是在损失函数中,而是在批处理生成器中。

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')

This way the transformations are applied directly from the batch generator, and Pandas is perfectly allowed here as we're dealing only with NumPy array on the CPU.通过这种方式直接从批处理生成器应用转换,并且这里完全允许使用 Pandas,因为我们只处理 CPU 上的 NumPy 数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM