Fine-Grained Representation Learning and Recognition by Exploiting Hierarchical Semantic Embedding

写在前面
paper -> 链接
code -> 链接(只有inference代码)

一、HSE发展背景

1. 基于深度学习的方法本质上都有两个缺点

(1)模型性能的保证依赖于大量带标注的训练数据;
(2)这些方法往往缺乏对能起指导作用的先验知识加以利用。

2. 精细化识别技术的主要难点

(1)难以区分的类间差别:对于从相似类别得到的物体,很多情况下他们的视觉差别是非常微小的,有些甚至是人都难以区分;
(2)明显的类内差异:对于从同一类别得到的物体,由于尺度、视角、遮挡以及多样化的背景,这些物体呈现出非常大的视觉差异。

3. 两种神经网络

一种是全连接神经网络,如受限玻尔兹曼机、深度置信网络等,另一种是卷积神经网络。

二、HSE模型创新点

1. 利用了层次化的语义知识

(1)在特征表达时,在神经网络中嵌入上级预测的得分向量,以之指导下级模型表达出更细致特征;
(2)在模型训练时,将上级的得分向量作为一种软目标,对下级预测的语义空间进行约束。
(3)首创性地将数据集划分为不同的类别。
在框架中主要体现在:特征表达时的语义知识的嵌入和模型训练时利用语义知识引导正则化预测结果。

2. 需要的训练集数目少

HSE 框架在训练样本越少的情况下,起到的作用越明显,说明 HSE 框架可以有效地减少模型训练时对数据的依赖,在小样本学习问题中
有潜在的应用价值。

三、HSE算法原理和实验

1. 算法理论原理

(1)图像浅层特征的提取(主干网络实现)

主要利用的就是resnet50的前41层作为主枝,提取图像的深度特征提取。
注意,如果是深层特征的提取的话是由分支网络实现的。

(2)语义知识嵌入表达学习(分支网络实现)

语义知识的嵌入表达体现在分支网络中:分支网络采用一种由语义知识引导
的注意力机制,分支网络首先会对来自于主干网络的特征图进行二次特征化表达,
产生一张新的分支特征图,通过结合上级预测的得分向量及其下级的分支特征图,
学习得到一张注意力权重图。这张权重图所表示的意思为,分支网络所生产的新
特征图每一个空间位置对于识别目标类别的重要程度
,判别性越高的位置,吸引
更多的注意力,在权重图相应位置对应的权重也越大。这张权重图作用在分支特
征图之上,最终产生一张加权的分支特征图,以此预测该层级类型的标签分布。

(3)语义知识对预测结果语义空间的约束(分支网络实现)

语义知识对预测结果语义空间的正则化体现在 HSE 框架的训练过程:本文将上级预测的得分向量作为软目标,强制约束其下级的预测结果符合分类树的语义规则,从而正则化其下级预测结果的语义空间。

在这里插入图片描述在这里插入图片描述

2. 算法对应的网络实现流程细节

(1)主干网络
如下图所示就是主干网络(trunk net)跟resnet50的区别。ResNet50的介绍可以看我上一篇blog零基础入门ResNet,在Cub200数据集上复现Resnet50
在这里插入图片描述
(2)分支网络
一定要参照这张图来读下文
在这里插入图片描述
1)语义知识嵌入表达学习框架中的关键参数的解释
ϕ i ( ⋅ ) \phi_i(\cdot) ϕi() : 经过主干网络之后,提取出的特征图 f I f_I fI,然后对 f I f_I fI进行进一步的特征图进行提取。即 f i ^ = ϕ i ( f I ) \hat{f_i}=\phi_i(f_I) fi^=ϕi(fI),这个主要是用来跟上一等级的输出结果 S i − 1 S_{i-1} Si1进行结合处理的,具体处理后面会解释。在本篇论文中所说的就是通过resnet50中的layer5,即第四个残差层。

ψ i ( ⋅ ) \psi_i(\cdot) ψi() : 作用跟 ϕ i ( ⋅ ) \phi_i(\cdot) ϕi()是一样的,之所以要做这次是因为要保持原来的全局特征,避免丢失。在本篇论文中所说的就是通过resnet50中的layer5,即第四个残差层。

φ i ( ⋅ ) \varphi_i(\cdot) φi() : 这是个全连接层,将 S i − 1 S_{i-1} Si1映射成一个1024维的语义知识表达向量。

repeat : 广播,将 S i − 1 S_{i-1} Si1经过 φ i ( ⋅ ) \varphi_i(\cdot) φi() 再次拓展成一个跟 f i ^ \hat{f_i} fi^具有相同维度(n,c,w,h)的向量 f i ′ f_i' fi

⊕ \oplus : 将 f i ^ \hat{f_i} fi^ f i ′ f_i' fi的每个位点的拼接。
在这里插入图片描述

a i ( ⋅ ) a_i(\cdot) ai(): 注意力训练模型,将凭借后的特征图连续用两个全连接层fc逐步将其映射为1024维和2048维,最后得到一个注意力系数(下图最右边蓝色部分)。

⊙ \odot : 将注意力系数向量与 ϕ i ( ⋅ ) \phi_i(\cdot) ϕi() 输出的特征图每个位置的图进行相乘,随后得到了加权的特征图 f i f_i fi
在这里插入图片描述
2)上级语义约束预测结果的过程体现
来自上层的 S i − 1 S_{i-1} Si1除了参与其分支结构中的上层语义嵌入学习框架中,还要参与上层语义框架最后输出的初始 S i S_{i} Si的学习演变中。具体的参与过程就是:
S i − 1 S_{i-1} Si1得将自己先拓展成跟 S i S_{i} Si具有相同维度的 S i − 1 ′ S_{i-1}' Si1
然后找到在通过在i-1层最后通过softmax函数输出的 S i − 1 S_{i-1} Si1中值最大的那一类c,并且通过从属关系找到c类对应的第i层中的k个子类
S i − 1 S_{i-1} Si1中c类的概率复制到 S i − 1 ′ S_{i-1}' Si1中的c的k个子类中
在这里插入图片描述
然后将 S i − 1 ′ S_{i-1}' Si1 S i S_{i} Si都进行温度为T=4的softmax函数计算,得出下面两个分布
在这里插入图片描述在这里插入图片描述

然后通过KL散射定义上层语义的正则化约束项
在这里插入图片描述

然后要求出针对整个训练集(实际训练的时候其实就是一个batch size的量)的正则项,然后就可以通过这个正则项去训练了。
在这里插入图片描述

3. 训练方法

(1) 需要优化的目标函数
以类别标签作为优化目标,采用交叉熵损损失函数作为目标优化函数。
1)首先,我们将第𝑖层的预测得分向量用 softmax 函数进行归一化:
在这里插入图片描述
2)计算损失函数,对某一个图像样本,假设它在当前层次类别的正确标签为𝑐𝑖,那么它的损失
值可以表示下图
在这里插入图片描述
然后对 ℓ i c \ell _{i}^{c} ic进行求和,从而求得整个训练集总体(实验的时候就是batch size)在第i层的分类损失函数 L i c L_{i}^{c} Lic

(2)训练步骤
1)逐个层次的渐进式训练
主干网络的41层直接使用ImageNet的pretrain模型参数进行初始化,并且在逐层训练这个阶段不参与更新。
在训练第𝑖个层次类别对应的分支网络时

HSE 模型已经集成了前𝑖 − 1个层次类别对应的网络结构因此,我们使用此前训练好的前𝑖 − 1个层次的分支网络模型,初始化 HSE 模型中前𝑖 − 1层分支网络的参数。而对第𝑖层的分支网络,子网络𝜓𝑖(·)和𝜙(·)中涉及的 9 个相关层的参数,本文实现同样使用在 ImageNet 数据集上预训练好的 Resnet-50 网络模型参数对其进行初始化。另外,𝜑(·)和𝑎(·)的实现是由全连接层组成,它们的参数使用 Xavier 算法进行初始化。分支网络的优化目标函数为: L i = L i c + γ L i r L_i=L_{i}^{c}+\gamma L_{i}^{r} Li=Lic+γLir γ \gamma γ是一个平衡分类损失函数项与正则化约束损失函数项对网络参数的影响,在本实验中值为2。另外需要特别注意的是,最顶层只有分类损失函数,没有正则约束项

数据增强和超参数

resize512,crop448,水平翻转
sgd作为solver,momentum=0.9,weigjt decay =0.00005
learning rate 初始1e-3,300epoch之后lr将为1e-4

2)联合训练

在所有分支网络都得到初步的训练后,我们对整个完整的 HSE 模型所有的参数进行联合优化。联合优化的目标函数为:
L = L 1 c L = L_{1}^{c} L=L1c + ∑ i = 2 N L i \sum_{i=2}^{N}L_{i} i=2NLi
在训练时,除了以一个更小的学习率 0.00001 之外,我们仍旧采用与步骤一相同的数据增量方法以及同样的超参数配置。

四、源码解读笔记

主要的解释流程都写在源码的注释上了,这里记一下这个函数的作用和需要注意的点

1. HSE IN CUB_200_2011

(1)deploy.py

1)作用
总的执行程序,
2)理解中需要注意的点
argparse模块
Python命令模块argparse学习笔记(二)
python命令行参数解析–argparse模块
cudnn.benchmark=True能加速gpu运算
torch.backends.cudnn.benchmark ?!
topk的用法
PyTorch中的topk函数详解
pytorch.t的转置函数
Pytorch里.t()的作用
在验证集中有两种准确率的计算方法,一是计算求出的预测标签数组中概率最高对应的那个标签如果跟答案标签一致就说明正确,另外一种就是概率前k大的预测标签中如果有一个跟答案标签对的上,也算正确。

(2)dataset.py

1)作用
按照deploy.py的需求构造dataloader
2)理解中需要注意的点
标签记得减1

(3)ResNetEmbed.py

1)作用
在deploy.py中被要求构造整个hse网络,包括主干和分支
2)理解中需要注意的点
AvgPool2d
torch之AvgPool2d

(4)Branch.py

1)作用
在ResNetEmbed.py中被要求构造分支结构,也就是传统的resnet中的第四个残差层,或者说是第五层,四种类别的这一分支构造都是相同的。
2)理解中需要注意的点

(5)EmbedGuiding.py

1)作用
在ResNetEmbed.py中被要求用来构造每一层的attention模型,注意第一个分结构和第四个分支结构是没有注意力模型的。

(6)model.py

五、调参记录

在这里插入图片描述

(具体日期有些是忘记标了)
2021.2.24号开始复现HSE

2021.2.24-2021.2.28(良好开局)

阅读论文并理解inference代码,完成了第一层的复现工作,良好的开局。

2021.3.1-2021.3.10(挑战开始)

这个阶段着重是复现第二层,经过如下
(1)准确率在前40个epoch左右就已经维持在了94.4%左右,觉得没必要继续训练下去,认为是逻辑,调参的问题
(2)首先针对的自然是学习率修改,通过之前resnet50的调参经验,通过观察acc的曲线图设置了几个节点进行相应倍数的衰减,实验了两、三天发现acc基本没有提升,且收敛速度也没有发生多大的变化。
(3)这时候重新去看论文,然后跟富宝师兄发现上层指导的映射逻辑那里有点错误,按照论文中的进行修改之后重新训练,效果还是没有提升
(4)然后试着改了下batch size,将8改为了4,又训练了两三天,收敛速度慢了一点,但是最高的acc达到了94.7%,但是分析之后觉得应该是偶然
(5)于是又有另外一个想法,在bs=4训练好之后,导入这个训练好的模型继续去用bs=8去训练,又训练了2,3天,发现效果也没有上升
(6)然后就去网上搜索各种tricks,然后搜索到了余弦退火这种学习率衰减的方式,然后也试了一下,很好,也没有提升
(7)然后又看了遍论文,然后决定还是老老实实地按照论文中所说地用恒定学习率去训练300代然后去恒定训练,以0.001去训练的话最后达到只能达到94.5%-94.6%之间,然后再把这训练好的模型导入并用0.0001去训练,然后学习率维持在了94.7%
(8)至此在第二层的探索达到了瓶颈,想着赶快训练完四层看看成果

2021.3.11~2021.3.20

(1)在第一层98.8%,第二层94.7%的acc下,去训练第三层,训练了2天左右,发现第三层低得离谱,足足差了7%,然后又看了一遍论文,没有什么新发现,然后重写了一遍代码,发现是导入上层预测得层数写成了第一层,改为第二层之后,又训练了300代,很快就达到了90%,经过重复load和train,最后也只达到了91.4%左右
(2)然后在98.8%,94.7%,91.8%的前三层acc的基础上进行训练第四层,训练了2天左右达到了86.8%左右
(3)接下来就是直接进行联合训练,一开始lr调成0.001,把主干也放进去训练,然后训练过程中每一层的都发生了巨大的退化,然后立刻想到应该把lr调成0.00001去联合训练
(4)联合训练步入了正轨,各层的准确率在训练了150代之后就超过了之前分层训练的最大值,但是这里面临一个问题,在联合训练的时候各层的acc并不一定都是同时上升的,可能第三层上升了0.3%,第二层反而下降了0.4%,所以我采取的策略就是只有每一层的acc都比当前各层最优的acc大才会去保存当前模型,就这样反复训练,反复降低lr训练,经过了几天的训练之后,最后的acc跟论文的差距为0%,0.8%,1.3%,1.4%

2021.3.21-2021.4.4

(1)然后看到github中是给出了师兄们训练好的model文件,然后便导进来查看了一下每一层的acc,结果是98.79%,95.69%,91.80%,88.09%,感到有点惊喜的是第三层的acc比论文也低了1%,所以想着我自己训练的模型是不是第三层已经达标了(因为我的训练过程也出现了第三层是91.8%的情况,但是因为第二层没有超过当前最有,所以我就没有保存这个模型)。
(2)后来也想到,可能当时文熙师兄在联合训练的时候也是遇到了我这个情况,所以取第三层为91.8%是保证整体最优的solution,所以论文中的数据可能是实验过程中出现的最大值,而不是稳定值(我自己的猜测)
(3)但是如果继续联合训练下去估计也不会由质的提升,所以又折返回去训练第二层了
(4)在重新训练第二层之前,我想测试一下各层的loss,按照理论分析,每层的loss应该是递增的,然后我用自己的代码去计算了一下loss,然后惊奇的发现训练集上的各层的loss并不是递增的,loss从小到大依次是第一层,第四层,第三层,第二层,然后又去测了一下测试集合,然后发现是正常的递增,然后用论文的模型去分别测试了一下训练集和测试集,情况和我自己写的代码是一样的,因此,怀疑的矛头指向了loss函数的构造
(5)在读了n遍论文和跟富宝师兄讨论之后,开始了几天的测试loss的阶段,从调整交叉熵的reduction和kl散度的reduction到将每个batch size求出的loss再除以batch size和整个数据集的数量,还有kl散度在损失函数中英文版论文中说是16,中文版说是2,这些情况都试过了,富宝师兄也对learning rate,wd,r这些参数多次组合调参过,最后效果并没有显著提升。
(6)自闭,迷茫,为什么loss会出现第二层大于第三层大于第四层呢?训练第二层的时候把第一层的acc也输出来看一下把,然后就这样试了,结果也是有点惊吓,第一层的acc在第二层的训练的时候出现了一定程度的退化,我明明只把第二层的相关参数放进去训练啊,为什么会影响到第一层,然后就把第一层训练好的所有参数打印出来,然后打印第二层训练好的整个模型的参数,然后写了个脚本筛选出了两者不同的地方,罪魁祸首就是bn.running_mean和bn.running_var这个两个参数发生了意料之外的变化,然后我想起了当时看正则bn算法的时候,bn算法的也是说每次计算的时候都对batch size的数据量进行训练的前向传播的时候都会重新计算一遍,所以就会导致这两个参数发生变化,后面也发现了bn的weight和bias的参数是没有发生变化的,所以这个猜测应该是对的。
(7)然后没有头绪的胡乱训练了几天,又发现一个现象,就是我在训练第二层的时候,虽然准确率也会上升,但是第一层最初训练好的acc是会呈现退化现象的嘛,但是第一层的退化现象没有出现退化到第一层的acc小于第二层这种离谱的情况,然后我就用94.8%的第二层去训练第三层,终于出现这种现象了,第二层的acc退化到80%,第三层缓慢上升到了91.4%左右,当时的学习率是0.001把
(8)然后我也考虑到了是不是因为lr=0.001太大了呢,同时我也严重怀疑第二层的acc都低于第三层的acc,这样第二层的指导作用还会有嘛?
(9)因此我先做了个验证实验去证明如果能keep住第一层的预测结果(就是保持原来acc最高的那个预测值)去训练第二层的话,这样在训练第一层的时候是不是能减缓第一层退化现象呢?然后减缓了损失那自然起到的指导效果就会更好了,从而提高第二层的训练acc,这组实验还遇到一个问题就是无法将第一层的预测结果都保存下来,内存会爆,所以采用的是文件存储的形式,在训练的时候,动态从文件读取对应的图片的第一层预测值,然后去构造kl散度计算误差,然后便以lr=0.00001去训练,训练了几天后,发现结果并不是我想的那样,第一层还是会发生退化,退化程度跟我原本直接使用当前的第一层结果训练出来是差不多的,而且,训练同样的代数的情况下,第二层的acc远远没有达到之前训练的效果,重复训练了’几个300代,acc最后也只达到了92%,或许是因为lr太小了,然后我将lr增大为0.001,重新训练一遍,看下效果。跟之前按照正常去训练反而上升速度减缓了。因此我觉得第一层的acc在训练的时候发生了退化应该是正常的,因为我在第一个训练阶段的时候,虽然之前没有在训练第二层的时候把第一层的acc打印出来看到退化的程度,但是经过多次训练,第一层的acc是会重新回到98.7%左右的,所以退化应该不会太影响它的指导作用把。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值