cod*_*tle 0 python metrics graph tensorflow
版本:python 3.8.2(我也尝试过3.6.8,但我认为python版本在这里并不重要),tensorflow 2.3.0,numpy 1.18.5
我正在使用稀疏标签张量训练一个用于分类问题的模型。我将如何定义一个指标来计算“0”标签在此之前出现的次数?我在下面的代码示例中尝试做的是将指标在数组中看到的所有标签存储起来,并在y_true每次update_state调用时不断地将现有数组与新数组连接起来。(我知道我可以只存储一个count变量并使用+=,但在实际使用场景中,连接是理想的并且内存不是问题。)以下是重现问题的最少代码:
import tensorflow as tf
class ZeroLabels(tf.keras.metrics.Metric):
"""Accumulates a list of all y_true sparse categorical labels (ints) and calculates the number of times the '0' label has appeared."""
def __init__(self, *args, **kwargs):
super(ZeroLabels, self).__init__(name="ZeroLabels")
self.labels = self.add_weight(name="labels", shape=(), initializer="zeros", dtype=tf.int32)
def update_state(self, y_true, y_pred, sample_weight=None):
"""I'm using sparse categorical crossentropy, so labels are 1D array of integers."""
if self.labels.shape == (): # if this is the first time update_state is being called
self.labels = y_true
else:
self.labels = tf.concat((self.labels, y_true), axis=0)
def result(self):
return tf.reduce_sum(tf.cast(self.labels == 0, dtype=tf.int32))
def reset_states(self):
self.labels = tf.constant(0, dtype=tf.int32)
Run Code Online (Sandbox Code Playgroud)
该代码可以单独运行,但当我尝试使用该指标训练模型时,它会抛出以下错误:
TypeError: An op outside of the function building code is being passed
a "Graph" tensor. It is possible to have Graph tensors
leak out of the function building context by including a
tf.init_scope in your function building code.
For example, the following function will fail:
@tf.function
def has_init_scope():
my_constant = tf.constant(1.)
with tf.init_scope():
added = my_constant * 2
Run Code Online (Sandbox Code Playgroud)
我认为这可能与调用self.labels时不直接属于图表的一部分有关。update_state以下是我尝试过的其他一些方法:
tf.int32,shape=() count变量并递增该变量,而不是连接新标签.numpy()(我希望强制 TensorFlow 不使用该图)try阻止excepttf.keras.metrics.Metric),在可能的情况下专门使用 numpy ,但这种方法会导致一些加载问题,即使我custom_objects在tf.keras.models.load_model@tf.autograph.experimental.do_not_convert在所有方法上使用装饰器global关键字self.labels = self.add_weight...)如果有帮助,这是这个问题的更一般版本:我们如何将未作为参数传入的张量合并到计算update_state中update_state?任何帮助将不胜感激。先感谢您!
小智 7
主要问题是第一次迭代分配,当没有初始值时:
if self.labels.shape == ():
self.labels = y_true
else:
self.labels = tf.concat((self.labels, y_true), axis=0)
Run Code Online (Sandbox Code Playgroud)
在 if 块内,构造函数中定义的变量“标签”消失并被 tf.Tensor 对象 (y_true) 替换。因此,您必须使用 tf.Variable 方法(分配、add_assing)来修改其内容但保留对象。此外,为了能够更改 tf.variable 形状,您必须以允许您拥有未定义形状的方式创建它,在本例中:(None,1),因为您在轴上连接=0。
所以:
class ZeroLabels(tf.keras.metrics.Metric):
def __init__(self, *args, **kwargs):
super(ZeroLabels, self).__init__(name="ZeroLabels")
# Define a variable with unknown shape. This will allow you have dynamically sized variables (validate_shape=False)
self.labels = tf.Variable([], shape=(None,), validate_shape=False)
def update_state(self, y_true, y_pred, sample_weight=None):
# On update method, just assign as new value the prevoius one joined with y_true
self.labels.assign(tf.concat([self.labels.value(), y_true[:,0]], axis=0))
def result(self):
return tf.reduce_sum(tf.cast(self.labels.value() == 0, dtype=tf.int32))
def reset_states(self):
# To reset the metric, assign again an empty tensor
self.labels.assign([])
Run Code Online (Sandbox Code Playgroud)
但是,如果您只计算数据集的 0,我建议您使用一个整数变量来计算这些元素,因为在每批处理后,标签数组都会增加其大小并获取其所有元素的总和时间越来越长,训练速度减慢。
class ZeroLabels_2(tf.keras.metrics.Metric):
"""Accumulates a list of all y_true sparse categorical labels (ints) and calculates the number of times the '0' label has appeared."""
def __init__(self, *args, **kwargs):
super(ZeroLabels_2, self).__init__(name="ZeroLabels")
# Define an integer variable
self.labels = tf.Variable(0, dtype=tf.int32)
def update_state(self, y_true, y_pred, sample_weight=None):
# Increase variable with every batch
self.labels.assign_add(tf.cast(tf.reduce_sum(tf.cast(y_true == 0, dtype=tf.int32)), dtype=tf.int32 ))
def result(self):
# Simply return variable's content
return self.labels.value()
def reset_states(self):
self.labels.assign(0)
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮助你(并对英语水平表示歉意)
| 归档时间: |
|
| 查看次数: |
1294 次 |
| 最近记录: |