零样本学习新进展:隐含特征的判别性学习
Discriminative Learning of Latent Features for Zero-Shot Recognition
Discriminative Learning of Latent Features for Zero-Shot Recognition
ZSL
零样本学习(zero-shot learning, ZSL)详见郑哲东在知乎中的回答。它的目标是通过训练阶段从已见类别中学到的知识,来识别未见类别。
Abstract
摘要:零样本学习(ZSL)的目标是通过学习图像表示和语义表示之间的嵌入空间来识别未见类图像的。多年来,在现有的研究成果中,中心任务都是学习对齐视觉空间和语义空间的合适映射矩阵,而忽略了学习ZSL 的鉴别性表示表征的重要性。本工作中,我们回顾了已有方法,证明了为 ZSL的视觉实例和语义实例学习鉴别性表示的必要性。我们提出了一种端到端的网络,能够做到:1)通过放大网络自动发现鉴别性区域;2)在引入用户定义属性和隐含属性的增强空间中学习鉴别性语义表示。我们提出的方法在两个很有挑战性的ZSL 数据集上进行了大量测试,实验结果表明我们提出的方法的表现显著优于之前最佳的方法。
解读:已有工作要学习一个好的W来对齐特征F和语义A。本文旨在学习更好的F和更好的A,即文中提到的判别性F和判别性A。
Introduction
已有方案的缺点(drawbacks):
1,特征对ZSL任务表示性不足: 在映射前,抽取图像的特征,传统的用预训练模型等方法仍不是针对ZSL特定抽取特征的最优解。
2,用户定义属性不全面: 现有的都是学习用户定义属性,而忽略了隐含表示。
3,分类训练不能充分挖掘潜力: 低层次信息和空间是分离训练的,没有大一统的框架。
本文贡献:
- 一种级联式放大机制,可用于学习以目标为中心的区域的特征。我们的模型可以自动识别图像中最具鉴别性的区域,然后在一个级联式的网络结构中将其放大以便学习。通过这种方式,我们的模型可以专注于从以目标为焦点的区域中学习特征。
- 一种用于联合学习隐含属性和用户定义属性的框架。我们将隐含属性的学习问题形式化为了一个类别排序问题,以确保所学习到的属性是鉴别性的。同时,在我们模型中,鉴别性区域的发掘和隐含属性的建模是联合学习的,这两者会互相协助以实现进一步的提升。
- 一种用于 ZSL 的端到端网络结构。所获得的图像特征可以调整得与语义空间更加兼容,该空间中既包含用户定义的属性,也包含隐含的鉴别性属性。
Latent Discriminative Features Learning(LDF)
Notation:
FNet (The Image Feature Network) :提取图像特征;
ZNet(The Zoom Network): 定位最具判别性的区域并将其放大;
ENet(The Embedding Network): 将图像特征映射到另一个空间。
问题
1. ZNet是如何定位判别性区域的?
循环注意力机制
下面我们先介绍各个子网络
FNet
FNet的目标就是提取图像特征。文章选择了已有的VGG19/GoogleNet。
ZNet
已有研究表明对目标的区域进行学习,有利于图像级的目标分类。受此启发,我们假设图像中存在判别性区域有助于ZSL。
ZNet的目标是定位到能够增强我们提取的特征的辨识度的区域,这个区域同时也要与某一个我们已经定义好了的属性对应。
- ZNet的输入是FNet的最后一个卷积层的输出。
- 在这里运用某个已有的激活函数方法,将我们定位好了的区域提取出来,即将裁剪操作在网络中直接实现。
- 将ZNet的输出与输入图像做按像素的矩阵乘法。
- 最后,将区域放大到与输入图像相同的尺寸。
如图2所示,再将ZNet的输出输入到另一个FNet(第一个FNet的拷贝)
ENet
ENet的目的是学习一个能够将视觉和语义信息关联起来的嵌入空间。
作者提出了一个兼容性得分。
s
=
<
W
T
ϕ
(
x
)
,
a
y
>
(5)
s = < W^T \phi(x), a^y > \tag{5}
s=<WTϕ(x),ay>(5)
其中, ϕ ( x ) \phi(x) ϕ(x)是FNet输出的 d d d维的图像表示, a y a^y ay是k维的属性向量。
兼容性得分的物理意义是什么?
答:The compatibility score measures the similarity between an image and the attribute annotations of classes. It is similar to the classification score in traditional object recognition task.
衡量一张图像和类别的属性标注之间的相似性(兼容性)。类似于传统目标识别任务中的分类得分。
Enet将图像特征映射到 2 k 2k 2k 维的属性空间。其中, 1 k 1k 1k 维对应用户定义属性(UA),并用softmax loss; 1 k 1k 1k 维对应隐含属性,为了使这些特征具有判别性,作者使用了triplet loss。
为什么UA是softmax loss,而LA是triplet loss?
答:图像有UA标注,没有LA标注。LA是学出来的。triplet loss是无监督学习的loss。
如何学习2k维属性的?
答:控制全连接层的参数,将特征映射到2k维。
ZSL Prediction
Predition with LA
-
对于一个已见类 s s s:
s在UA空间中的类中心为 a s \mathbf{a}^{s} as,
s在LA空间中的类中心为所有样本LA特征的平均值
ϕ l a t s ‾ = 1 N ∑ i ϕ l a t ( x i ) \overline{\phi_{lat}^{s}} = \frac{1}{N} \sum_i \phi_{lat}(x_i) ϕlats=N1i∑ϕlat(xi) -
对于一个未见类 u u u:
计算未见类 u ∈ Y U u \in \mathcal{Y}_U u∈YU和已见类 c ∈ Y S c \in \mathcal{Y}_S c∈YS在UA空间中的关系系数 β u \beta^{u} βu,使得 a u = β u a c \mathbf{a}^{u} = \beta^{u} \mathbf{a}^{c} au=βuac。
β c u = arg min ∣ ∣ a u − ∑ β c u a c ∣ ∣ 2 2 + λ ∣ ∣ β c u ∣ ∣ 2 2 , c ∈ Y S (14) \beta_{c}^{u} = \arg \min || \mathbf{a}^{u} - \sum \beta_{c}^{u} \mathbf{a}^{c} ||_{2}^{2} + \lambda || \beta_{c}^{u} ||_{2}^{2}, c \in \mathcal{Y}_S \tag{14} βcu=argmin∣∣au−∑βcuac∣∣22+λ∣∣βcu∣∣22,c∈YS(14) -
计算LA空间中 u u u的表示:
假设未见类 u u u和已见类在UA空间中的关系与其在LA空间的关系一致。
ϕ l a t u ‾ = ∑ β c u ϕ l a t c ‾ , c ∈ Y S (15) \overline{ \phi_{lat}^u} = \sum \beta_c^u { \overline {\phi_{lat}^c} }, c \in \mathcal{Y}_S \tag{15} ϕlatu=∑βcuϕlatc,c∈YS(15)
学习用户定义属性空间中已见类和未见类关系,然后应用到隐含属性空间中的已见类,得到未见类的隐含属性。
首先,已知UA空间中已见类属性表示和未见类属性表示,求得关系
β
c
u
\beta_{c}^{u}
βcu;
然后,学到LA空间中已见类属性表示,应用关系
β
c
u
\beta_{c}^{u}
βcu,得到未见类在LA空间中的属性表示。
Reference
1.paper
code
补充材料
2.论文笔记1 - 知乎
3.论文笔记2 - RexKing6’s Note
4.论文笔记3 - 雪花新闻
5.什么是 One/zero-shot learning?
Q&A
1. 隐含特征的“特征”指的是视觉特征吗?
就是隐含的属性特征。
2. [4.1] Fnet对性能的提升有多大?
表1,AwA(CUB)数据集上有4%(9%)的提升。
3. [4.2] ZNet是如何使得到的区域,既有判别性,又有语义信息?
直观想法:目标区域期望包含一些背景信息来增强属性嵌入。通过放大网络来实现。
判别性,来自注意力机制;语义,来自于视觉语义映射。
4. [4.2] 逐元素乘法的作用?
放大网络里的技巧。
5. [Table 1] VGG比GoogLeNet好?
6. [Appendices] A U → T A_{U \rightarrow T} AU→T 和 A S → T A_{S \rightarrow T} AS→T 是怎么计算的?
7. 实验中,cZSL设定下
M
C
A
MCA
MCA在50%左右,为什么gZSL中的
M
C
A
t
MCA_t
MCAt只有不到20%?
代码阅读
train_ldf.py
feature = tf.squeeze(feature, axis=[1, 2])
print('feature shape:', feature)
feature = slim.dropout(feature, keep_prob=0.5)
# 计算相容性得分
logits = slim.fully_connected(feature, num_outputs=2 * FLAGS.attribute_label_cnt, activation_fn=None)
print('logits shape', logits)
loss.py
def build_multi_loss_3(logits, gt_onehot_labels, whole_attr_labels, num_labels, margin, squared=False,
triplet_strategy='batch_hard', optimizer='Adam', freeze=False, variable_to_train=None):
y_conv = tf.reshape(logits, [-1, 2 * FLAGS.attribute_label_cnt])
y_conv_softmax = y_conv[:, 0:FLAGS.attribute_label_cnt]
y_conv_triplet = y_conv[:, FLAGS.attribute_label_cnt:2 * FLAGS.attribute_label_cnt]
print(y_conv, y_conv_softmax, y_conv_triplet)
# build softmax loss 分类损失
# (16,30) x (230,30).T output (16, 230), compatibility score
whole_inner_product = tf.matmul(y_conv_softmax, tf.transpose(whole_attr_labels))
with tf.name_scope('softmax_loss_with_score'):
softmax_loss_with_score = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(logits=whole_inner_product, labels=gt_onehot_labels))
tf.summary.scalar('softmax_loss_with_score', softmax_loss_with_score)
# Define triplet loss 三元组损失
with tf.name_scope('triplet_loss'):
if triplet_strategy == "batch_all":
triplet_loss, fraction = batch_all_triplet_loss(labels=num_labels,
embeddings=y_conv_triplet,
margin=margin,
squared=squared)
tf.summary.scalar('triplet_loss', triplet_loss)
elif triplet_strategy == "batch_hard":
triplet_loss = batch_hard_triplet_loss(labels=num_labels,
embeddings=y_conv_triplet,
margin=margin,
squared=squared)
tf.summary.scalar('triplet_loss', triplet_loss)
else:
raise ValueError("Triplet strategy not recognized: {}".format(triplet_strategy))
with tf.name_scope('multi_loss'):
multi_loss = softmax_loss_with_score + triplet_loss
tf.summary.scalar('multi_loss', multi_loss)
with tf.variable_scope('train_multi_loss'):
global_step = tf.train.get_or_create_global_step()
lr = tf.train.exponential_decay(FLAGS.learning_rate,
global_step=global_step,
decay_rate=FLAGS.lr_decay_rate,
decay_steps=FLAGS.lr_decay_step)
tf.summary.scalar('learning_rate_multi', lr)
if freeze:
optimizer_2 = tf.train.AdamOptimizer(lr)
train_op = tf.contrib.slim.learning.create_train_op(multi_loss, optimizer_2,
variables_to_train=variable_to_train)
else:
train_op = tf.contrib.layers.optimize_loss(loss=multi_loss,
global_step=global_step,
learning_rate=lr,
optimizer=optimizer)
return multi_loss, train_op