目录
1 分类任务
1.1 multi-class
在分类任务中,multi-class分类,一个样本只对应一个label。假设分类任务中总label数量为
N
N
N,则每个样本对应的标签label转成one-hot形式为
[
0
,
0
,
.
.
,
1..0
]
[0,0,..,1..0]
[0,0,..,1..0],是一个长度为
N
N
N的向量,且只有一个1代表了索引对应的label位置。
tensorflow里针对multi-class计算loss函数主要有三个:
- tf.nn.softmax_cross_entropy_with_logits
- tf.nn.softmax_cross_entropy_with_logits_v2
- tf.losses.softmax_cross_entropy
代码例子如下:
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=one_hot_y)
loss = tf.reduce_mean(cross_entropy)
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
# metric
prob = tf.nn.softmax(logits, name='prob')
predictions = tf.argmax(prob, axis=1, name='predictions')
accuracy = tf.reduce_mean(tf.cast(tf.equal(predictions,y_true), tf.float32))
说明:tf.nn.softmax_cross_entropy_with_logits_v2相对 tf.nn.softmax_cross_entropy_with_logits区别在于BP反向计算梯度的时候,不仅会作用于logits还会作用于labels (比如对抗学习任务),而tf.nn.softmax_cross_entropy_with_logits只会作用于labels。不过当labels是placeholders的时候,用tf.nn.softmax_cross_entropy_with_logits_v2与tf.nn.softmax_cross_entropy_with_logits没区别,因为placeholder形式没有参数可以求梯度的。
1.2 multi-label
在mulit-label分类中,与multi-class的区别是,一个样本可能对应多个label,label转成one-hot形式
[
0
,
1
,
.
.
,
1..0
]
[0,1,..,1..0]
[0,1,..,1..0],长度为
N
N
N的向量,有1个或者多个1,分别代表了索引位置对应的多个label。
tensorflow提供的计算loss函数如下:
- tf.nn.sigmoid_cross_entropy_with_logits
- tf.nn.weighted_cross_entropy_with_logits
- tf.losses.sigmoid_cross_entropy
代码例子如下:
cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=one_hot_y)
loss = tf.reduce_mean(tf.reduce_sum(cross_entropy, axis=1))
prediction = tf.sigmoid(logits)
output = tf.cast(prediction >threshold, tf.int32)
train_op = tf.train.AdamOptimizer(0.001).minimize(loss)
2 multi-label分类方法
2.1 多个独立的二分类器
可以把multi-label分类用
N
N
N个独立的二分类器来做
N
N
N个multi-label的分类。最后一层包含了
N
N
N个独立的sigmoi (logistics) 激活函数,通过一个阈值threshold来输出多个类别。如下图所示:
2.1.1 小结
方法容易理解,模型也较容易训练,但忽视了label与label之间的语义关系,比如在上图中,"Woman"类和“Girl”类就存在一定的相似性,但是因为每个二分类器都是一个独立的分类器,每个label的预测不会考虑其它label之间的关系。
2.2 KNN方式
训练模型学习样本与label是否匹配任务来做分类,主要形式有两种:
- 第一:将样本和label拼接成一句话输入模型,最后一层是一个二分类器
- 第二:训练一个双塔模型,提取样本和label的特征向量,计算向量相似性来判断样本与label的匹配
上面两个方法主要都是让模型有区分样本是否和label匹配的问题,类似问模型这样一个问题:“这张图是狗还是不是?”
2.2.1 小结
样本制作考虑问题较多,比如负样本采样等问题,同时预测的时候需要对样本和每个label组合的pair对都进行一次预测,复杂度较高。
2.3 seq2seq方式
这种方式利用seq2seq框架,类似机器翻译任务,只是这里对输入 x x x进行编码,通过解码器来预测对应的 y y y label序列。该方法可以学习label与label之间的关系,如上面提到的,"woman"类别和"girl"类别是有相关性的,seq2seq在解码阶段可以对label与label之间的关系进行学习
2.3.1 小结
seq2seq模型相对计算复杂度较高,同时由于seq2seq在解码阶段本身存在语言连贯性挑战等问题
3 如何提高extreme multi-label或者multi-class分类速度
extreme multi-label或者multi-class主要挑战任务是需要对样本从很大的一个label空间中预测相关的label集,比如文本分类任务中,维基百科有将近50w的分类label,亚马逊有将近1.3万的label。由于很大的label空间,频率很低的label数据样本不足,导致数据稀疏,类别样本不平衡问题严重,训练复杂度也较高
3.1 候选采样 (Candidate Sampling)
在multi-class或者multi-label任务中,每个训练样本
(
x
i
,
T
i
)
(x_i, T_i)
(xi,Ti),由上下文
x
i
x_i
xi和对应的正labels
T
i
T_i
Ti组成,其中
T
i
T_i
Ti是总label集合的
L
L
L的小部分,我们希望学习一个函数
F
(
x
,
y
)
F(x,y)
F(x,y),预测
x
x
x对应每个
y
y
y类别的概率。由于对每个
y
∈
L
y \in L
y∈L,我们都需要计算
F
(
x
,
y
)
F(x,y)
F(x,y)概率值,当
∣
L
∣
\begin{vmatrix} L\end{vmatrix}
∣∣L∣∣很大时,计算代价将会十分大。候选集采样方法针对每个样本
(
x
i
,
T
i
)
(x_i, T_i)
(xi,Ti),我们只需要计算
F
(
x
,
y
)
F(x,y)
F(x,y),对于一小部分的候选类别
C
i
⊂
L
C_i \subset L
Ci⊂L的概率值,一般
C
i
C_i
Ci是由其中正label
T
i
T_i
Ti和随机采样label
S
i
⊂
L
S_i \subset L
Si⊂L组成的,即:
C
i
=
T
i
∪
S
i
C_i = T_i \cup S_i
Ci=Ti∪Si
下面是一些候选集不同采样算法的对比情况:
正label | 负采样label | 训练loss | |
---|---|---|---|
Noise Contrastive Estimation(NCE) | T i T_i Ti | S i S_i Si | Logistic |
Negative Sampling | T i T_i Ti | S i S_i Si | Logistic |
Sampled Logistic | T i T_i Ti | ( S i − T i ) (S_i-T_i) (Si−Ti) | Logistic |
Full Logistic | T i T_i Ti | ( L − T i ) (L-T_i) (L−Ti) | Logistic |
Full Softmax | T i = t i T_i={t_i} Ti=ti | ( L − T i ) (L-T_i) (L−Ti) | Softmax |
Sampled Softmax | T i = t i T_i={t_i} Ti=ti | ( S i − T i ) (S_i-T_i) (Si−Ti) | Softmax |
NCE,Negative Sampling和Sampled Softmax都是通过对负label进行采样,缩减
F
(
x
,
y
)
F(x,y)
F(x,y)在整个label集
∣
L
∣
\begin{vmatrix} L \end{vmatrix}
∣∣L∣∣的计算。
下面是NCE在tensorflow里提供的计算loss函数形式:
tf.nn.nce_loss(weights = nec_weights, #[num_classes, dim]最后分类层权重参数
biases = nec_biases, #[num_classes] 分类偏差
labels = train_labels, # [batch_size, num_true] 输入的标签
inputs = embed, #[batch_size, dim] 输入的向量
num_sampled = num_sampled, # int 负采样个数
num_classes = num_classes, # int 分类的总类别数
num_true = num_true) # int 样本的正样本数
3.2 hierarchical softmax
层级softmax速度优化主要思想是对分类label ∣ L ∣ \begin{vmatrix} L \end{vmatrix} ∣∣L∣∣进行哈夫曼编码,则每个label的计算复杂度由 O ( L ) O(L) O(L)降低到 O ( l o g 2 L ) O(log_2L) O(log2L),具体原理和实现可以参考我的上一篇层次softmax (hierarchical softmax)理解 博文
4 参考
Noise-contrastive estimation: A new estimation principle for
unnormalized statistical models
What is Candidate Sampling
https://github.com/tensorflow/tensorflow/blob/r1.2/tensorflow/python/ops/nn_impl.py#L1269