最后两周!60万奖金AI攻防赛来了!(附baseline代码及实操)

Datawhale

共 6955字,需浏览 14分钟

 ·

2021-09-02 21:43


今年6月,由OPPO发起,OPPO安全主办的“OPPO安全AI挑战赛”正式拉开序幕。比赛主要聚焦人脸识别场景中的对抗攻击。为了模拟真实的人脸识别场景并增加比赛的难度,组织者在后台使用了一组已经添加了防御措施的识别模型,要求参赛选手在不知道这些后台模型具体细节的前提下,对它们进行黑盒攻击。

本次比赛已经入最后两周冲刺阶段(9月15日截止报名与组队),还没有报名的同学可借助本次分享的2篇baseline分享快速上手实战。扫描下方二维码,或点击阅读原文即可前往大赛官网报名参赛。


赛题介绍

比赛任务

本次比赛主要使用人脸识别数据集,具体的图片来自公开数据集 CASIA-FaceV5 和 CelebA 中的人脸图片。每个人都有2-5张不同图片,并被保存在一个文件夹中(如./images/0/,./images/1/…)。


参赛者需要修改这些图片,并保留原始图片尺寸和数据集目录结构。同时,对图片的修改必须足够微小。关于扰动的添加对于图像质量的影响,比赛组织者采用添加了扰动 Lp 范数和 Full Reference-IQA (FR-IQA) 来进行评价,其中 FR-IQA 部分将采用 MS-SSIM 图像结构相似性指标来进行量化。


除了自动判断外,在线下决赛环节,组织者还会对对抗样本的肉眼视觉差异进行更加严格的评判,即对抗样本和原始样本的视觉差异越小越好。


在把数据集提交到系统后,后台的防御模型会对上传数据集进行预测。攻击数据集要尽量让防御模型产生错误的结果。当攻击不成功时,得分为0,当攻击成功时,得分由扰动添加前后的图像差异大小来衡量,对原图的影响越小得分越高。最终得分由扰动大小和判断原图片和修改后图片的图像质量评分(multi-scale structural similarity)共同决定。


赛程与奖励

【大赛赛程】

06月18日-09月15日|组队报名

07月12日-09月15日|线上初赛

09月26日-10月21日|线上复赛

11月|线下决赛


【奖金设置】

总奖金60万元

冠军:15万元

亚军(2支队伍):每支队伍9万元

季军(3支队伍):每支队伍5万元

优胜奖(4支队伍):每支队伍3万元

大赛地址:https://security.oppo.com/challenge/home.html


baseline分享

作者:刘羽中

科大讯飞AI金牌讲师,多次在国内数据竞赛中获得优异成绩,曾获四维图新自动驾驶算法赛冠军,爱奇艺视频版权检测三等奖,微众人脸对抗优胜奖。擅长计算机视觉和深度学习相关应用。

代码链接:https://pan.baidu.com/s/1QYJ5azudMqWMqKv57MjpzA

提取码: cr9p


数据集分析

赛题数据从公开数据集`CASIA-FaceV5`、`CelebA`中抽取人脸图像,这些人脸图片分属于不同的人物对象。


每个对象拥有约2~5张图片,并且已经进行了人脸区域裁剪,且裁剪至正方形尺寸。

人脸尺寸

赛题人脸图片并没有缩放操作,而保留了原图尺寸,即图片的尺寸各不相同,选手可以按照自身的需要进行缩放操作。


选手提交结果数据(对抗样本)时需要保证每张图片的尺寸大小和测试数据的原始图像大小保持一致。



基础思路

赛题任务为典型的黑盒无目标攻击,需要选手对给定的图片进行「加噪」,以得到与原图尽可能相似的对抗样本。


由于对抗样本具有传递性,可以使用已有的人脸识别模型来进行黑盒攻击。即使用开源的人脸识别模型来生成对抗样本。


步骤1:加载人脸模型

为了保证模型的便捷性,这里我们选择了Pytorch版本的InsightFace实现,安装方法如下:

# https://github.com/nizhib/pytorch-insightface
pip install git+https://github.com/nizhib/pytorch-insightface

加载iresnet34人脸识别模型:

import insightface
model = insightface.iresnet34(pretrained=True)
model.eval()

步骤2:提取比赛人脸特征

使用iresnet34模型对初赛数据集的2000张照片提取特征,这里只需要做正向传播即可。

img_feats = torch.zeros(2000, 512).float().cuda()
idx_img = 0
with torch.no_grad():
    for img_data, _ in train_loader:
        feat = m(img_data.cuda())
        img_feats[idx_img, :] = feat
        idx_img += 1

进而对特征进行归一化,保证计算人脸相似度保持在0-1之间:

import torch.nn.functional as F
img_feats = F.normalize(img_feats, p=2, dim=1)

步骤3:多步FGSM攻击

FGSM(Fast Gradient Sign Method)是经典有效的对抗样本产生方法,具体思路如下:

  • 扰动变化量与梯度的变化方向一致,则误差函数就会增大。
  • 使用Sign函数保证了扰动同梯度方向一致,对分类结果产生最大化改变。

由于比赛是无目标攻击,所以具体的攻击步骤如下:

  • 步骤1:计算人脸特征相似度,选择与当前人脸最相似的人脸作为攻击目标。
  • 步骤2:执行单步FSGM产生对抗样本,并对扰动大小进行截断。
  • 步骤3:重复多次步骤2,直到目标人脸的概率值达到阈值。

具体实现代码如下:

def one_step_attack(source_idx, aim_idx=10):
    # 计算人脸相似度,得到攻击目标
    aim_idx = torch.matmul(
     img_feats[source_idx].view(1, 512), img_feats.T
    )[0].argsort()[-5].item()
    
    # 读取原始人脸图片
    ori_image = cv2.imread(paths[source_idx])
    img = preprocess(transforms.ToPILImage()(ori_image))
    img = img.reshape(-1, 3, 112, 112).cuda() 
    img_ori = img.clone().detach()
    
    img_adv = None
    best = 0
    
    # 执行多步扰动,记录最优结果
    for _ in range(50):
        # 每次对扰动后的图像都需要重新计算特征
        img = Variable(img, requires_grad=True)
        img_embedding = model(img.cuda())
        img_embedding = F.normalize(img_embedding, p=2, dim=1)
        feat_ids = torch.matmul(img_embedding, img_feats.T)
        objective_aim = feat_ids[0][aim_idx]
        objective_source = feat_ids[0][source_idx]
        
        if objective_aim.item() - objective_source.item() > best and objective_aim.item() == feat_ids[0].max().item():
            img_adv = img.clone().detach()
        
        model.zero_grad()
        objective_aim.backward()
        
        # 根据梯度信息,单步FGSM
        data_grad = img.grad.data.sign() * 0.0075
        with torch.no_grad():
            delta_diff = img + Variable(data_grad) - img_ori
            delta_diff = torch.clamp(delta_diff, min=-0.13, max=0.13)
            img = img_ori + delta_diff
    
    return img, img_ori

(滑动查看完整代码)

步骤4:保存测试集攻击结果

对于测试集每张照片,重复上述操作得到对抗样本,并进行保存为原始格式。

for idx in range(len(paths)):    
    path1, path2 = paths[idx].split('/')[-2:]
    
    img1, img2 = one_step_attack(idx)
    img1 = unorm(img1[0])
    img1 = img1.data.cpu().numpy().round()
    img1 = np.clip(img1, 1, 255)
    img1 = img1.transpose([1, 2, 0])
    
    h, w = cv2.imread(paths[idx]).shape[:2]
    img1 = cv2.resize(img1, (h, w))
    cv2.imwrite(f'./images/{path1}/{path2}', img1)



赛题进阶思路

1. 本次比赛是黑盒攻击,建议在本地构建验证集。即使用人脸识别模型B对人脸识别模型A产生的对抗样本进行验证,模拟线上的打分。


2. 赛题人脸图像尺度大小不一,但现有的人脸识别模型大都接受112*112的输入尺寸,因此使用pooling代替图片缩放操作。

大尺寸图片 -> 图片缩放 -> 人脸识别模型
大尺寸图片 -> pooling -> 人脸识别模型


Baseline在初赛线上评测得分44分,代码链接:https://pan.baidu.com/s/1QYJ5azudMqWMqKv57MjpzA

提取码: cr9p

由于篇幅原因,本篇文字介绍主要以第一篇baseline为例。

第二篇baseine参考如下:

代码:https://pan.baidu.com/s/1QYJ5azudMqWMqKv57MjpzA 提取码: cr9p

文章链接:baseline | OPPO 安全AI挑战赛,人脸识别对抗攻击赛题详解


点击阅读原文报名参赛

浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报