原文地址:https://arxiv.org/abs/1904.08653
代码地址:https://github.com/marvis/pytorch-yolo2
一、算法原理
本文通过训练和添加对抗补丁,实现了一种untargeted攻击,可以使YOLOv2无法识别添加了补丁的人。本文的算法思想如下:
首先将随机生成的对抗补丁贴在图片上,此处应注意本文的对抗补丁的位置并不是任意的,一般是贴在需要被攻击的目标(此处是人)的中心。为了准确的将补丁贴到对应位置,adversarial-yolo算法会从label中找到图片中的目标位置,再向这些位置添加补丁。
添加补丁前,adversarial-yolo会对补丁进行旋转、加噪声、改变亮度等操作,这些操作是为了增加补丁在现实环境中的性能。
在添加完补丁后,将图像传入YOLO模型进行检测,使用YOLO的输出和补丁的一些性质计算loss,loss分三部分,如下:
- dev_loss:yolo输出的置信度
- nps_loss:non-printability score,表示patch不可打印的程度。
- tv_loss:total variation,越小图像越平滑。
dev_loss是最重要的一个loss,说白了,它就是分类置信度(某个网格中存在目标的概率)和目标置信度(某个网格中的目标是某特定类的概率,比如人)的乘积的最大值,这个loss反映的是YOLO模型输出的置信度,我们的目标是要最小化这个置信度,故将其直接用于loss。
nps_loss指补丁无法被打印的程度,它的计算方法如下。c表示所有打印机能打印出的颜色。设置这个loss的目的是为了让生成的补丁能更准确的被打印出来,提高其在现实场景攻击的性能。
tv_loss为相邻像素点的欧式距离,表示图像的平滑程度,平滑变换的图像看上去显得比较真实,也能增加攻击的鲁棒性。
最后的loss = α * tv_loss + β * nps_loss + dev_loss,对这个总loss进行后向传播,就可以更新补丁了。
二、关键代码
1、数据读取补丁的生成和处理
此处对应项目中的load_data.py文件下对于数据读取和补丁添加与处理相对的内容,主要有以下代码:
# 用于对补丁进行各种变换
class PatchTransformer(nn.Module):
...
# 向图片上添加补丁
class PatchApplier(nn.Module):
...
# 读取Inria数据集中的数据,这个数据集可在‘http://pascal.inrialpes.fr/data/’中下载
# 主要类别就是human
class InriaDataset(Dataset):
...
关于这些代码的细节不是很重要,这里就不写了,感兴趣可以自行研究一下。
2、Loss的计算
本部分代码对应load_data.py中的相应部分。
上面说到,文章中loss的计算被分为了三个部分,首先是dev_loss的计算。dev_loss实际上就是YOLO输出的置信度,要解释如何计算dev_loss,首先需要理解YOLOv2的输出格式。本文所使用的YOLO模型最终会输出一个[batch, 5, 85, 19, 19]大小的tensor,其中batch即输入的组数,剩下四个量的意义为:
- 5指的是5个anchor boxes(默认)
- 85是每个格子的输出向量,由bx,by,bw,bh,pc和80个分类的预测概率组成,其中第一个分类(索引号为5)是person
- 19为输出的特征图大小,因为yolo的格子数一般默认定义为19x19
我们所需要的loss就是分类置信度(pc)和一个分类(此处是human)的预测概率。故代码中首先将YOLO的输出变为了[batch, 85, 1805],因为我们需要的东西都在这85组值里,然后提取两个概率:
# 分类置信度,即pc,是85组数里的第5个(序号4),用sigmond处理转化为概率
output_objectness = torch.sigmoid(output[:, 4, :])
# 抛弃掉前五个值,只留后面的目标置信度
output = output[:, 5:5 + self.num_cls , :]
# 用softmax处理转化为概率
normal_confs = torch.nn.S