38

基于Caffe的DeepID2实现(下)

小喵的唠叨话:这次的博客,真心累伤了小喵的心。但考虑到知识需要巩固和分享,小喵决定这次把剩下的内容都写完。

四、数据的重整,简单的划分

前面的Data层用于生成成对的输入数据,Normalization层,用于将feature归一化,那么之后是不是就可以使用ContrastiveLoss层进行训练了呢?

且慢,还差一步。

ContrastiveLoss层要求有3个bottom:feature1、feature2以及表示对位的feature是否为同一个identity的label。

我们现在得到的feature却是所有的都在一起,data层直接得到的label也和这里要求的label不同。因此务必要对数据进行一次重整。

一个简单的规则就是按照奇偶,将feature划分成两部分。这样得到的两部分正好就是相同位置为一对。对于label的重整,也可以用类似的方法。小喵这里只对feature进行重整,而label的处理则是通过改ContrastiveLoss层来实现。

feature的重整本质上就是一个切片的操作,这里命名为id2_slice_layer,实现方法就是按照奇偶把bottom的数据复制到top。后馈的时候,也就是将两部分的feature的diff都直接复制到对应位置的bottom_diff中,具体实现如下:

头文件,巨简单。。。

Cpp的代码,也非常简单,要注意id2_slice层的top有两个,每个的形状都是bottom的一半。

GPU上的实现,为了简单起见,也是直接调用了CPU的前馈函数。

这样就完成了feature的重整。由于没有用到新的参数,因此也不需要修改caffe.proto。

亲可以仿照这个方法对label来做类似的操作。鉴于小喵比较懒。。。这里就只是简单的改ContrastiveLoss层的代码了。

第一步,在ContrastiveLossLayer中新增一个用于记录feature pair是否是同一个identity的成员变量,取代原本的第三个bottom的功能。这样只需要在前馈的时候提前算好,就可以代替之前的第三个bottom来使用,而不需要再修改别的地方的代码。

为了大家使用的方便,小喵直接把修改之后的头文件粘贴出来(删掉注释)。新增的行,用“added by miao”这个注释标注出来。头文件只加了一行。

源文件的修改也十分简单,这里只贴出来Cuda的部分。源文件,修改了与原来的bottom3相关的地方。

需要注意的时候,前馈和后馈都需要做一点代码上的修改,虽说十分的简单,但也要小心。

至此,基于Caffe的DeepID2的修改全部完成。

 

最后,十分感谢小喵的师弟,胖喵的审查,每一篇博客都由胖喵第一手的阅读并提出意见。

 

写于2个月之后:
小喵在2个月之前写完了这三篇博客,当时自己也做了一些实验,在人脸识别上得到了一定的提升。但之后一直忙于复现师兄的原先的结果。直到最近才完整的复现了出来。中间尝试了各种修改,真是一把辛酸泪。相应的修改以更新的形式写到了每篇博客的后面了。修改的源码并没有粘上,最近没啥心情整理了。

 

如果您觉得本文对您有帮助,那请小喵喝杯茶吧~~O(∩_∩)O~~

%e6%89%93%e8%b5%8f

转载请注明出处~

 

 

miao

miao

38 Comments

  1. 首先楼主好人一生平安。

    问个问题,DeepID2里面用到了locally convolution layer这一部分怎么没有提到?

    • 你说的对,这部分是没有说。local conv层caffe没有实现,但从网上可以找到,据说速度比较慢。我实验的时候直接用的googlenet,效果还好。local conv应该不是必须的,而且triplet loss可能比deepid2更有研究价值。

      • 谢谢楼主回答。
        我没有找到local conv layer的实现,只有类似的locally connected layer,但是这个参数会更多,速度会更加慢。如果楼主能提供相关资料,我十分感激。
        另外,我跟你的想法有些不一样,我觉得triplet loss效果并不能比contrastive loss好多少,triplet要的数据量太大了(FaceNet),而且我看DeepID2的paper里的意思,加入negative项对性能影响很小。

        • 真心十分抱歉,我没有专门研究local conv,能查到的资料估计和你一样多。😔
          然后,你是我搭建这个博客之后,第29个回复!前28个都是广告。。。😭
          对于triplet loss,我认为还是很有研究意义的。只是我不觉得需要和论文一样去实现,完全可以把triplet loss作为新的监督信号加进来。
          deepid2加negative项效果很小,很大程度上是由于feature是由identity signal决定的。而且如果删掉identity signal的话,这两种方法是不是就更相似了呢?

          • 我也是认为是由于identity信号使得negative项使得效果不明显。triplet的方法更直接一些吧,Person ReID也用的是triplet,确实两者十分类似,只是有一点区别我认为是contrastive loss对intra-class的特征相似约束会更强,如果要求intra-class invariant的话,也许会更好。总之应该是视场景而使用二者之一吧。
            感谢博主的用心答复。希望以后能继续出一些最新的关于face的caffe实现啊。汤晓鸥组的paper一点代码都不给真是令人蛋疼。
            加油!

  2. 楼主啊,作为一个初学者,问一个白痴的问题。怎么训练lfw的数据集啊?它给的txt都是直接的pair,那我需要对所有的图片生成一个list,然后生成lmdb?在forward阶段去读那些pair.txt,对每个batch加载pair? 还有每个人的image也太少了吧?我觉得直接训练softmax并不会怎么好吧?

    跪谢楼主赐教lfw数据集你是怎么玩的?先不管paper说的提取patch等

    • 使用实验室内部的一个数据集。我在使用webFace这个数据集的时候,也得到了差不多的结果(可能差一点)。网络是GoogleNet,将输入改成112。不使用contrastive loss的话,大概能到97%。比较都是直接l2来比的。
      PS.你回复这么多次,其他的回复我就都删掉啦

    • 是指什么呢?效果的话,我又回答过别人相同的问题,您可以看一下。

  3. 您好,我是想问contrastiveloss算出来是多大的数量级呢,和softmax loss相比呢

    • 这个与loss weight和特征长度都有关系。我的特征没有归一化,所以比较大。用简化的google net训练的,特征长度512,类别数13000。最终的loss如下(google net有三级输出)
      Train net output #0: id2_2/class_loss = 1.2214 (* 0.5 = 0.6107 loss)
      Train net output #1: id2_2/id2_loss = 652.572 (* 0.001 = 0.652572 loss)
      Train net output #2: id2_3/class_loss = 1.01738 (* 0.5 = 0.508688 loss)
      Train net output #3: id2_3/id2_loss = 598.083 (* 0.001 = 0.598083 loss)
      Train net output #4: id2_4/class_loss = 0.568487 (* 1 = 0.568487 loss)
      Train net output #5: id2_4/id2_loss = 741.723 (* 0.001 = 0.741723 loss)

  4. 我看您这里的id2_loss和class_loss是差不多一个数量级(乘上loss weight之后)。刚开始训练的时候id2_loss是多少呢?还有特征为什么是512维啊,有什么考虑吗?

    • 特征是512维并没有什么考虑。通常也就只有128,256和512。我的DeepID2的网络是在之前的DeepID的基础上做的,模型是finetune的。最开始的contrastive loss可以达到1K~1W这个数量级。
      这两个差不多一个数量级是因为我后期训练的时候不断调整loss weight才达到的。我在训练过程中不断的改变loss weight的比重,做了很多的实验,这是当时效果比较好的一组。

      • 樓主,請問一下最開始加入verify信號時,weight是如何設置的,還有DeepID訓練20W,是因爲lr變化一次是20W嘛?

        • 我通常先deepid训练,然后加入verification信号之后,loss weight设成1,看一下大致的大小,之后把loss weight设小,当它和分类的信号差不多大就可以。

          • 楼主,我现在deepID在LFW上达到94%,然后在这个基础上改为DeepID2,在DeepID训练15W之后加入verification信号,给它一个比较小的loss weight之后发现,softmax loss变大了很多,而且accuracy减了大概20%,我想问一下刚开始加入的时候,softmax loss的loss weight还是1嘛,我把它设为0.8,发现softmax loss收敛了,但是accuracy还是比DeepId的小,不知道楼主刚加入verification时,两个信号loss weight是怎么设置的,我基本上verification是8K级别,softmax loss是3.几的样子

            • 加入verification信号的时候,softmax肯定会慢慢变大,accu下降也是必然的。但是人脸识别,这是个识别的任务,不是分类的任务。所以分类的效果并不能说明识别的能力,你得不断的测试LFW的结果。
              我之前最终的loss大致是 softmax 2左右,verification 600左右。

              • softmax loss为什么会慢慢变大,不是很明白,我怎么觉得应该是verification慢慢变大吗,然后softmax慢慢变小,然后再调小verification的weight这样对不对,可是我发现我的训练结果是加入verification之后,verification基本不变呀,郁闷中

              • 不是很理解,为啥softmax会慢慢变大,我总觉得softmax应该慢慢变小,然后verification慢慢变大,说明识别能力越来越强,然后把verification的weight调小,这样一个过程,不知道楼主做实验的时候这两个loss的总体是怎样一个变化趋势

                • deepid就是优化softmax的。所以softmax loss会很小。换成deepid2之后,目标就不完全是softmax了,所以softmax变大不是很正常的吗?

  5. 非常感谢!请问您训练多少epoch呢?模型有多少参数呢。我用的是resnet,有10层,然后提取了160维度的特征,训练出来96.5%左右。用了constrastive loss之后,目前训练是95.5%左右,可能没训练好。

    • 我最开始的deepid的模型训20w轮,再用deepid2训10w轮。batch size 128,用了googlenet,输入改成128,输出的部分删掉pool直接连fc到512,再到13000。模型最终大小大概有200m,参数主要在全连接了。
      你可以多试试几个loss weight。训练过程中也多测试一下,可能最终的模型并不是最好的。

      • 楼主,请问一下deepID训练完之后,开始用deepID2训练时,两个信号的loss_weight是如何设置的?还有20W轮是一次lr调整吗

  6. 你好 我想问一下 如果输入的数据是num不确定,有总数为奇数或为偶数的情况下,又对应怎样修改呢?

    • 其实也好办,假设你的某一类的样本是15个,但是要生成样本对,这样你就能顺利的生成7对样本对。还剩下一张图片,我的策略是再从15张图片中随机选一张来配对。当然你也可以直接丢弃这个样本。
      如果不是构造样本对,而是样本组的话,比如4个样本一组。15个样本就够造成3组,余下3个样本,随便再选一张凑数即可。

发表评论

电子邮件地址不会被公开。