Пользовательские метрики и потери: AttributeError: у объекта 'Tensor' нет атрибута * numpy, созданного во время обучения - PullRequest
0 голосов
/ 29 марта 2020

Я пытаюсь реализовать пользовательскую функцию metri c, а также пользовательскую функцию потерь. Обе реализации сталкиваются с одной и той же проблемой, поэтому я собираюсь сосредоточить внимание на этом посте только на одном из них.

Моя цель - получить доступ к значению тензора во время метода подгонки, чтобы сделать расчеты на основе указанных значений, сохраненных как в y_true, так и в y_pred. Эти вычисления не могут быть выполнены с использованием встроенных внутренних функций Keras .

В качестве примера ниже приведен фиктивный код:

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, LSTM, Dense
from tensorflow.keras.metrics import Metric

x, y = list(), list()
for _ in range(10):
    x.append(np.arange(10))
    y.append(np.random.randint(0, 2))


x = np.reshape(x, (len(x), 1, len(x[0])))
y = np.asarray(y)

class custom_metric(Metric):
    def __init__(self, name = 'custom_metrics', **kwargs):
        super(custom_metric, self).__init__(name = name, **kwargs)
        self.true_positives = self.add_weight(name = 'tp', initializer = 'zeros')

    def update_state(self, y_true, y_pred, sample_weight = None):
        self.test(y_true, y_pred)
        # In a real application, new_metric would be a function that depends on
        # the values stored in both y_true and y_pred 
        new_metric = 0.1 
        self.true_positives.assign_add(tf.reduce_sum(new_metric))

    def result(self):
        return self.true_positives

    def reset_states(self):
        self.true_positives.assign(0.)

    def test(self, y_true, y_pred):
        tf.print(y_true)
        print(y_true.numpy())

model = Sequential([
    LSTM(5,
         input_shape = (np.asarray(x).shape[1], np.asarray(x).shape[2]),
         return_sequences = True,
         recurrent_initializer = 'glorot_uniform',
         activation = 'tanh',
         recurrent_dropout = 0.2,
         dropout = 0.2
        ),
    Dense(2, activation = 'softmax')
])

model.compile(
    optimizer = 'adam',
    loss = 'sparse_categorical_crossentropy',
    metrics = ['sparse_categorical_accuracy', custom_metric()]
)

model.fit(
    x, y,
    epochs = 1,
    batch_size = 1
)

Я написал эту фиктивную функцию test просто для иллюстрации проблемы. Если используется только tf.print, код запускается и значения в тензорах печатаются на stdout после завершения подгонки. Тем не менее, если я пытаюсь что-то вроде y_true.numpy или print(y_true.numpy()) код возвращает

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

Я пробовал несколько методов из нескольких потоков StackOverflow и Github, в том числе комбинации sess = tf.Session() с .eval(), tf.GradientTape, но каким-то образом не удалось успешно реализовать ни один из них.

Кто-нибудь знает, как решить эту проблему?

Ответы [ 3 ]

0 голосов
/ 30 марта 2020

Для тензорного потока <2.0 Графический режим по умолчанию. Чтобы запустить в активном режиме, вы должны включить его в начале с помощью: </p>

import tensorflow as tf  #<--- first import 
tf.enable_eager_execution()   #<-- immidiately followed by this, before you start defining any model
.
.
.
...rest of the code

Eager-tenors have. numpy () function.

Но даже если вы сделаете это, метод tf.keras.Model.fit () может его где-то отключить. Потому что:

Это работает:

def test(self, y_true, y_pred):
    if tf.executing_eagerly():  #<--- This is False
        print(y_true.numpy())
    else:
        print(y_pred)

Это также:

def test(self, y_true, y_pred):
    print(y_pred)

Но это не так:

def test(self, y_true, y_pred):
        tf.print(y_true)
        print(y_true.numpy())

Если вы хотите сделайте любые дальнейшие вычисления для y_true, затем вы можете сделать это, используя тензор потока операций в графическом режиме:

class custom_metric(Metric):
    def __init__(self, name = 'custom_metrics', **kwargs):
        super(custom_metric, self).__init__(name = name, **kwargs)
        self.true_positives = self.add_weight(name = 'tp', initializer = 'zeros')
        self.lol_value = self.add_weight(name = 'lol', initializer = 'zeros')

    def update_state(self, y_true, y_pred, sample_weight = None):
        self.test(y_true, y_pred)
        # In a real application, new_metric would be a function that depends on
        # the values stored in both y_true and y_pred 
        new_metric = 0.1 
        self.true_positives.assign_add(tf.reduce_sum(new_metric))

    def result(self):
        return self.lol_value

    def reset_states(self):
        self.true_positives.assign(0.)
        self.lol_value.assign(0.)

    def test(self, y_true, y_pred):
        print(y_pred)
        self.lol_value.assign_add(100)

или, если вы действительно, абсолютно хотите numpy, тогда используйте tf.numpy_function () , который преобразует обычные вычисления numpy в эквивалентный графовый код.

def func_x(varx):
    #print(x)
    return (varx+1).astype(np.uint8)


class custom_metric(Metric):
    def __init__(self, name = 'custom_metrics', **kwargs):
        super(custom_metric, self).__init__(name = name, **kwargs)
        self.true_positives = self.add_weight(name = 'tp', initializer = 'zeros')
        self.res = self.add_weight(name='loop_counter', initializer='zeros', dtype=tf.uint8)

    def update_state(self, y_true, y_pred, sample_weight = None):
        self.test(y_true, y_pred)
        # In a real application, new_metric would be a function that depends on
        # the values stored in both y_true and y_pred 
        new_metric = 0.1 
        self.true_positives.assign_add(tf.reduce_sum(new_metric))

    def result(self):
        return self.res

    def reset_states(self):
        self.true_positives.assign(0.)

    def test(self, y_true, y_pred):
        self.res.assign(tf.numpy_function(func=func_x, inp=[self.res], Tout=[tf.uint8]))
0 голосов
/ 31 марта 2020

Наконец-то нашел ответ на него. Пока не знаю почему, но код работает с использованием tf-nightly 2.2.0-dev версии. См https://github.com/tensorflow/tensorflow/issues/38038

0 голосов
/ 30 марта 2020

numpy() метод должен существовать для тензорных объектов, когда активный режим выполнения включен в tf2.x. Может быть, эта ссылка может быть вам полезна: https://www.tensorflow.org/guide/eager#object -oriented_metrics

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...