Adversarial Robustness - Theory and Practice

2023-05-16

文章目录

  • 第一章 - Introduction to adversarial robustness
  • 第二章 - linear models
  • 第三章 - Adversarial examples, solving the inner maximization
    • 1.非针对性攻击
    • 2.针对性攻击(基于改进的PGD->the (normalized) steepest descent method)
    • 3.组合优化解决内部最大问题
  • 第四章 - Adversarial training, solving the outer minimization
    • 1. 方案目标
    • 2. 可选择方案
    • 3. 方案实施
    • 4. 代码

Adversarial Robustness - Theory and Practice

第一章 - Introduction to adversarial robustness

我运行Adversarial Robustness-Theory and Practice.introduction代码,加载resnet50,看到在注入噪音后,pig图像被算法误认为是airliner。

第二章 - linear models

(1) 加载MINIST数据集

(2) 对数据进行常规训练,TEST_ERR错误率仅仅0.04%.

(3) 开始进行对抗攻击,随机干扰数EPSILON =0.2

(4) 实行对抗攻击,发现TEST_ERR的错误率从之前的0.04%骤升到85%左右。

(5) 然后进行鲁棒训练,最核心的是MODEL(X.VIEW(X.SHAPE[0], -1))[:,0] - EPSILON*(2*Y.FLOAT()-1)*MODEL.WEIGHT.NORM(1)

(6) 鲁棒训练完成后,任何对抗攻击不会让TEST_ERROR高于2.5%。此时非对抗攻击得到的TEST_ERROR的错误率是0.3%左右(这个结果是大于之前的0.04%的)。这是鲁棒训练20个周期的结果,我测试了下,如果加大训练周期,并不会让结果更优。
也就是说进行鲁棒训练会提升抵抗对抗攻击的能力,但是同时会小幅度提升TEST_ERROR的比率。

第三章 - Adversarial examples, solving the inner maximization

1.非针对性攻击

主要方法是FGSM和PGD。PGD是迭代更新,比FGSM的迭代次数多。但是当梯度很小的时候,传统的PGD的效果也不好,于是出现the (normalized) steepest descent method.相对于传统PGD算法,它的delta.data = (delta + alpha*delta.grad.detach().sign()).clamp(-epsilon,epsilon)。这种改进的PGD的表现仍然受到目标内局部最优可能性的限制,虽然不可能完全避免局部最优,但可以通过随机重启来缓解这个问题。

2.针对性攻击(基于改进的PGD->the (normalized) steepest descent method)

最大化真实label的损失函数,并最小化目标label的损失函数,这相当于解决内部优化问题。下面是几种损失函数设计

(1)loss = (yp[:,y_targ] - yp.gather(1,y[:,None])[:,0]).sum()

缺点:仅仅让非零数字欺骗分类器。原因在于我们是the class logit for the zero minus the class logit for the true class. 但是我们实际上并不关心其他类的情况。所以我们可以修改损失函数为下面这种。

(2)loss = 2*yp[:,y_targ].sum() - yp.sum()

缺点:不能达到100%正确率。

(3) 占个位,这个不太懂。

3.组合优化解决内部最大问题

有一些寻找边界区间界限的方法,但是被轻微扰动后,区间界限上下浮动比较大,不实用。最终用的方法是混合整数线性规划策略。代码部分主要是利用cvxpy构建了很多constraints。

关于优化这部分内容不需要细看。如果细看的话,估计2年也看不完。大概知道做什么的就行了。

第四章 - Adversarial training, solving the outer minimization

1. 方案目标

The goal of the robust optimization formulation, therefore, is to ensure that the model cannot be attacked even if the adversary has full knowledge of the model.
In other words, no matter what attack an adversary uses, we want to have a model that performs well.

2. 可选择方案

2.1 local gradient-based search (providing a lower bound on the objective) 基于局部梯度的搜索
2.2 exact combinatorial optimization (exactly solving the objective) 精确的组合优化 (不实用)
2.3. convex relaxations (providing a provable upper bound on the objective) 凸松弛

但是经过分析,法2不实用,最终的可行方案是下面两个

2.1.Using lower bounds, and examples constructed via local search methods, to train an (empirically) adversarially robust classifier.
2.3Using convex upper bounds, to train a provably robust classifier.

3. 方案实施

The basic idea is to simply create and then incorporate adversarial examples into the training process
the question arises as to which adversarial examples we should train on?

4. 代码

4.1 加载minist数据集
4.2 初始化model_cnn
4.3 定义fgsm、pgd函数
4.4 定义标准训练函数、对抗攻击函数
4.5 进行联合训练(基于cnn)

  opt = optim.SGD(model_cnn.parameters(), lr=1e-1)
   for t in range(10):
       train_err, train_loss = epoch(train_loader, model_cnn, opt)
       test_err, test_loss = epoch(test_loader, model_cnn)
       adv_err, adv_loss = epoch_adversarial(test_loader, model_cnn, pgd_linf)
       if t == 4:
           for param_group in opt.param_groups:
               param_group["lr"] = 1e-2
       print(*("{:.6f}".format(i) for i in (train_err, test_err, adv_err)), sep="\t")
   	
   torch.save(model_cnn.state_dict(), "model_cnn.pt") 

So as we saw before, the clean error is quite low, but the adversarial error is quite high (and actually goes up as we train the model more). Let’s now do the same thing, but with adversarial training.
4.6 做一些happy的事情

opt = optim.SGD(model_cnn_robust.parameters(), lr=1e-1)
for t in range(10):
    train_err, train_loss = epoch_adversarial(train_loader, model_cnn_robust, pgd_linf, opt)
    test_err, test_loss = epoch(test_loader, model_cnn_robust)
    adv_err, adv_loss = epoch_adversarial(test_loader, model_cnn_robust, pgd_linf)
    if t == 4:
        for param_group in opt.param_groups:
            param_group["lr"] = 1e-2
    print(*("{:.6f}".format(i) for i in (train_err, test_err, adv_err)), sep="\t")
torch.save(model_cnn_robust.state_dict(), "model_cnn_robust.pt")

pretty good!

4.7 对比两个不同的cnn

  model_cnn_robust = nn.Sequential(nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(),
                                    nn.Conv2d(32, 32, 3, padding=1, stride=2), nn.ReLU(),
                                    nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
                                    nn.Conv2d(64, 64, 3, padding=1, stride=2), nn.ReLU(),
                                    Flatten(),
                                    nn.Linear(7*7*64, 100), nn.ReLU(),
                                    nn.Linear(100, 10)).to(device)
   								 
   model_cnn = nn.Sequential(nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(),
                             nn.Conv2d(32, 32, 3, padding=1, stride=2), nn.ReLU(),
                             nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
                             nn.Conv2d(64, 64, 3, padding=1, stride=2), nn.ReLU(),
                             Flatten(),
                             nn.Linear(7*7*64, 100), nn.ReLU(),
                             nn.Linear(100, 10)).to(device)

额额,一模一样…

4.8 对抗攻击?对抗训练?
损失函数的目标是最小化。
在chapter 1里,通过在损失函数前加符号,可以控制损失函数最大化和最小化。而且损失函数可以联合训练哦。
在chapter 3里,仅仅攻击训练,而不去反向传播更新权值,会大化损失函数(相当于改变了输入)。
在chapter 4里,通过对有干扰(fgsm或者pgd产生的对抗样本)的输入的损失函数最小化,相当于进行了对抗训练。

4.9 完美收官
经过对抗训练后,贼6!

4.10 凸优化
4.10.1 策略一
注:对比chapter 3 bound_propagation 是一样的

def bound_propagation(model, initial_bound):
   l, u = initial_bound
   bounds = []
   
   for layer in model:
       if isinstance(layer, Flatten):
           l_ = Flatten()(l)
           u_ = Flatten()(u)
       elif isinstance(layer, nn.Linear):
           l_ = (layer.weight.clamp(min=0) @ l.t() + layer.weight.clamp(max=0) @ u.t() 
                 + layer.bias[:,None]).t()
           u_ = (layer.weight.clamp(min=0) @ u.t() + layer.weight.clamp(max=0) @ l.t() 
                 + layer.bias[:,None]).t()
       elif isinstance(layer, nn.Conv2d):
           l_ = (nn.functional.conv2d(l, layer.weight.clamp(min=0), bias=None, 
                                      stride=layer.stride, padding=layer.padding,
                                      dilation=layer.dilation, groups=layer.groups) +
                 nn.functional.conv2d(u, layer.weight.clamp(max=0), bias=None, 
                                      stride=layer.stride, padding=layer.padding,
                                      dilation=layer.dilation, groups=layer.groups) +
                 layer.bias[None,:,None,None])
           
           u_ = (nn.functional.conv2d(u, layer.weight.clamp(min=0), bias=None, 
                                      stride=layer.stride, padding=layer.padding,
                                      dilation=layer.dilation, groups=layer.groups) +
                 nn.functional.conv2d(l, layer.weight.clamp(max=0), bias=None, 
                                      stride=layer.stride, padding=layer.padding,
                                      dilation=layer.dilation, groups=layer.groups) + 
                 layer.bias[None,:,None,None])
           
       elif isinstance(layer, nn.ReLU):
           l_ = l.clamp(min=0)
           u_ = u.clamp(min=0)
           
       bounds.append((l_, u_))
       l,u = l_, u_
   return bounds

注:对比chapter 3 bound_propagation 有差异 添加了idx

    def interval_based_bound(model, c, bounds, idx):
        # requires last layer to be linear
        cW = c.t() @ model[-1].weight
        cb = c.t() @ model[-1].bias
        
        l,u = bounds[-2]
        return (cW.clamp(min=0) @ l[idx].t() + cW.clamp(max=0) @ u[idx].t() + cb[:,None]).t()    

注:新添加

    def robust_bound_error(model, X, y, epsilon):
        initial_bound = (X - epsilon, X + epsilon)
        err = 0
        for y0 in range(10):
            C = -torch.eye(10).to(device)
            C[y0,:] += 1
            err += (interval_based_bound(model, C, bounds, y==y0).min(dim=1)[0] < 0).sum().item()
        return err

注:新添加

    def epoch_robust_bound(loader, model, epsilon):
        total_err = 0
        
        C = [-torch.eye(10).to(device) for _ in range(10)]
        for y0 in range(10):
            C[y0][y0,:] += 1
        
        for X,y in loader:
            X,y = X.to(device), y.to(device)
            initial_bound = (X - epsilon, X + epsilon)
            bounds = bound_propagation(model, initial_bound)
            for y0 in range(10):
                lower_bound = interval_based_bound(model, C[y0], bounds, y==y0)
                total_err += (lower_bound.min(dim=1)[0] < 0).sum().item()
        return total_err / len(loader.dataset)

That doesn’t seem particularly useful, and indeed, it is a property of virtually all the relaxation-based verification approaches, is that they are vaccuous when evaluated upon a network trained without knowledge of these bounds.

4.10.2 策略二 Training using provable criteria
if we train a network specifically to minimize a loss based upon this upper bound, we get a network where the bounds are meaningful. This is a somewhat subtle but important point which is worth repeating.

    def epoch_robust_bound(loader, model, epsilon, opt=None):
        total_err = 0
        total_loss = 0
        
        C = [-torch.eye(10).to(device) for _ in range(10)]
        for y0 in range(10):
            C[y0][y0,:] += 1
        
        for X,y in loader:
            X,y = X.to(device), y.to(device)
            initial_bound = (X - epsilon, X + epsilon)
            bounds = bound_propagation(model, initial_bound)
            loss = 0
            for y0 in range(10):
                if sum(y==y0) > 0:
                    lower_bound = interval_based_bound(model, C[y0], bounds, y==y0)
                    loss += nn.CrossEntropyLoss(reduction='sum')(-lower_bound, y[y==y0]) / X.shape[0]
                    total_err += (lower_bound.min(dim=1)[0] < 0).sum().item()
            total_loss += loss.item() * X.shape[0]  
            #print(loss.item())
            if opt:
                opt.zero_grad()
                loss.backward()
                opt.step()
        return total_err / len(loader.dataset), total_loss / len(loader.dataset)

!!!Finally, let’s train our model using this robust loss bound. Note that training rovably robust models is a bit of a tricky business. If we start out immediately by trying to train our robust bound with the full ϵ=0.1, the model will collapse to just predicting equal probability for all digits, and will never recover. Instead, to reliably train such models we need to schedule ϵ during the training process, starting with a small ϵ and gradually raising it to the desired level. The schedule we use below was picked rather randomly, and we can do much better with a bit of tweaking, but it serves our basic purpose.

    torch.manual_seed(0)
    model_cnn_robust_2 = nn.Sequential(nn.Conv2d(1, 32, 3, padding=1, stride=2), nn.ReLU(),
                                       nn.Conv2d(32, 32, 3, padding=1, ), nn.ReLU(),
                                       nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
                                       nn.Conv2d(64, 64, 3, padding=1, stride=2), nn.ReLU(),
                                       Flatten(),
                                       nn.Linear(7*7*64, 100), nn.ReLU(),
                                       nn.Linear(100, 10)).to(device)
    								   
    opt = optim.SGD(model_cnn_robust_2.parameters(), lr=1e-1)
    eps_schedule = [0.0, 0.0001, 0.001, 0.01, 0.01, 0.05, 0.05, 0.05, 0.05, 0.05] + 15*[0.1]
    
    print("Train Eps", "Train Loss*", "Test Err", "Test Robust Err", sep="\t")
    for t in range(len(eps_schedule)):
        train_err, train_loss = epoch_robust_bound(train_loader, model_cnn_robust_2, eps_schedule[t], opt)
        test_err, test_loss = epoch(test_loader, model_cnn_robust_2)
        adv_err, adv_loss = epoch_robust_bound(test_loader, model_cnn_robust_2, 0.1)
        #if t == 4:
        #    for param_group in opt.param_groups:
        #        param_group["lr"] = 1e-2
    
        print(*("{:.6f}".format(i) for i in (eps_schedule[t], train_loss, test_err, adv_err)), sep="\t")
    torch.save(model_cnn_robust_2.state_dict(), "model_cnn_robust_2.pt")

Train Eps Train Loss* Test Err Test Robust Err
0.000000 0.829700 0.033800 1.000000
0.000100 0.126095 0.022200 1.000000
0.001000 0.119049 0.021500 1.000000
0.010000 0.227829 0.019100 1.000000
0.010000 0.129322 0.022900 1.000000
0.050000 1.716497 0.162200 0.828500
0.050000 0.744732 0.092100 0.625100
0.050000 0.486411 0.073800 0.309600
0.050000 0.393822 0.068100 0.197800
0.050000 0.345183 0.057100 0.169200
0.100000 0.493925 0.068400 0.129900
0.100000 0.444281 0.067200 0.122300
0.100000 0.419961 0.063300 0.117400
0.100000 0.406877 0.061300 0.114700
0.100000 0.401603 0.061500 0.116400
0.100000 0.387260 0.059600 0.111100
0.100000 0.383182 0.059400 0.108500
0.100000 0.375468 0.057900 0.107200
0.100000 0.369453 0.056800 0.107000
0.100000 0.365821 0.061300 0.116300
0.100000 0.359339 0.053600 0.104200
0.100000 0.358043 0.053000 0.097500
0.100000 0.354643 0.055700 0.101500
0.100000 0.352465 0.053500 0.096800
0.100000 0.348765 0.051500 0.096700

    print("PGD, 40 iter: ", epoch_adversarial(test_loader, model_cnn_robust_2, pgd_linf, num_iter=40)[0])

PGD, 40 iter: 0.0779

So somewhere right in the middle. Note also that training these provably robust models is a challenging task, and a bit of tweaking (even still using interval bounds) can perform quite a bit better. For now, though, this is sufficient to make our point that we can obtain non-trivial provable bounds for trained networks.

Notes:还有很长的路要走…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Adversarial Robustness - Theory and Practice 的相关文章

随机推荐

  • 全国DNS服务器IP地址大全详细介绍

  • Nginx之TCP/UDP反向代理

    Nginx从1 9 13起开始发布ngx stream core module模块不仅能支持TCP代理及负载均衡 其实也是支持UDP协议的 1 Nginx下载 wget http nginx org download nginx 1 24
  • 【无标题】

    错误代码 root 64 xxx nginx sbin nginx t nginx emerg unknown directive 34 stream 34 in usr local nginx conf nginx conf 118 ng
  • pm2常用的命令用法介绍

    pm2 是一个带有负载均衡功能的Node应用的进程管理器 当你要把你的独立代码利用全部的服务器上的所有CPU 并保证进程永远都活着 0秒的重载 PM2是完美的 下面我们来看pm2常用的命令用法介绍吧 PM2 xff08 github上的源码
  • 华为CE12808更换主控板

    在更换主控板的过程中 xff0c 务必缓慢 平稳地插拔单板 xff0c 避免左右晃动而导致触碰相邻单板 xff0c 造成正在运行中的单板发生故障 在主控板拔插的过程中严禁用手接触单板上的元器件 xff0c 以免损坏单板 新的主控板在出厂时已
  • 迪普防火墙FW1000普通双击热备配置

    一 组网图 二 端口聚合配置 三 配置三层接口地址 四 配置普通双机热备 五 配置安全域 六 配置地址对象 七 配置服务对象 八 配置静态路由 九 配置VRRP 十 配置NAT地址池 十一 配置源NAT 十二 配置目的NAT 十三 配置包过
  • 迪普防火墙F1000静默双击热备配置

    一 组网图 二 创建端口聚合 三 配置心跳接口IP地址 四 配置静默双击热备 五 配置三层接口IP地址 六 配置安全域 七 配置地址对象 八 配置服务对象 九 配置静态路由 十 配置NAT地址池 十一 配置源NAT 十二 配置目的NAT 十
  • Zabbix用户及用户组权限概述

    本文简单介绍用户及用户组权限 xff0c 参考官方文档 xff1a https www zabbix com documentation 5 2 manual config users and usergroups 一 概述 Zabbix
  • 使用nginx反向代理MRCP SERVER

    MRCP V2 的消息组成 MRCP xff08 V2 xff09 的交互过程可以分为三部分 1 SIP交互 xff1a Session Initiation Protocol xff0c 缩写SIP 正如协议的名称所言 xff0c 用于初
  • 一文搞懂如何使用STM32驱动直流电机(普通PWM输出和L298N、高级定时器输出带死区双通道互补PWM和IR2110S及自举电路、H桥电路和电机正反转)

    本文将用最通俗易懂的语言讲解怎么使用STM32驱动直流电机 xff0c 以及在使用过程中容易遇到的问题和解决办法 本文将介绍两种驱动方式 xff1a 普通PWM驱动L298N驱动直流电机 xff1b 互补PWM驱动IR2110S驱动直流电机
  • Linux —— 线程池

    目录 一 什么是线程池 二 线程池的优点 三 线程池的应用 四 实现一个简单的线程池 五 单例模式 1 饿汉实现方式 2 懒汉实现方式 3 单例模式实现线程池 xff08 懒汉方式 xff09 六 其他常见的各种锁 一 什么是线程池 线程池
  • 跟我一起写Shell脚本之二十二--常用命令(xargs)

    1 介绍 xargs 是一个强有力的命令 xff0c 它能够捕获一个命令的输出 xff0c 然后传递给另外一个命令 命令格式 xff1a xargs options command 选项 xff1a a file 从文件中读入作为 stdi
  • 解决Win10笔记本电脑Wifi频繁断线的问题

    Win10无线总是掉线怎么回事 经常有网友抱怨 xff0c 电脑升级Win10之后 xff0c 无线网络经常容易掉线或者不稳定的情况 有时候即便是勾选了自动连接Wifi xff0c 断线后也不会自动连接 Win10笔记本Wifi总是断线解决
  • 国内各个界面库比较,告诉你怎么选择界面库?

    目前网络上的界面库多彩多样 这里以个人的观点 xff0c 来评价一下界面库 如果有不当的地方望批评指出 1 Skin 43 43 www uipower com 该界面库是基于WIN32的界面库 xff0c 以上海勇进公司的形式来运作 xf
  • Docker端口映射

    为什么要端口映射 xff1f 在启动容器时 xff0c 如果不配置宿主机器与虚拟机的端口映射 xff0c 外部程序是无法访问虚拟机的 xff0c 因为没有端口 端口映射的指令是什么 xff1f docker指令 xff1a docker r
  • pyqt QStatusBar显示提示信息

    span class token keyword from span PyQt5 span class token keyword import span QtCore span class token keyword from span
  • 打jar包出现错误: The packaging for this project did not assign a file to the build artifact

    转载 xff1a 打jar包出现错误 xff1a The packaging for this project did not assign a file to the build artifact 曼彻斯特的天空是红色的的博客 CSDN博
  • 常见错误——使用CP命令复制目录出现 omitting directory 错误

    错误名称 omitting directory 使用命令 cp 描述 在Linux下使用cp命令拷贝对象时 xff0c 若出现了 omitting directory 错误 xff0c 确认CP命令复制的对象是否为非空目 录 在复制非空目录
  • 个人简历

    大家好 xff1a 本人系重庆大学2003级硕士研究生 xff0c 将于2006年7月毕业 相关技能 xff1a 1 计算机 xff1a 熟悉计算机软 硬件体系结构 xff0c 了解计算机接口技术 xff1b 熟悉C 43 43 汇编等语言
  • Adversarial Robustness - Theory and Practice

    文章目录 第一章 Introduction to adversarial robustness第二章 linear models第三章 Adversarial examples solving the inner maximization1