Tensorflow 如何正确使用tf.metrics.accurity?

Tensorflow 如何正确使用tf.metrics.accurity?,tensorflow,Tensorflow,我在使用tf.metrics中的accurity函数处理以logits作为输入的多重分类问题时遇到一些问题 我的模型输出如下所示: logits = [[0.1, 0.5, 0.4], [0.8, 0.1, 0.1], [0.6, 0.3, 0.2]] 我的标签是一个热编码向量: labels = [[0, 1, 0], [1, 0, 0], [0, 0, 1]] 当我尝试做类似于tf.metrics.accur

我在使用
tf.metrics
中的
accurity
函数处理以logits作为输入的多重分类问题时遇到一些问题

我的模型输出如下所示:

logits = [[0.1, 0.5, 0.4],
          [0.8, 0.1, 0.1],
          [0.6, 0.3, 0.2]]
我的标签是一个热编码向量:

labels = [[0, 1, 0],
          [1, 0, 0],
          [0, 0, 1]]
当我尝试做类似于
tf.metrics.accurity(标签、登录)的事情时,
永远不会给出正确的结果。我显然做错了什么,但我不知道是什么原因。

TL;DR

精度函数根据它创建的两个局部变量计算预测与标签匹配的频率:
total
count
,用于计算
logits
标签匹配的频率

acc, acc_op = tf.metrics.accuracy(labels=tf.argmax(labels, 1), 
                                  predictions=tf.argmax(logits,1))

print(sess.run([acc, acc_op]))
print(sess.run([acc]))
# Output
#[0.0, 0.66666669]
#[0.66666669]
  • acc(准确度):仅使用
    total
    count
    返回指标,不更新指标
  • acc_op(更新):更新指标
要了解acc返回
0.0
的原因,请查看以下详细信息


使用一个简单示例详细说明:

logits = tf.placeholder(tf.int64, [2,3])
labels = tf.Variable([[0, 1, 0], [1, 0, 1]])

acc, acc_op = tf.metrics.accuracy(labels=tf.argmax(labels, 1),   
                                  predictions=tf.argmax(logits,1))
初始化变量:

logits = tf.placeholder(tf.int64, [2,3])
labels = tf.Variable([[0, 1, 0], [1, 0, 1]])

acc, acc_op = tf.metrics.accuracy(labels=tf.argmax(labels, 1),   
                                  predictions=tf.argmax(logits,1))
由于
metrics.accurity
创建了两个局部变量
total
count
,我们需要调用
local\u variables\u initializer()
来初始化它们

sess = tf.Session()

sess.run(tf.local_variables_initializer())
sess.run(tf.global_variables_initializer())

stream_vars = [i for i in tf.local_variables()]
print(stream_vars)

#[<tf.Variable 'accuracy/total:0' shape=() dtype=float32_ref>,
# <tf.Variable 'accuracy/count:0' shape=() dtype=float32_ref>]
上面的精度返回0.0,因为
total
count
是零,尽管给出了匹配的输入

print('ops:', sess.run(acc_op, {logits:[[0,1,0],[1,0,1]]})) 
#ops: 1.0

print('[total, count]:',sess.run(stream_vars)) 
#[total, count]: [2.0, 2.0]
使用新输入,在调用更新op时计算精度。注意:由于所有的logit和label匹配,我们得到的精度为1.0,局部变量
total
count
实际给出了正确预测的
总计
和进行的
总计比较

现在,我们使用新的输入(而不是更新ops)调用
accurity

精度调用不使用新的输入更新度量,它只使用两个局部变量返回值。注意:在这种情况下,登录和标签不匹配。现在再次调用更新操作:

print('op:',sess.run(acc_op,{logits:[[0,1,0],[0,1,0]]}))
#op: 0.75 
print('[total, count]:',sess.run(stream_vars)) 
#[total, count]: [3.0, 4.0]
指标将更新为新的输入



有关如何在培训期间使用指标以及如何在验证期间重置指标的更多信息,请参见。

应用于cnn,您可以写:

x_len=24*24
y_len=2

x = tf.placeholder(tf.float32, shape=[None, x_len], name='input')

fc1 = ... # cnn's fully connected layer
keep_prob = tf.placeholder(tf.float32, name='keep_prob')
layer_fc_dropout = tf.nn.dropout(fc1, keep_prob, name='dropout')

y_pred = tf.nn.softmax(fc1, name='output')
logits = tf.argmax(y_pred, axis=1)

y_true = tf.placeholder(tf.float32, shape=[None, y_len], name='y_true')
acc, acc_op = tf.metrics.accuracy(labels=tf.argmax(y_true, axis=1), predictions=tf.argmax(y_pred, 1))


sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())

def print_accuracy(x_data, y_data, dropout=1.0):
    accuracy = sess.run(acc_op, feed_dict = {y_true: y_data, x: x_data, keep_prob: dropout})
    print('Accuracy: ', accuracy)

将答案扩展到TF2.0,本教程在此清楚地解释了如何使用tf.metrics提高准确性和损失。

请注意,它提到在每个历元之后重置度量:

train\u loss.reset\u states()
列车精度。复位状态()
测试丢失。重置状态()
测试精度。重置状态()
当标签和预测是一个热编码时

def系列步骤(功能、标签):
使用tf.GradientTape()作为磁带:
预测=模型(特征)
损失=tf.reduce_平均值(tf.nn.softmax_交叉_熵_与_logits(标签=标签,logits=预测))
梯度=磁带梯度(损失、模型、可训练的重量)
优化器。应用_梯度(zip(梯度、模型、可训练的_权重))
列车损耗(损耗)
列车精度(tf.argmax(标签,1),tf.argmax(预测,1))

在TF 2.0上,如果您使用的是TF.keras API,则可以定义一个自定义类MyAccurance,该类继承自TF.keras.metrics.Accurance,并覆盖如下更新方法:

#导入
# ...
类别MyAccurance(tf.keras.metrics.Accurance):
def更新状态(自身、y_真、y_pred、样本重量=无):
y_true=tf.argmax(y_true,1)
y_pred=tf.argmax(y_pred,1)
返回超级(MyAccurance,self)。更新状态(y_true,y_pred,样本重量)
然后,在编译模型时,您可以按照通常的方式添加度量

从my_awesome_模型导入鉴别器
discriminador.compile(tf.keras.optimizers.Adam(),
损耗=tf.nn.softmax\u交叉\u熵\u与逻辑,
指标=[MyAccurance()])
从my_puzzling_数据集导入train_数据集、test_数据集
discriminador.fit(训练数据集.shuffle(70000).repeat().batch(1000),
历元=1,每历元步长=1,
验证数据=测试数据集。随机(70000)。批量(1000),
验证(步骤=1)
#培训1步,验证1步
#1/1[===========================================================================3s/步-损耗:0.1502-精度:0.9490-val_损耗:0.1374-val_精度:0.9550
或者在整个数据集上评估yout模型

discriminador.evaluate(测试数据集.batch(TST数据集长度))
#> [0.131587415933609, 0.95354694]

您希望在最后一个维度上获得最大值,因此它应该是
tf.argmax(logits,1)
tf.argmax(labels,1)
并且我认为您得到了
labels
predictions
混合,我对为什么必须运行
acc
操作两次感到困惑?当我测试这段代码时,似乎确实需要这样做,否则acc将不包含精度张量,尽管文档中明确指出:
accurity:表示精度的张量,total的值除以count
@gyre你可以找到解释,但底线是我们正在努力使它更直观
tf.contrib.metrics.accurity
似乎工作得更好。我发现这对于理解tf.metrics.accurity()的实际功能非常有用。
x_len=24*24
y_len=2

x = tf.placeholder(tf.float32, shape=[None, x_len], name='input')

fc1 = ... # cnn's fully connected layer
keep_prob = tf.placeholder(tf.float32, name='keep_prob')
layer_fc_dropout = tf.nn.dropout(fc1, keep_prob, name='dropout')

y_pred = tf.nn.softmax(fc1, name='output')
logits = tf.argmax(y_pred, axis=1)

y_true = tf.placeholder(tf.float32, shape=[None, y_len], name='y_true')
acc, acc_op = tf.metrics.accuracy(labels=tf.argmax(y_true, axis=1), predictions=tf.argmax(y_pred, 1))


sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())

def print_accuracy(x_data, y_data, dropout=1.0):
    accuracy = sess.run(acc_op, feed_dict = {y_true: y_data, x: x_data, keep_prob: dropout})
    print('Accuracy: ', accuracy)