前言
- 本文属于我迁移学习专栏里的一篇,该专栏用于记录本人研究生阶段相关迁移学习论文的原理阐述以及复现工作。
- 本专栏的文章主要内容为解释原理,论文具体的翻译及复现代码在文章的github中。
原理阐述
文章介绍
- 这篇文章于2016年发表在NIPS会议,作者是来自谷歌的研究人员。
- 这篇文章开篇点出,当前领域自适应的研究主要着眼于以下两个方向:1.将不同域的数据映射到同一个域,从而使得源域和目标域尽可能的相近。2.不同域,但不采用映射到同一域的方法,而是提取两者之间域不变的特征,两个域之间总有相同的特征,不然何谈迁移,要做的就是提取到域不变的特征用这些特征进行预测,从而得到同时适用于两个域的预测模型。简而言之,上面两种方法分别是映射到同一域和提取域不变特征。
- 然而作者从另一个角度考虑问题,他先是说到了负迁移,他认为每个领域都有域不变的特征和独有的特征(共享和私有特征),而倘若试图利用私有特征进行预测则会适得其反,造成负迁移,反之,只有使用共享特征才能达到迁移学习的目标。也就是说有些私有特征宁可不用,这个地方我埋个伏笔,作者竟然提取了两个域各自的私有特征并作为一个loss(differ-loss),思路非常清奇。
- 上面的介绍大家大体看一下就可以,很多疑惑不要紧,看下面的模型结构就能理解的更深入一些。
模型结构
- DSN的模型是这样的:
私有特征提取器
- 上图中的Private Source/Target Encoder是源域和目标域数据的私有特征提取器,用于提取各自的私有特征,所以每个提取器的参数是不共享的。
- 两个私有特征提取器内部结构是一样的,由多个卷积层提取特征,然后flatten一下,得到图中的 h p t 、 h p s h^{t}_{p}、h^{s}_{p} hpt、hps。
- 具体结构可以参考下述代码:
# private target encoder
self.private_target_encoder=nn.Sequential(
nn.Conv2d(3,32,5),
nn.MaxPool2d(2,2),
nn.ReLU(),
nn.Conv2d(32,64,5),
nn.MaxPool2d(2,2),
nn.ReLU(),
Flatten2(),
nn.Linear(64*4*4,100)
)
共享特征提取器
- 上图中的Shared Encoder是共享特征提取器,用于提取源域数据和目标域数据的公有特征。由于是公有特征,所以自然参数是共享的。
- 相关结构如代码所示:
# source and target shared encoder
self.shared_encoder=nn.Sequential(
nn.Conv2d(3,32,5),
nn.MaxPool2d(2,2),
nn.ReLU(),
nn.Conv2d(32,64,5),
nn.MaxPool2d(2,2),
nn.ReLU(),
Flatten2(),
nn.Linear(64*4*4,100)
)
similarity loss
-
similarity loss用于衡量源域数据和目标域数据经过Shared Encoder到的公有特征的相似度,衡量方法是将两个域的feature map放入到梯度翻转层然后输入到全连接层进行域分类,共分为两类,源域数据类标签为1,目标域数据类标签为0。误差使用交叉熵(CrossEntropyLoss)。
-
倘若提取到了有力的公有特征,那么域分类器的loss会很大。然而由于梯度翻转层的存在使得反向传播试图降低误差从而无法提取到有力的公有特征时对于特征提取层(即公有特征提取器)起到反作用,从而抑制误差降低,从而有利于提取公有特征。
-
这部分结构其实就是DANN中的全局域分类器。
-
代码示例如下:
# domain predictor
self.domain_predictor=nn.Sequential(
nn.Linear(100, 100),
nn.ReLU(),
nn.Linear(100, 2)
)
# similar loss 其实就是域损失,因为倘若足够相似,域损失很小的。
Reverse_X_src=ReverseLayerF.apply(shared_src,alpha)
Reverse_X_tar=ReverseLayerF.apply(shared_tar,alpha)
domain_src=torch.ones(len(Reverse_X_src)).long().to(self.device)
domain_tar=torch.zeros(len(Reverse_X_tar)).long().to(self.device)
result_X_src=self.domain_predictor(Reverse_X_src)
result_X_tar=self.domain_predictor(Reverse_X_tar)
loss_similar=nn.CrossEntropyLoss()(result_X_src,domain_src)+nn.CrossEntropyLoss()(result_X_tar,domain_tar)
difference loss
- difference loss使用的是squared Frobenius norm来计算,关于这个,网上有说这就是L2范数的平方。
H c s 和 H p s H^s_{c}和H^s_{p} Hcs和Hps就是 多 个 样 本 的 h c s 和 h p s 多个样本的h^s_{c}和h^s_{p} 多个样本的hcs和hps,每一行是一个样本的 h c s 和 h p s h^s_{c}和h^s_{p} hcs和hps。
解码器
- shared decoder是这个模型的重点结构,它将源域和目标域的私有及共享特征整合到一起,然后进行上采样得到和样本尺寸一样的矩阵
X
′
X'
X′,即根据特征还原了样本,然后通过计算 scale-invariant mean squared error得到Loss-rec。这个损失与MSE有区别:
∣ ∣ x − x ′ ∣ ∣ 2 2 ||x-x'||^2_{2} ∣∣x−x′∣∣22是L2正则化的平方。即:
关于这个损失大家可以移步:https://www.cnblogs.com/MTandHJ/p/14381010.html - 至于作者为什么用这个损失,原文是这么说的,均方误差损失(MSE)传统上用于重建任务,但是对于缩放项下正确的预测它都会进行惩罚,这个是可以理解的,因为MSE要求“一字不差”,而我们事实上只要比例上特征是正确的,数值上有所差距是可以容忍的。而scale-invariant mean squared error会惩罚成对像素之间的差异,这样就只会惩罚整体形状的差异,而不会在输入的绝对颜色或强度上花费建模能力,这样就不显得那么死板。作者说的其实是比较好理解的。
- loss:
标签分类器
- 这个就不多说了。
总损失函数
- 见下图:
作者并没有给出权重参数 α β γ αβγ αβγ的推荐值。
总结
- 在测试的时候,测试数据经过共享编码层,然后使用标签分类器进行分类。由此可见影响分类精度的主要就是共享编码层和标签分类层的参数。标签分类层相对独立,主要由分类损失来调整参数。而共享编码层的similarity loss是可以理解的,用于生成相似的源域和目标域特征,但是共享编码层的参数同样受loss_rec影响,这个重构损失有点让人摸不着头脑,作者非得让私有特征和公有特征分开,然后重构损失是为了让分开的私有特征和公有特征合在一起是可以尽可能的复原样本的,这样是为了让私有特征和公有特征不重复,是彼此独立的,difference loss也是这个目的,作者的目的就是单独提取出共有和私有特征,只依靠公有特征来进行域适应,哇哦,感觉作者对于自己的理论是相当自信的,也就是说他坚持认为只有一部分特征是具有域不变性的,我们只需要用这部分进行域适应,而作者也是这么履行的,他不惜使用loss-rec和difference loss来将这部分特征提取出来,与不能参数域适应的特征划清界限。很佩服作者的想象力,不管效果如何,我觉得这种能力十分可贵。