我的毕设选题是:基于孪生网络的苹果外观品质分级系统研究。以前只是粗略的了解过孪生网络,没有系统学习过,所以现在重新完整的学习一遍孪生网络,学习内容分为两个blog,一篇是理论内容,一篇是代码实操。
一、什么是孪生网络(Siamese Neural Network)?
一句话:孪生网络是一种由至少两个神经网络并行组成的神经网络(这里的并行的重要特征是两个神经网络共享参数),尤其是CNN并行,但是也可以有LSTM/RNN并行,同时并行的网络如果结构不一致则会被称为伪孪生网络(Pseudo-Siamese Network)。这种并行的CNN结构允许模型学习图像(或者视频中某一帧)的相似性,从而代替了直接进行分类。
并行的每一部分CNN都需要把输入进行嵌入(embedding)或降维,这里的嵌入具体指两个神经网络将输入映射到新的空间,形成在新空间的表示,这个表示是可以学习的,通过机器学习(反向传播算法等等)可以优化网络参数和权重来减少Loss以改善我们的embedding表示,Loss越小,则意味着最终的向量表示中,越相关的类别,它们的表示越接近;不相关的类别,它们的表示就越远。这里的远近我们用距离表示,随之就引出了另外一个研究方向——度量学习(Metric Learning,专门研究两个表示的相似度或者说距离)。举个例子,比如我们指定embedding的大小为20,而我们的数据是128*128*3(宽*高*通道数)大小的一张图片,那么这个图片在这个孪生网络模型中的表示就是一个长度为20的向量,后续所有的实验和研究都是对这个长度为20的向量进行的,这个向量就代表着图片的特征。
这里我想加一些关于embedding的内容。
embedding最早起源于自然语言处理(NLP)领域,它可以将离散变量转变为连续向量,那么如何对CV领域的图像进行embedding呢?最简单的方法就是自编码器(Auto-Encoder),自编码器由编码器和解码器两部分构成,而编码器的中间向量就是图像的embedding表示,可以用来聚类或分类。embedding后来也用于图像检索领域并取得了非常好的效果。
在考研复习备考的过程中,通过学习政治(具体说是马原)我明白了任何一个事情或现象背后一定有它的物质动因或逻辑,一个新事物的产生不是凭空出现的。embedding作为一个很优秀的技术,它的出现解决了非常多问题,在众多领域都取得好了很好的效果,我想说它的价值并不仅仅在于NLP中的词嵌入(Word Embedding)或者CV中CAE(Convolution Auto-encoder),甚至包括凯明最新的MAE(Masked Autoencoders),这种将有具体类别的数据用低维空间表示并且这种表示可以学习的思想更值得我们学习。我们学习学的不是知识,知识是学不完的,昨天有CAE,今天有MAE,后天是不是就会有AAE,BAE甚至DAE了呢?我们更应该注重这种抽象的解决问题的能力。
其实大概一年前的现在,2021年2月份时候,我做过一段时间遥感高光谱图像的CAE,但是当时没有考虑这么多这么严谨,只是想到了遥感图像非常复杂,传统RGB图像三通道,而遥感图像可能数百个波段(可以理解为通道数,但是不完全一样),需要降维,其次做的是无监督特征提取的课题,想让模型自己去学习重要的特征,从而就想到了auto-encoder这种网络结构。这和孪生网络的初衷有些相似:降维和学习事物的某种表示。
我们从数学角度再对embedding解释。embedding在数学上表示一个mapping(映射),
也就是一个function,其中该函数是injective(就是我们所说的单射函数,每个Y只有唯一的X对应,反之亦然)和structure-preserving (结构保存,比如在X所属的空间上X1<X2,那么映射后在Y所属空间上同理 Y1<Y2)。那么对于图像的 embedding,就是将图像的特征映射到另外一个空间,其中这个映射具有injective和structure-preserving的特点。通俗的翻译可以认为是特征嵌入,就是把X所属空间的特征映射为到Y空间的多维向量,那么该多维向量相当于嵌入到Y所属空间中,一个萝卜一个坑。
这里我展示了MNIST数据集经过embedding之后形成超空间,再经过PCA投影到二维平面上的投影[1]。
这里面只有10个类别(数字0-9),但是如果我们想增加一个数字比如11应该怎么办呢?我们不需要重新训练模型,想到孪生网络的原理,比较相似度,那么只要让数字11和其余10个数字在embedding之后的空间里远离,那么许多个11靠近,一起凑成了一个簇,也就成为了新的类别。通过使用embedding之后比较相似度,我们就可以进行小样本学习,只使用少量训练样本就可以达到很好的分类效果。这对于现实生产生活是很有帮助的,因为有些任务因为各种实际情况而很难采集到大量数据。
二、孪生网络如何训练?
前面我们已经提到了孪生网络可以有多个分支,分支的数量对于孪生网络模型的训练是有很大影响的,更进一步,选择损失函数时需要考虑分支的数量。
对比损失(Contrastive Loss)旨在计算模型的输入映射到超空间之后的距离,这和预测具体类别的那些传统损失函数形成了对比(比如交叉熵损失函数),目的是增大分类器的类间差异。对比损失随着近几年深度学习的飞速发展产生了许多变种,但是它们起作用的方式都一样。Contrastive Loss是来自Yann LeCun的论文[2].
现在假设我们的孪生网络有两个输入,我们想知道二者之间有多少相似度,如果使用对比损失,需要进行如下步骤:
需要注意的是,我们并不关注embedding在超空间的具体数值,我们只关心它们之间的距离。
三元组对比损失Triplet Contrastive Loss
一种常见的孪生网络的损失函数是Triplet Loss,顾名思义,三元组损失,所以输入需要有三个样本。TripletLoss是在FaceNet论文中的提出来的[3],是对Contrastive Loss的改进。
Triplet Loss定义:最小化锚点和具有相同身份的正样本之间的距离,最大化锚点和具有不同身份的负样本之间的距离。
Triplet Loss的目标:Triplet Loss的目标是使得相同标签的特征在空间位置上尽量靠近,同时不同标签的特征在空间位置上尽量远离,同时为了不让样本的特征聚合到一个非常小的空间中要求对于同一类的两个正例和一个负例,负例应该比正例的距离至少远margin。这个margin是一个超参数,可以自己手动设定。具体如下图所示:
三元组中的每一个样本点都有其自己存在的意义,锚点(anchor)决定了当前模型训练的是哪个类别,正样本表示同类别的另外一个样本点,负样本表示不是当前类别的样本点。具体数学表达式如下所示:
其中xa表示锚点,xp表示正样本,xn表示负样本,α表示边界。
三、孪生网络如何推理?
目前我们已经了解了孪生网络如何训练,接下来我们来学习孪生网络是如何进行推理的。在训练过程中,我们使用了多个孪生网络的分支,而在推理过程中,我们只需要使用一个分支即可。
在推理过程中,孪生网络先将未知类别的图片通过CNN(已经训练好的映射方式embedding function)让它的特征映射到超空间,将图片在超空间中的embedding和其他已知类簇进行比较,比较后我们可以得到与其他类簇相似度的信息,或者未知类别图片和其他已知类别之间的距离,从而可以将这个测试图片划分为某个已知类别或归为新的类别。
理论内容先介绍这么多,下篇我们进行代码实操,用Python和深度学习框架自己动手实现一个孪生网络。如果必要的理论还欠缺的话,我们下篇再进行补充。欢迎各位老师同学批评指正!
[1]LeCun, Y., Bottou, L., Bengio, Y. and Haffner, P., 1998. Gradient-based learning applied to document recognition. Proceedings of the IEEE, 86(11), pp.2278–2324.
[2]http://www.cs.toronto.edu/~hinton/csc2535/readings/hadsell-chopra-lecun-06-1.pdf
[3]https://arxiv.org/abs/1503.03832