Python 更新TensorFlow自定义度量的内部状态(即在度量计算中使用非更新状态变量)
版本:python 3.8.2(我也尝试过3.6.8,但我认为python版本在这里并不重要)、tensorflow 2.3.0、numpy 1.18.5 我正在用稀疏标签张量训练一个分类问题的模型。我如何定义一个度量来计算“0”标签在该点之前出现的次数?在下面的代码示例中,我试图存储度量在数组中看到的所有标签,并在每次调用Python 更新TensorFlow自定义度量的内部状态(即在度量计算中使用非更新状态变量),python,tensorflow,graph,metrics,Python,Tensorflow,Graph,Metrics,版本:python 3.8.2(我也尝试过3.6.8,但我认为python版本在这里并不重要)、tensorflow 2.3.0、numpy 1.18.5 我正在用稀疏标签张量训练一个分类问题的模型。我如何定义一个度量来计算“0”标签在该点之前出现的次数?在下面的代码示例中,我试图存储度量在数组中看到的所有标签,并在每次调用update\u state时将现有数组与新的y\u true连接起来。(我知道我可以只存储一个count变量并使用+=,但在实际使用场景中,串联是理想的,内存不是问题。)下
update\u state
时将现有数组与新的y\u true
连接起来。(我知道我可以只存储一个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)
这段代码本身就可以工作,但当我尝试使用此度量训练模型时,它会抛出以下错误:
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
我认为这可能与调用update\u state
时,self.labels
不是图形的直接部分这一事实有关。以下是我尝试过的其他一些事情:
- 存储
,tf.int32
shape=()
变量,并增加该变量,而不是连接新标签count
- 使用
将所有内容转换为numpy,并将它们连接起来(我希望强制TensorFlow不使用图形).numpy()
- 使用
和尝试
块除了上面带有numpy转换的
- 创建一个全新的类(而不是子类化
),在可能的情况下专门使用numpy,但这种方法会导致一些加载问题,即使在tf.keras.metrics.Metric
tf.keras.models.load\u model
- 使用
装饰器进行所有方法@tf.autograph.experimental.don\u not \u convert
- 修改全局变量而不是属性,并使用
关键字global
- 使用非tensorflow属性(不使用
)self.labels=self.add\u weight…
如果有帮助的话,下面是这个问题的一个更一般的版本:我们如何在
update\u state
计算中合并没有作为参数传递到update\u state
的张量?任何帮助都将不胜感激。提前谢谢你 当没有初始值时,主要问题是第一次迭代赋值:
if self.labels.shape == ():
self.labels = y_true
else:
self.labels = tf.concat((self.labels, y_true), axis=0)
在if块中,构造函数中定义的变量“labels”消失,并被tf.Tensor对象(y_true)替换。因此,您必须使用tf.Variable方法(assign、add_assing)修改其内容,但保留对象。此外,为了能够更改tf.variable形状,您必须以这样一种方式创建它,即它允许您拥有一个未定义的形状,在本例中:(无,1),因为您在轴=0上连接
因此:
但是,如果您只需要一个变量来计算数据集的0,我建议您使用一个整数变量来计算这些元素,因为在每个批处理过程之后,labels数组将增加其大小,并且获取其所有元素的总和将花费越来越多的时间,从而降低您的训练速度
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)
我希望这能帮助您(并为英语水平道歉)主要问题是第一次迭代赋值,当时没有初始值:
if self.labels.shape == ():
self.labels = y_true
else:
self.labels = tf.concat((self.labels, y_true), axis=0)
在if块中,构造函数中定义的变量“labels”消失,并被tf.Tensor对象(y_true)替换。因此,您必须使用tf.Variable方法(assign、add_assing)修改其内容,但保留对象。此外,为了能够更改tf.variable形状,您必须以这样一种方式创建它,即它允许您拥有一个未定义的形状,在本例中:(无,1),因为您在轴=0上连接
因此:
但是,如果您只需要一个变量来计算数据集的0,我建议您使用一个整数变量来计算这些元素,因为在每个批处理过程之后,labels数组将增加其大小,并且获取其所有元素的总和将花费越来越多的时间,从而降低您的训练速度
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)
我希望这能帮助你(并为英语水平道歉)