我正在尝试实现自定义指标函数以及自定义损失函数。两种实现都面临着相同的问题,因此,我将只关注其中之一。
我的目标是在fit方法期间访问张量的值,以便根据存储在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
的组合,但是以某种方式未能成功实现它们。
有人知道如何解决这个问题吗?
答案 0 :(得分:0)
numpy()
方法。也许此链接可能对您有所帮助:https://www.tensorflow.org/guide/eager#object-oriented_metrics
答案 1 :(得分:0)
对于tensorflow,默认情况下为<2.0图形模式,要在eager模式下运行,您必须首先通过以下方式启用它:
import tensorflow as tf #<--- first import
tf.enable_eager_execution() #<-- immidiately followed by this, before you start defining any model
.
.
.
...rest of the code
热切张量具有.numpy()函数。
但是即使您执行此操作,也可能是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进行任何进一步的计算,则可以在图形模式下使用tensorflow ops进行:
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]))
答案 2 :(得分:0)
最后找到了答案。我不知道为什么,但是代码使用tf-nightly 2.2.0-dev
版本。参见https://github.com/tensorflow/tensorflow/issues/38038