Convertendo tensor TensorFlow em matriz Numpy

Sep 13 2020

Descrição do Problema

Estou tentando escrever uma função de perda personalizada no TensorFlow 2.3.0. Para calcular a perda, preciso que o y_predparâmetro seja convertido em uma matriz numpy. No entanto, não consigo encontrar uma maneira de convertê-lo de <class 'tensorflow.python.framework.ops.Tensor'>em um array numpy, embora pareça haver funções do TensorFlow para fazer isso.

Exemplo de Código

def custom_loss(y_true, y_pred):
    print(type(y_pred))
    npa = y_pred.make_ndarray()
    ...
    

if __name__ == '__main__':
    ...
    model.compile(loss=custom_loss, optimizer="adam")
    model.fit(x=train_data, y=train_data, epochs=10)

dá a mensagem de erro: AttributeError: 'Tensor' object has no attribute 'make_ndarraydepois de imprimir o tipo do y_predparâmetro:<class 'tensorflow.python.framework.ops.Tensor'>

O que eu tentei até agora

Procurando por uma solução, descobri que este parece ser um problema comum e há algumas sugestões, mas elas não funcionaram para mim até agora:

1. "... então, basta chamar .numpy () no objeto Tensor.": Como posso converter um tensor em uma matriz numpy no TensorFlow?

então eu tentei:

def custom_loss(y_true, y_pred):
    npa = y_pred.numpy()
    ...

me dando AttributeError: 'Tensor' object has no attribute 'numpy'

2. "Use tensorflow.Tensor.eval () para converter um tensor em uma matriz": como converter um tensor TensorFlow em uma matriz NumPy em Python

então eu tentei:

def custom_loss(y_true, y_pred):
    npa = y_pred.eval(session=tf.compat.v1.Session())
    ...

me dando um dos mais longos vestígios de mensagens de erro que já vi com o núcleo sendo:

InvalidArgumentError: 2 root error(s) found.
      (0) Invalid argument: You must feed a value for placeholder tensor 'functional_1/conv2d_2/BiasAdd/ReadVariableOp/resource' with dtype resource
         [[node functional_1/conv2d_2/BiasAdd/ReadVariableOp/resource (defined at main.py:303) ]]
         [[functional_1/cropping2d/strided_slice/_1]]
      (1) Invalid argument: You must feed a value for placeholder tensor 'functional_1/conv2d_2/BiasAdd/ReadVariableOp/resource' with dtype resource
         [[node functional_1/conv2d_2/BiasAdd/ReadVariableOp/resource (defined at main.py:303) ]]

também ter que chamar as funções de compatibilidade do TensorFlow da versão 1.x não parece muito à prova de futuro, então, de qualquer forma, não gosto muito dessa abordagem.

3. Olhando para a documentação do TensorFlow, parecia haver a função de que eu precisava apenas esperar: tf.make_ndarray Criar um ndarray numpy a partir de um tensor.

então eu tentei:

def custom_loss(y_true, y_pred):
    npa = tf.make_ndarray(y_pred)
    ...

me dando AttributeError: 'Tensor' object has no attribute 'tensor_shape'

Olhando para o exemplo na documentação do TF, eles usam isso em um proto_tensor, então tentei primeiro converter para um proto:

def custom_loss(y_true, y_pred):
    proto_tensor = tf.make_tensor_proto(y_pred)
    npa = tf.make_ndarray(proto_tensor)
    ...

mas já tf.make_tensor_proto(y_pred)levanta o erro:TypeError: Expected any non-tensor type, got a tensor instead.

Também tentar fazer um tensor const primeiro dá o mesmo erro:

def custom_loss(y_true, y_pred):
    a = tf.constant(y_pred)
    proto_tensor = tf.make_tensor_proto(a)
    npa = tf.make_ndarray(proto_tensor)
    ...

Existem muitos mais posts sobre isso, mas parece que todos eles estão voltando a essas três ideias básicas. Ansioso para as suas sugestões!

Respostas

runDOSrun Sep 13 2020 at 17:11

y_pred.numpy()funciona no TF 2, mas AttributeError: 'Tensor' object has no attribute 'make_ndarrayindica que há partes do seu código que você não está executando no modo Eager, pois de outra forma não teria um Tensorobjeto, mas um EagerTensor.

Para habilitar o modo ansioso, coloque isso no início do seu código, antes que qualquer coisa no gráfico seja construída:

tf.config.experimental_run_functions_eagerly(True)

Em segundo lugar, ao compilar seu modelo, adicione este parâmetro:

model.compile(..., run_eagerly=True, ...)

Agora você está executando no modo ansioso e todas as variáveis ​​realmente contêm valores que você pode imprimir e trabalhar. Esteja ciente de que mudar para o modo Eager pode exigir ajustes adicionais em seu código (veja aqui uma visão geral).