零样本学习(zero-shot learning, ZSL)详见郑哲东在知乎中的回答。它的目标是通过训练阶段从已见类别中学习到的知识,来识别未见类别。
摘要:零样本学习(ZSL)的目标是通过学习图像表示和语义表示之间的嵌入空间来识别未见类图像的。多年来,在现有的研究成果中,中心任务都是学习对齐视觉空间和语义空间的合适映射矩阵,而忽略了学习ZSL 的鉴别性表示表征的重要性。本工作中,我们回顾了已有方法,证明了为 ZSL的视觉实例和语义实例学习鉴别性表示的必要性。我们提出了一种端到端的网络,能够做到:1)通过放大网络自动发现鉴别性区域;2)在引入用户定义属性和隐含属性的增强空间中学习鉴别性语义表示。我们提出的方法在两个很有挑战性的ZSL 数据集上进行了大量测试,实验结果表明我们提出的方法的表现显著优于之前最佳的方法。
已有方案的缺点(drawbacks):
1,特征对ZSL任务表示性不足: 在映射前,抽取图像的特征,传统的用预训练模型等方法仍不是针对ZSL特定抽取特征的最优解。
2,用户定义属性不全面: 现有的都是学习用户定义属性,而忽略了隐含表示。
3,分类训练不能充分挖掘潜力: 低层次信息和空间是分离训练的,没有大一统的框架。
本文贡献:
Notation:
FNet (The Image Feature Network) :提取图像特征;
ZNet(The Zoom Network): 定位最具判别性的区域并将其放大;
ENet(The Embedding Network): 将图像特征映射到另一个空间。
问题
1. ZNet是如何定位判别性区域的?
循环注意力机制
下面我们先介绍各个子网络
FNet的目标就是提取图像特征。文章选择了已有的VGG19/GoogleNet。
已有研究表明对目标的区域进行学习,有利于图像级的目标分类。受此启发,我们假设图像中存在判别性区域有助于ZSL。
ZNet的目标是定位到能够增强我们提取的特征的辨识度的区域,这个区域同时也要与某一个我们已经定义好了的属性对应。
如图2所示,再将ZNet的输出输入到另一个FNet(第一个FNet的拷贝)
ENet的目的是学习一个能够将视觉和语义信息关联起来的嵌入空间。
作者提出了一个兼容性得分。
(5) s = < W T ϕ ( x ) , a y > 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是属性向量。
兼容性得分的物理意义是什么?
答: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是已见类的有属性/标签,隐含属性没有实际的属性。
如何学习2k维属性的?
答:学习一个W,通过调整网络中的参数。
对于源类s:
s在UA空间中的类中心为 a s \mathbf{a}^{s} as,
s在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 u u在UA空间中和其他已见类的关系。
(14) β c u = arg min ∣ ∣ a u − ∑ β c u a c ∣ ∣ 2 2 + λ ∣ ∣ β c u ∣ ∣ 2 2 , c ∈ Y S \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)
利用已见类和未见类在UA空间的关系以及已见类在LA空间的表示,计算得到LA空间中的表示。
(15) ϕ l a t u ‾ = ∑ β c u ϕ l a t u ‾ \overline{ \phi_{lat}^u} = \sum \beta_c^u { \overline {\phi_{lat}^u} } \tag{15} ϕlatu=∑βcuϕlatu(15)
首先,已知UA空间中源类的属性表示和目标类的属性表示,求得关系 β c u \beta_{c}^{u} βcu;然后,学到LA空间中源类的属性表示,应用关系 β c u \beta_{c}^{u} βcu,得到目标类在LA空间中的属性表示。
学已知属性空间中源类和目标类的关系,然后应用到隐含属性空间中的源类表示,得到目标类的隐含表示。
1.paper
code
补充材料
2.论文笔记1 - 知乎
3.论文笔记2 - RexKing6’s Note
4.论文笔记3 - 雪花新闻
5.什么是 One/zero-shot learning?
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