使用 TensorFlow 的多标签文本分类
Posted
技术标签:
【中文标题】使用 TensorFlow 的多标签文本分类【英文标题】:Multilabel Text Classification using TensorFlow 【发布时间】:2016-05-25 19:32:19 【问题描述】:文本数据组织为具有 20,000 个元素的向量,例如 [2, 1, 0, 0, 5, ...., 0]。 第 i 个元素表示文本中第 i 个单词的频率。
ground truth 标签数据也表示为具有 4,000 个元素的向量,例如 [0, 0, 1, 0, 1, ...., 0]。 第 i 个元素指示第 i 个标签是否是文本的正标签。 文本的标签数量因文本而异。
我有一个用于单标签文本分类的代码。
如何为多标签文本分类编辑以下代码?
特别想知道以下几点。
如何使用 TensorFlow 计算准确度。 如何设置判断标签是正面还是负面的阈值。例如,如果输出为 [0.80, 0.43, 0.21, 0.01, 0.32],ground truth 为 [1, 1, 0, 0, 1],则得分超过 0.25 的标签应被判断为正。谢谢。
import tensorflow as tf
# hidden Layer
class HiddenLayer(object):
def __init__(self, input, n_in, n_out):
self.input = input
w_h = tf.Variable(tf.random_normal([n_in, n_out],mean = 0.0,stddev = 0.05))
b_h = tf.Variable(tf.zeros([n_out]))
self.w = w_h
self.b = b_h
self.params = [self.w, self.b]
def output(self):
linarg = tf.matmul(self.input, self.w) + self.b
self.output = tf.nn.relu(linarg)
return self.output
# output Layer
class OutputLayer(object):
def __init__(self, input, n_in, n_out):
self.input = input
w_o = tf.Variable(tf.random_normal([n_in, n_out], mean = 0.0, stddev = 0.05))
b_o = tf.Variable(tf.zeros([n_out]))
self.w = w_o
self.b = b_o
self.params = [self.w, self.b]
def output(self):
linarg = tf.matmul(self.input, self.w) + self.b
self.output = tf.nn.relu(linarg)
return self.output
# model
def model():
h_layer = HiddenLayer(input = x, n_in = 20000, n_out = 1000)
o_layer = OutputLayer(input = h_layer.output(), n_in = 1000, n_out = 4000)
# loss function
out = o_layer.output()
cross_entropy = -tf.reduce_sum(y_*tf.log(out + 1e-9), name='xentropy')
# regularization
l2 = (tf.nn.l2_loss(h_layer.w) + tf.nn.l2_loss(o_layer.w))
lambda_2 = 0.01
# compute loss
loss = cross_entropy + lambda_2 * l2
# compute accuracy for single label classification task
correct_pred = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, "float"))
return loss, accuracy
【问题讨论】:
我认为除了交叉熵之外可能还有更好的损失函数。 对于多标签分类问题,有许多不同的准确度度量:单错误准确度、排名损失、平均平均准确度等。我自己还在学习 TensorFlow,还没有设法正确实现他们中的任何一个。但也许这篇论文会对你有所帮助:arxiv.org/pdf/1312.5419v3.pdf 如果你有任何进展,请告诉我! 为了更好地了解准确率,请考虑计算准确率和召回率。 @Benbeny_
是什么@我没有看到它定义
【参考方案1】:
将relu更改为输出层的sigmoid。 将交叉熵损失修改为 sigmoid 交叉熵损失的显式数学公式(显式损失在我的案例/张量流版本中起作用)
import tensorflow as tf
# hidden Layer
class HiddenLayer(object):
def __init__(self, input, n_in, n_out):
self.input = input
w_h = tf.Variable(tf.random_normal([n_in, n_out],mean = 0.0,stddev = 0.05))
b_h = tf.Variable(tf.zeros([n_out]))
self.w = w_h
self.b = b_h
self.params = [self.w, self.b]
def output(self):
linarg = tf.matmul(self.input, self.w) + self.b
self.output = tf.nn.relu(linarg)
return self.output
# output Layer
class OutputLayer(object):
def __init__(self, input, n_in, n_out):
self.input = input
w_o = tf.Variable(tf.random_normal([n_in, n_out], mean = 0.0, stddev = 0.05))
b_o = tf.Variable(tf.zeros([n_out]))
self.w = w_o
self.b = b_o
self.params = [self.w, self.b]
def output(self):
linarg = tf.matmul(self.input, self.w) + self.b
#changed relu to sigmoid
self.output = tf.nn.sigmoid(linarg)
return self.output
# model
def model():
h_layer = HiddenLayer(input = x, n_in = 20000, n_out = 1000)
o_layer = OutputLayer(input = h_layer.output(), n_in = 1000, n_out = 4000)
# loss function
out = o_layer.output()
# modified cross entropy to explicit mathematical formula of sigmoid cross entropy loss
cross_entropy = -tf.reduce_sum( ( (y_*tf.log(out + 1e-9)) + ((1-y_) * tf.log(1 - out + 1e-9)) ) , name='xentropy' )
# regularization
l2 = (tf.nn.l2_loss(h_layer.w) + tf.nn.l2_loss(o_layer.w))
lambda_2 = 0.01
# compute loss
loss = cross_entropy + lambda_2 * l2
# compute accuracy for single label classification task
correct_pred = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, "float"))
return loss, accuracy
【讨论】:
【参考方案2】:您必须使用其他交叉熵函数的变体来支持多标签分类。如果您的输出少于一千个,您应该使用sigmoid_cross_entropy_with_logits,如果您有 4000 个输出,您可以考虑使用candidate sampling,因为它比以前更快。
如何使用 TensorFlow 计算准确度。
这取决于您的问题以及您想要实现的目标。如果您不想错过图像中的任何对象,那么如果分类器除了一个对象之外没有问题,那么您应该将整个图像视为错误。您还可以认为错过或未分类的对象是错误。后者我认为它由 sigmoid_cross_entropy_with_logits 支持。
如何设置判断一个标签是正面还是正面的阈值 消极的。例如,如果输出为 [0.80, 0.43, 0.21, 0.01, 0.32],ground truth 为 [1, 1, 0, 0, 1],得分超过 0.25 的标签应判断为正。
门槛是一种方法,你必须决定哪一种。但这是某种 hack,而不是真正的多标签分类。为此,您需要我之前所说的先前功能。
【讨论】:
我不知道为什么人们建议使用 'sigmoid_cross_entropy_with_logits'。如果它是它的名字所暗示的,即 -Y*ln(sigmoid(logits)) 。然后它会通过给每个班级高概率来最小化损失,事实上在我的情况下它就是这样。 此函数不返回概率。而且我看不出它会如何通过提供高价值来最大限度地减少损失。如果将类设置为 1,当类不存在时设置为 0,则当对象不在图像中时网络给出接近 0 的值,如果对象在图像中,则值接近 1 或更大(甚至 2 o 3)图片。我正在使用它并且效果很好。 它将通过为每个类赋予高值来最小化损失,因为对标记为 0 的类赋予高值没有惩罚(或 0 损失)。因此需要修改交叉熵损失具有二进制交叉熵 (y * ln(sigmoid(logits)) + 1-y * ln(sigmoid(1-logits))) 。 sigmoid_cross_entropy_with_logits 内部没有实现二进制交叉熵。我很惊讶为什么它在你的情况下工作,你在使用 theano 等 我认为你的数学有问题。它是: y * ln(sigmoid(logits)) + (1-y) * ln(1-sigmoid(logits)) 所以: logits=0, y=0 => 0 ;对数=1,y=1 => 0;对数=1,y=0 => 1.3;对数=0,y=1 => 1.3;您可以在 google 中使用数字绘制函数。只需搜索 y*-ln (1 / ( 1 + e^-x)) +(1-y)*-ln (1-1 / ( 1 + e^-x)) 我的错,忽略我上面的数学。这是我正在使用的,对我有用的 -tf.reduce_mean(tf.mul(y,tf.log(tf.nn.sigmoid(logits) + 1e-9)) + tf.mul(1-y,tf .log(1 - tf.nn.sigmoid(logits) + 1e-9))) 。这有效,而您的建议无效,如果我的论点有误,请告诉我以上是关于使用 TensorFlow 的多标签文本分类的主要内容,如果未能解决你的问题,请参考以下文章