孪⽣⽹络⼊门(上)SiameNet及其损失函数
最近在多个关键词(⼩数据集,⽆监督半监督,图像分割,SOTA模型)的范畴内,都看到了这样的⼀个概念,孪⽣⽹络,所以今天有空⼤概翻看了⼀下相关的经典论⽂和博⽂,之后做了⼀个简单的案例来强化理解。如果需要交流的话欢迎联系我,WX:cyx645016617
所以这个孪⽣⽹络⼊门,我想着分成上下两篇,上篇也就是这⼀篇讲解模型理论、基础知识和孪⽣⽹络独特的损失函数;下篇讲解⼀下如何⽤代码来复线⼀个简单的孪⽣⽹络。
1 名字的由来
孪⽣⽹络的别名就会死Siame Net,⽽Siam是古代泰国的称呼,所以Siame其实是“泰国⼈”的古代的称呼。为什么Siame现在在英⽂中是“孪⽣”“连体”的意思呢?这源⾃⼀个典故:
⼗九世纪泰国出⽣了⼀对连体婴⼉,当时的医学技术⽆法使两⼈分离出来,于是两⼈顽强地⽣活了⼀⽣,1829年被英国商⼈发现,进⼊马戏团,在全世界各地表演,1839年他们访问美国北卡罗莱那州后来成为“玲玲马戏团” 的台柱,最后成为美国公民。
1843年4⽉13⽇跟英国⼀对姐妹结婚,恩⽣了10个⼩孩,昌⽣了12个,姐妹吵架时,兄弟就要轮流到每个⽼婆家住三天。1874年恩因肺病去世,另⼀位不久也去世,两⼈均于63岁离开⼈间。两⼈的肝⾄今仍
保存在费城的马特博物馆内。从此之后“暹罗双胞胎”(Siame twins)就成了连体⼈的代名词,也因为这对双胞胎让全世界都重视到这项特殊疾病。
2 模型结构
这个图有这⼏个点来理解:
其中的Network1和Network2按照专业的话来说就是共享权制,说⽩了这两个⽹络其实就是⼀个⽹络,在代码中就构建⼀个⽹络就⾏了;
⼀般的任务,每⼀个样本经过模型得到⼀个模型的pred,然后这个pred和ground truth进⾏损失函数的计算,然后得到梯度;这个孪⽣⽹络则改变了这种结构,假设是图⽚分类的任务,把图⽚A输⼊到模型中得到了⼀个输出pred1,然后我再把图⽚B输⼊到模型中,得到了另外⼀个输出pred2,然后我这个损失函数是从pred1和pred2之间计算出来的。就是⼀般情况下,模型运⾏⼀次,给出⼀个loss,但是在siame net中,模型要运⾏两次才能得到⼀个loss。日清日毕
我个⼈感觉,⼀般的任务像是衡量⼀种绝对的距离,样本到标签的⼀个距离;但是孪⽣⽹络衡量的是样本到样本之间的⼀个距离。
辰字五行2.1 孪⽣⽹络的⽤途
Siame net衡量的是两个输⼊的关系,也就是两个样本相似还是不相似。
有这样的⼀个任务,在NIPS上,在1993年发表了⽂章《Signature Verification using a ‘Siame’ Time Delay Neural Network》⽤于美国⽀票上的签名验证,检验⽀票上的签名和银⾏预留的签名是否⼀致。当时论⽂中就已经⽤卷积⽹络来做验证了...当时我还没出⽣。
亲爱的早上好图片之后,2010年Hinton在ICML上发表了《Rectified Linear Units Improve Restricted Boltzmann Machines》,⽤来做⼈脸验证,效果很好。输⼊就是两个⼈脸,输出就是same or different。
可想⽽知,孪⽣⽹络可以做分类任务。在我看来,孪⽣⽹络不是⼀种⽹络结构,不是resnet那种的⽹络结构,⽽是⼀种⽹络的框架,我可以把resnet当成孪⽣⽹络的主⼲⽹络这样的。
既然孪⽣⽹络的backbone(我们暂且这样叫,应该可以理解的把)可以是CNN,那么也⾃然可以是LSTM,这样可以实现词汇的语义的相似度分析。
之前Kaggle上有⼀个question pair的⽐赛,衡量两个问题是否提问的是同⼀个问题这样的⽐赛,TOP1的⽅案就是这个孪⽣⽹络的结构Siame net。
后来好像还有基于Siame⽹络的视觉跟踪算法,这个我还没有了解,以后有机会的话我看⼀看这个论⽂。《Fully-convolutional siame networks for object tracking》。先挖⼀个坑。
2.2 伪孪⽣⽹络
问题来了,孪⽣⽹络中看似两个⽹络,实则共享权制为⼀个⽹络,假设我们真的给他弄两个⽹络,那样不就可以⼀个是LSTM,⼀个CNN实现不同模态的相似度⽐较了?
奥马冰箱质量如何没错,这个叫做pudo-siame network 伪孪⽣⽹络。⼀个输⼊是⽂字,⼀个输⼊是图⽚,判断⽂字描述是否是图⽚内容;⼀个是短标题,⼀个是长⽂章,判断⽂章内容是否是标题。(⾼中语⽂作⽂常年跑题选⼿的救星,以后给⽼师说这个算法说我的⽂章没有跑题,您要不再看看?⽼师会打死我吗)
不过本⽂和下⼀篇的代码都是以siame network为核⼼,backbone也以CNN卷积⽹络和图像展开。
2.3 三胞胎
既然有了⼆胞胎的⽹络,当然也有三胞胎,叫做Triplet network《Deep metric learning using Triplet network》。据说效果已经好过Siame
network了,不知道有没有四胞胎和五胞胎。
3 损失函数
分类任务常规使⽤softmax加上交叉熵,但是有⼈提出了,这种⽅法训练的模型,在“类间”区分性上表现的并不好,使⽤对抗样本攻击就⽴刻不⾏了。后续有空讲解⼀下对抗样本攻击,再挖个坑。简单的说就是,假设是⼈脸识别,那么每个⼈就是⼀个类别,那么你让⼀个模型做⼀个⼏千分类的任务,每⼀个类别的数据⼜很少的情况下,想想也会感觉到这个训练的难度。
针对这样的问题,孪⽣⽹络有两个损失函数⽐较近经典:
Contrastive Loss
Triplte Loss
3.1 Contrastive Loss
提出论⽂:《Dimensionality Reduction by Learning an Invariant Mapping》
现在我们已知:
图⽚1 经过模型得到pred1
图⽚2 经过模型得到pred2
pred1和pred2计算得到loss
论⽂中给出了这样的⼀个计算公式:
⾸先呢,这个经过模型得到的pred1和pred2都是向量,过程相当于图⽚经过CNN提取特征,然后得到了⼀个隐含向量,是⼀个Encoder的感觉。
然后计算这两个向量的欧⽒距离,这个距离(如果模型训练的正确的话),就可以反应两个输⼊图像的相关性。我们每次输⼊两个图⽚,我们需要事先确定这两个图像是⼀类的,还是不同的,这个类似⼀个标签,也就是上图公式中的Y。如果是⼀类的,那么Y为0,如果不
是,Y=1
类似于⼆值交叉熵损失函数,我们需要注意的是:
Y=0的时候,损失为:(1−Y)L S(D i W)
Y=1的时候,损失为:YL D(D i W).
其中论⽂中L D,L S是常数,论⽂中默认取0.5
i是⼀个次⽅的含义,论⽂中和常⽤的contrastive loss中,都是默认i=2,也就是欧⽒距离的平⽅。
对于类别是1(different类别的),我们⾃然是希望pred1和pred2的欧⽒距离越⼤越好。那么这个⼤到什么程度是个头呢?损失函数是往⼩的⽅向移动,那么需要做什么呢?增加⼀个margin,当作最⼤的距离。如果pred1和pred2的距离⼤于margin,那么就认为这两个样本距离⾜够⼤,就当其的损失为0。所以写的⽅法就是:max(margin−distance,0).
上图中的W我理解为神经⽹络的weight,然后→X
1,表⽰要输⼊的原图⽚。
所以损失函数就变成这个样⼦:
总结⼀下,这⾥⾯需要注意的应该就是对于different的两个图⽚,需要设置⼀个margin,然后⼩于margin的计算损失,⼤于margin的损失为0.
计算机一级考试b
3.2 Contrastive Loss pytorch
# Custom Contrastive Loss
class Module):
"""
Contrastive loss function.
Bad on: /exdb/publis/pdf/hadll-chopra-lecun-06.pdf
"""
def __init__(lf, margin=2.0):
super(ContrastiveLoss, lf).__init__()
lf.margin = margin
def forward(lf, output1, output2, label):
euclidean_distance = F.pairwi_distance(output1, output2)
loss_contrastive = an((1-label) * torch.pow(euclidean_distance, 2) + # calmp夹断⽤法
(label) * torch.pow(torch.clamp(lf.margin - euclidean_distance, min=0.0), 2))
return loss_contrastive
其中唯⼀需要谈⼀下的可能就是functional.pariwi_distance,
这个就是计算对应元素的欧⽒距离,举个例⼦:
import torch
functional as F
a = torch.Tensor([[1,2],[3,4]])
b = torch.Tensor([[10,20],[30,40]])
F.pairwi_distance(a,b)
输出为:
然后看⼀下这个数字是不是欧⽒距离:
没问题的啊
对数的性质3.3 Triplte Loss
提出论⽂:《FaceNet: A Unified Embedding for Face Recognition and Clustering》
令我
这个论⽂提出了FactNet,然后使⽤了Triplte Loss。Triplet Loss即三元组损失,我们详细来介绍⼀下。
Triplet Loss定义:最⼩化锚点和具有相同⾝份的正样本之间的距离,最⼩化锚点和具有不同⾝份的负样本之间的距离。这个其实应该是三胞胎⽹络的损失函数,同时输⼊三个样本,⼀个图⽚,然后⼀个same类别的图⽚和⼀个different图⽚。
Triplet Loss的⽬标:Triplet Loss的⽬标是使得相同标签的特征在空间位置上尽量靠近,同时不同标签的特征在空间位置上尽量远离,同时为了不让样本的特征聚合到⼀个⾮常⼩的空间中要求对于同⼀类的两个正例和⼀个负例,负例应该⽐正例的距离⾄少远margin。
如下图所⽰:
这个的话我们要如何构建损失函数呢?已知我们想要的:
让anchor和positive得到的向量的欧⽒距离越⼩越好;
让anchor和negative得到的向量的欧⽒距离越⼤越好;
所以期望下⾯这个公式成⽴:
简单的说就是anchor和positive的距离要⽐anchor和negative的距离⼩,⽽且这个差距要⾄少要⼤于α。个⼈的思考是,这⾥的T,是三元组的集合。对于⼀个数据集,往往可以构建出⾮常多的三元组,因此我个⼈感觉这种任务⼀般⽤在类别多,数据量较少的任务中,不然三元组数量爆炸了
3.4 Triplte Loss keras
这⾥有⼀个keras的triplte loss的代码
def triplet_loss(y_true, y_pred):
"""
Triplet Loss的损失函数
"""
anc, pos, neg = y_pred[:, 0:128], y_pred[:, 128:256], y_pred[:, 256:]
# 欧式距离
pos_dist = K.sum(K.square(anc - pos), axis=-1, keepdims=True)
neg_dist = K.sum(K.square(anc - neg), axis=-1, keepdims=True)
basic_loss = pos_dist - neg_dist + TripletModel.MARGIN
loss = K.maximum(basic_loss, 0.0)
print "[INFO] model - triplet_loss shape: %s" % str(loss.shape)
return loss
参考⽂献:
[1] Momentum Contrast for Unsupervid Visual Reprentation Learning, 2019, Kaiming He Haoqi Fan Yuxin Wu Saining Xie Ross Girshick哪个星球最大
[2] Dimensionality Reduction by Learning an Invariant Mapping, 2006, Raia Hadll, Sumit Chopra, Yann LeCun
Processing math: 100%