有趣但鸡肋的e2e对抗样本正则项

最近频频在论文中看到计算当前样本的对抗样本作为正则项去训练模型
抱着好奇心这个东西究竟有多少收益,在audio tagging的比赛里尝试了一下
结论是成本太高,收益较小,很鸡肋
成本在于一个batch里每个样本都要计算对抗样本 <=> 调试时间和需求显存加倍 。。。
就是bs加了个倍,反正在audio tagging里太浪费了,这么多显存干啥不好。。

对抗样本的介绍下面一张图带过了,入门可参考https://zhuanlan.zhihu.com/p/33316527
这里写图片描述

吐槽归吐槽,下面放出实现方案,以及调试过程中各种形式的收益比较
以下结论来自https://www.kaggle.com/c/freesound-audio-tagging-2019

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
### x_mel_shape  ( time_steps, frequency, channels)

## 特征抽取
output = backbone(x_mel)
output = fc_layer(output)

## 计算loss
logloss = Lambda(lambda x: K.mean(K.binary_crossentropy(x[0], x[1]),axis=-1))([y_in, output])

## 计算梯度
g = Lambda(lambda x: tf.stop_gradient(K.gradients(x[0], x[1])[0]),output_shape=x_mel_shape)([logloss, x_mel])
g1 = Lambda(lambda x: cfg.adv_eps * K.sign(x))(g)
g2 = Lambda(lambda x: cfg.adv_eps * x )(g)
因为g2效果好,所以
g = g2

## 生成对抗样本并获得结果
x_adv = Lambda(lambda x:x[0] + x[1])([x_mel,g])
x_adv_fp = backbone(x_adv) # 主干网络
adv_output = fc_layer(x_adv)

## 计算对抗样本的loss
adv_loss1 = Lambda(lambda x: K.mean(K.binary_crossentropy(x[0], x[1]), axis=-1))([y_in, adv_output])
adv_loss2 = Lambda(lambda x: K.mean(K.binary_crossentropy(x[0], x[1]), axis=-1))([output, adv_output])
因为adv_loss2效果好,所以
adv_loss = adv_loss2

## 和正常样本加权平均
loss = Lambda(lambda x:K.mean(cfg.adv_alpha * x[0] + (1-cfg.adv_alpha) * x[1]))([adv_loss,logloss])

model.add_loss(loss)
model.compile(
optimizer=Nadam(lr=cfg.lr),
)