如何在不启用 keras 中的 run_eagerly 标志的情况下将张量转换为 numpy 数组

Posted

技术标签:

【中文标题】如何在不启用 keras 中的 run_eagerly 标志的情况下将张量转换为 numpy 数组【英文标题】:how to convert a tensor to a numpy array without enabling the run_eagerly flag in keras 【发布时间】:2021-11-03 03:40:36 【问题描述】:

我正在编写自己的指标回调函数,我使用 sklearn 来计算指标,为此我需要将 y_true 和 y_pred 张量作为 numpy 数组。我的函数如下所示:

def precision_macro(y_true, y_pred):
    # get the y_true and y_pred tensors as 1-D numpy array
    y_true_array = np.array(true)
    y_pred_array = np.array(pred)
    ....................
    ....................
        CALCULATIONS
    ....................
    ....................
    precision = precision_score(y_true_array, y_pred_array, average="macro", zero_division=0)
    return precision

如果我在编译调用期间像这样设置run_eargly=True,一切正常:

model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=lr),
                      loss='binary_crossentropy',
                      metrics=model_metrics,
                      run_eagerly=True) 

但这比将标志设置为 False 成本高且速度慢,但如果我不将标志设置为 True,我的转换就会出现问题。以下是我在没有将 run_eagrly 标志设置为 True 的情况下尝试过的事情,但没有奏效:

如果我只是不设置 run_eagerly 标志,我会收到以下错误

NotImplementedError:无法将符号张量 (ExpandDims:0) 转换为 numpy 数组。此错误可能表明您正在尝试将张量传递给 NumPy 调用,这是不受支持的

然后我尝试了

import tensorflow.keras.backend as K

def precision_macro(y_true, y_pred):
    # get the y_true and y_pred tensors as 1-D numpy array
    y_true_array = K.eval(y_true)
    y_pred_array = K.eval(y_pred)
    ....................

或者我尝试在张量上调用 numpy 函数

def precision_macro(y_true, y_pred):
    # get the y_true and y_pred tensors as 1-D numpy array
    y_true_array = y_true.numpy()
    y_pred_array = y_pred.numpy()
    ....................

我也尝试在这样的会话中运行它:

import tensorflow.keras.backend as K
import tensorflow as tf

def precision_macro(y_true, y_pred):
    sess = tf.compat.v1.Session()
    # get the y_true and y_pred tensors as 1-D numpy array
    with sess.as_default():
       y_true_array = K.eval(y_true)
       y_pred_array = K.eval(y_pred)
    ....................

对于所有 thress 情况,我都会收到以下错误

AttributeError: 'Tensor' 对象没有属性 'numpy'

我试着这样运行它:

import tensorflow.keras.backend as K
import tensorflow as tf

def precision_macro(y_true, y_pred):
    sess = tf.compat.v1.Session()
    # get the y_true and y_pred tensors as 1-D numpy array
    with sess.as_default():
       y_true_array = sess.run(y_true)
       y_pred_array = sess.run(y_pred)
    ....................

我收到以下错误

InvalidArgumentError:找到 2 个根错误。 (0) 无效参数:您必须使用 dtype 资源为占位符张量“迭代器”提供值 (1) 无效参数:您必须使用 dtype 资源为占位符张量“迭代器”提供值

我尝试将 numpy 从 1.19.5 降级到 1.18.5 但这也没有用,我得到了同样的错误

正在尝试tf.numpy_function()

import tensorflow as tf

def numpy_function(y_true, y_pred):
    # get the y_true and y_pred tensors as 1-D numpy array
    y_true_array = y_true
    y_pred_array = y_pred
    .... calculations ....
    precision = precision_score(y_true_array, y_pred_array, average="macro", zero_division=0)
    precision_per_class.append(precision_score(y_true_array, y_pred_array, average=None, zero_division=0))
    return precision

我作为度量传递的函数

@tf.function
def precision_macro(y_true, y_pred):
    score = tf.numpy_function(numpy_function, [y_true, y_pred], tf.float32)

    return score

我这样编译,model_metrics = ['accuracy', precision_macro]

model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=lr),
                      loss='binary_crossentropy',
                      metrics=model_metrics)

我收到以下错误

TypeError: 'Tensor' 对象不支持项目分配

我正在使用keras = 2.6. tensorflow = 2.6 numpy = 1.19.5

那么,谁能帮帮我?

【问题讨论】:

我还尝试在将 Tenosr 转换为 numpy 数组之前启用急切执行,然后通过调用 tf.compat.v1.enable_eager_execution() 和 tf.compat 在执行的其余部分禁用它。 v1.disable_eager_execution() 并且它不起作用,如果我在启用后直接打印 tf.executing_eagerly() 它仍然打印 False! 【参考方案1】:

你可以试试tf.numpy_function。它接收一个函数作为参数,并在传递给函数之前自动将张量转换为 numpy 数组,并将函数的输出转换回张量。见例子:

def my_numpy_func(y_true, y_pred):
  # y_true and y_pred are already numpy arrays
  # put all numpy or sklearn codes here
  return metrics.mean_squared_error(y_true, y_pred)

@tf.function
def custom_metric(y_true, y_pred):
  # y_true and y_pred are tensors
  # no numpy or sklearn code is allowed here
  score = tf.numpy_function(my_numpy_func, [y_true, y_pred], tf.float32)
  return score

它将允许您拥有run_eagerly = False,并且理论上运行速度更快,因为除了此自定义指标之外的大多数计算都在图形模式下工作。

【讨论】:

我禁用了 run_eagerly 并尝试过。我收到此错误 >TypeError: 'Tensor' object does not support item assignment 我在 my_numpy_func 中添加了一个 breakpoint() 调用,并且参数仍然作为张量传递! 如果我启用 run_eagerly 参数将作为 numpy 数组传递。所以也许问题是我可以只为度量计算启用标志吗? 请确保首先删除所有 tf.compat.v1.X 或 tensorflow v1 代码(并且不要再次尝试这些代码),因为这些代码在 tensorflow v2 中有错误并会破坏。然后,请在您尝试tf.numpy_function 时发布指标代码,即precision_macromy_numpy_func,包括显示您如何调用model.compile 例如,我可以重现您的错误的一种方法是执行 model.compile(loss='mse',optimizer='sgd',metrics=[my_numpy_func]),而不是您应该调用 model.compile(loss='mse',optimizer='sgd',metrics=[custom_metric]) 以使其正常工作。 你能检查一下问题的最后一部分吗,我修改了它,我没有使用tf.compat.v1的任何内容

以上是关于如何在不启用 keras 中的 run_eagerly 标志的情况下将张量转换为 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章

Keras - 如何在不改变纵横比的情况下使用 ImageDataGenerator

如何使用 Theano 启用 Keras 以利用多个 GPU

如何重塑文本数据以适合 keras 中的 LSTM 模型

如何在不禁用列表项的命中测试的情况下启用对列表项的选择?

在不使用 Keras API 的情况下,提取 Keras 层的权重对于进行前向传递有啥意义

如何在不使用本机代码的情况下要求用户在 NativeScript 上启用蓝牙