Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击

  • CIFAR数据集
  • NI-FGSM介绍
    • 背景
    • 算法流程
  • NI-FGSM代码实现
    • NI-FGSM算法实现
    • 攻击效果
  • 代码汇总
    • nifgsm.py
    • train.py
    • advtest.py

之前已经针对CIFAR10训练了多种分类器:
Pytorch | 从零构建AlexNet对CIFAR10进行分类
Pytorch | 从零构建Vgg对CIFAR10进行分类
Pytorch | 从零构建GoogleNet对CIFAR10进行分类
Pytorch | 从零构建ResNet对CIFAR10进行分类
Pytorch | 从零构建MobileNet对CIFAR10进行分类
Pytorch | 从零构建EfficientNet对CIFAR10进行分类
Pytorch | 从零构建ParNet对CIFAR10进行分类

本篇文章我们使用Pytorch实现NI-FGSM对CIFAR10上的ResNet分类器进行攻击.

CIFAR数据集

CIFAR-10数据集是由加拿大高级研究所(CIFAR)收集整理的用于图像识别研究的常用数据集,基本信息如下:

  • 数据规模:该数据集包含60,000张彩色图像,分为10个不同的类别,每个类别有6,000张图像。通常将其中50,000张作为训练集,用于模型的训练;10,000张作为测试集,用于评估模型的性能。
  • 图像尺寸:所有图像的尺寸均为32×32像素,这相对较小的尺寸使得模型在处理该数据集时能够相对快速地进行训练和推理,但也增加了图像分类的难度。
  • 类别内容:涵盖了飞机(plane)、汽车(car)、鸟(bird)、猫(cat)、鹿(deer)、狗(dog)、青蛙(frog)、马(horse)、船(ship)、卡车(truck)这10个不同的类别,这些类别都是现实世界中常见的物体,具有一定的代表性。

下面是一些示例样本:

在这里插入图片描述

NI-FGSM介绍

NI-FGSM(Nesterov Iterative Fast Gradient Sign Method)即涅斯捷罗夫迭代快速梯度符号法,是一种在对抗攻击领域中对FGSM进行改进的迭代攻击算法,以下是其详细介绍:

背景

  • 传统的FGSM及其一些迭代改进版本如I-FGSM等,在生成对抗样本时存在一些局限性,例如可能会在迭代过程中陷入局部最优,导致攻击效果不够理想或生成的对抗样本转移性较差。NI-FGSM借鉴了优化算法中的Nesterov加速梯度法的思想,旨在更有效地利用梯度信息,提高攻击的效率和效果。

算法流程

  1. 初始化
    • 设定参数:确定最大扰动幅度 ϵ \epsilon ϵ、迭代次数 T T T、步长 α = ϵ / T \alpha = \epsilon / T α=ϵ/T、衰减因子 μ \mu μ
    • 初始化变量:令初始累积梯度 g 0 = 0 g_0 = 0 g0=0,初始对抗样本 x 0 a d v = x x_0^{adv}=x x0adv=x x x x 为原始图像)。
  2. 迭代过程
    • 对于每次迭代 t = 0 t = 0 t=0 T − 1 T - 1 T1
      • 计算跳跃点 x t n e s = x t a d v + α ⋅ μ ⋅ g t x_t^{nes}=x_t^{adv}+\alpha \cdot \mu \cdot g_t xtnes=xtadv+αμgt
      • 计算跳跃点 x t n e s x_t^{nes} xtnes 在模型中的梯度 ∇ x J ( x t n e s , y t r u e ) \nabla_{x} J\left(x_t^{nes }, y^{true }\right) xJ(xtnes,ytrue)
      • 累积梯度更新: g t + 1 = μ ⋅ g t + ∇ x J ( x t n e s , y t r u e ) ∥ ∇ x J ( x t n e s , y t r u e ) ∥ 1 g_{t + 1}=\mu \cdot g_t+\frac{\nabla_{x} J\left(x_t^{nes }, y^{true }\right)}{\left\| \nabla_{x} J\left(x_t^{nes}, y^{true }\right)\right\| _{1}} gt+1=μgt+xJ(xtnes,ytrue)1xJ(xtnes,ytrue)
      • 更新对抗样本: x t + 1 a d v = C l i p x ϵ { x t a d v + α ⋅ s i g n ( g t + 1 ) } x_{t + 1}^{adv}=Clip_{x}^{\epsilon}\left\{x_t^{adv}+\alpha \cdot sign\left(g_{t + 1}\right)\right\} xt+1adv=Clipxϵ{xtadv+αsign(gt+1)},其中 C l i p x ϵ Clip_{x}^{\epsilon} Clipxϵ 函数将生成的对抗样本限制在原始图像 x x x ϵ \epsilon ϵ 邻域内。
  3. 输出结果:返回最终生成的对抗样本 x T a d v x_T^{adv} xTadv

在整个算法流程中,通过引入Nesterov加速梯度的思想,在每次迭代计算梯度之前先进行跳跃操作,从而利用先前累积梯度的信息来更有效地更新对抗样本,使得生成的对抗样本具有更好的转移性,能够在不同模型上保持较高的攻击成功率。

NI-FGSM代码实现

NI-FGSM算法实现

import torch
import torch.nn as nndef NI_FGSM(model, criterion, original_images, labels, epsilon, num_iterations=10, decay=1):"""NI-FGSM (Nesterov Iterative Fast Gradient Sign Method)参数:- model: 要攻击的模型- criterion: 损失函数- original_images: 原始图像- labels: 原始图像的标签- epsilon: 最大扰动幅度- num_iterations: 迭代次数- decay: 动量衰减因子"""# alpha 每次迭代步长alpha = epsilon / num_iterations# 复制原始图像作为初始的对抗样本perturbed_images = original_images.clone().detach().requires_grad_(True)momentum = torch.zeros_like(original_images).detach().to(original_images.device)for _ in range(num_iterations):# 先沿先前累积梯度的方向进行跳跃nes_images = perturbed_images + alpha * decay * momentumnes_images = nes_images.clone().detach().requires_grad_(True)outputs = model(nes_images)loss = criterion(outputs, labels)model.zero_grad()loss.backward()data_grad = nes_images.grad.data# 更新动量 (batch_size, channels, height, width)momentum = decay * momentum + data_grad / torch.sum(torch.abs(data_grad), dim=(1, 2, 3), keepdim=True)# 计算带动量的符号梯度sign_data_grad = momentum.sign()# 更新对抗样本perturbed_images = perturbed_images + alpha * sign_data_gradperturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)return perturbed_images

攻击效果

在这里插入图片描述

代码汇总

nifgsm.py

import torch
import torch.nn as nndef NI_FGSM(model, criterion, original_images, labels, epsilon, num_iterations=10, decay=1):"""NI-FGSM (Nesterov Iterative Fast Gradient Sign Method)参数:- model: 要攻击的模型- criterion: 损失函数- original_images: 原始图像- labels: 原始图像的标签- epsilon: 最大扰动幅度- num_iterations: 迭代次数- decay: 动量衰减因子"""# alpha 每次迭代步长alpha = epsilon / num_iterations# 复制原始图像作为初始的对抗样本perturbed_images = original_images.clone().detach().requires_grad_(True)momentum = torch.zeros_like(original_images).detach().to(original_images.device)for _ in range(num_iterations):# 先沿先前累积梯度的方向进行跳跃nes_images = perturbed_images + alpha * decay * momentumnes_images = nes_images.clone().detach().requires_grad_(True)outputs = model(nes_images)loss = criterion(outputs, labels)model.zero_grad()loss.backward()data_grad = nes_images.grad.data# 更新动量 (batch_size, channels, height, width)momentum = decay * momentum + data_grad / torch.sum(torch.abs(data_grad), dim=(1, 2, 3), keepdim=True)# 计算带动量的符号梯度sign_data_grad = momentum.sign()# 更新对抗样本perturbed_images = perturbed_images + alpha * sign_data_gradperturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)return perturbed_images

train.py

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import ResNet18# 数据预处理
transform_train = transforms.Compose([transforms.RandomCrop(32, padding=4),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])transform_test = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 加载Cifar10训练集和测试集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)# 定义设备(GPU或CPU)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 初始化模型
model = ResNet18(num_classes=10)
model.to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)if __name__ == "__main__":# 训练模型for epoch in range(10):  # 可以根据实际情况调整训练轮数running_loss = 0.0for i, data in enumerate(trainloader, 0):inputs, labels = data[0].to(device), data[1].to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()if i % 100 == 99:print(f'Epoch {epoch + 1}, Batch {i + 1}: Loss = {running_loss / 100}')running_loss = 0.0torch.save(model.state_dict(), f'weights/epoch_{epoch + 1}.pth')print('Finished Training')

advtest.py

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import *
from attacks import *
import ssl
import os
from PIL import Image
import matplotlib.pyplot as pltssl._create_default_https_context = ssl._create_unverified_context# 定义数据预处理操作
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])# 加载CIFAR10测试集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128,shuffle=False, num_workers=2)# 定义设备(GPU优先,若可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = ResNet18(num_classes=10).to(device)criterion = nn.CrossEntropyLoss()# 加载模型权重
weights_path = "weights/epoch_10.pth"
model.load_state_dict(torch.load(weights_path, map_location=device))if __name__ == "__main__":# 在测试集上进行FGSM攻击并评估准确率model.eval()  # 设置为评估模式correct = 0total = 0epsilon = 16 / 255  # 可以调整扰动强度for data in testloader:original_images, labels = data[0].to(device), data[1].to(device)original_images.requires_grad = Trueattack_name = 'NI-FGSM'if attack_name == 'FGSM':perturbed_images = FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'BIM':perturbed_images = BIM(model, criterion, original_images, labels, epsilon)elif attack_name == 'MI-FGSM':perturbed_images = MI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'NI-FGSM':perturbed_images = NI_FGSM(model, criterion, original_images, labels, epsilon)perturbed_outputs = model(perturbed_images)_, predicted = torch.max(perturbed_outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = 100 * correct / total# Attack Success RateASR = 100 - accuracyprint(f'Load ResNet Model Weight from {weights_path}')print(f'epsilon: {epsilon}')print(f'ASR of {attack_name} : {ASR}%')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/65060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

继承详细总结

一.继承的定义与概念 1.定义:继承是一种is-a的关系,例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。 2.允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数) 和 属…

批量多线程给TXT文档插入相关腾讯AI【高质量无水印无版权】原创图片

给蜘蛛访问的网站文章插入相关图片,可以带来以下好处: ‌1、提升用户体验‌:图片能够直观地展示文章内容,帮助用户更好地理解和消化信息。对于阅读者来说,图文并茂的内容往往更具吸引力,也能提高他们的阅读…

牵手红娘:牵手App红娘助力“牵手”,脱单精准更便捷

随着互联网的普及,现代青年的社交圈层加速扩大,他们的恋爱观也正经历着前所未有的转变。在繁忙的工作之余,人们希望能够找到一种既高效又真诚的交友方式。于是,线上交友平台成为了他们寻找爱情的新选择。让不同文化背景、不同工作…

STM32-笔记12-实现SysTick模拟多线程流水灯

1、前言 正常STM32实现多线程,需要移植一个操作系统FreeRTOS。但是在这里不移植FreeRTOS怎么实现多线程呢?使用SysTick,那么怎么使用SysTick来模拟多线程呢?前面我们知道SysTick就是一个定时器,它不是在主函数的while循…

麒麟信安受邀出席开放原子园区行暨供需对接活动,分享基于关基领域打造的行业解决方案

12月17日,武汉市经信局和开放原子开源基金会共同主办开放原子园区行暨供需对接活动,旨在推进武汉市开源体系建设,推动开源技术赋能千行百业。活动吸引了武汉市委金融办、市卫健委、疾控中心、医保局、信息中心(大数据中心)、市红十字会、银行…

Everspin代理MR25H10CDFR存储MRAM

RAMSUN提供的MR25H10CDFR是一款具备1,048,576位存储容量的磁阻随机存取存储器(MRAM)设备,由131,072个8位字构成。该设备提供与串行EEPROM和串行闪存兼容的读/写时序,无写延迟,并且其读/写寿命是不受限制的。 与其它串…

golang 并发--goroutine(四)

golang 语言最大的特点之一就是语法上支持并发,通过简单的语法很容易就能创建一个 go 程,这就使得 golang 天生适合写高并发的程序。这一章节我们就主要介绍 go 程,但是要想完全理解 go 程我们需要深入研究 GPM 模型,关于 GPM 模型…

三维模型中的UV展开是什么意思?它有什么优势?

UV展开涉及将三维模型的表面展开为一个或多个二维区域,以便将纹理图像正确地映射到模型上。这个过程类似于将一个立体物体的表面切割并平铺开来。UV坐标是用于在二维纹理图像中定位颜色和细节的坐标系统,U和V分别代表纹理图像的水平和垂直轴。 UV展开它…

SpringAI人工智能开发框架006---SpringAI多模态接口_编程测试springai多模态接口支持

可以看到springai对多模态的支持. 同样去创建一个项目 也是跟之前的项目一样,修改版本1.0.0 这里 然后修改仓库地址,为springai的地址 然后开始写代码

JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中

本文为Oracle数据库JSON学习系列的第一篇,讲述如何将JSON文档存储到数据库中,包括了版本为19c和23ai的情形。 19c中的JSON 先来看一下数据库版本为19c时的情形。 创建表colortab,其中color列的长度设为4000。若color的长度需要设为32767&a…

hhdb客户端介绍(51)

功能模块设计 数据可视化与报表 报表生成 基于数据库中的数据,允许用户创建自定义报表,可选择报表的数据源(表、视图或查询结果)、报表布局(表格、图表等)、字段显示、分组与汇总方式等,满足…

SOME/IP 协议详解——信息格式

文章目录 1. 头部格式1.1 消息 ID(Message ID)1.2 长度(Length)1.3 请求 ID(Request ID)1.4 协议版本(Protocol Version):1.5 接口版本(Interface Version&am…

Spring学习(一)——Sping-XML

一、Spring的概述 (一)什么是Spring? Spring是针对bean对象的生命周期进行管理的轻量级容器。提供了功能强大IOC、AOP及Web MVC等功能。Spring框架主要由七部分组成:分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 S…

用 gdbserver 调试 arm-linux 上的 AWTK 应用程序

很多嵌入式 linux 开发者都能熟练的使用 gdb/lldb 调试应用程序,但是还有不少朋友在调试开发板上的程序时,仍然在使用原始的 printf。本文介绍一下使用 gdbserver 通过网络调试开发板上的 AWTK 应用程序的方法,供有需要的朋友参考。 1. 下载 …

ubuntu 24.04-无域名创建本机和局域网和同网段局域网机器可访问的https网页服务

1. 安装nginx, apt install nginx apt install nginx 2. 创建nginx.conf配置文件: gedit /etc/nginx/nginx.conf 3. 配置文件内容如下: user snake; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid;# L…

树莓派换源

查询自己版本: lsb_release -a bullseye可以理解为树莓派的系统代号(10,11,12都不同,一定要看好自己系统是什么版本) 查询架构 uname -a aarch64的地方就是代表系统架构的,我的是aarch64的架…

SMMU软件指南SMMU编程之虚拟机结构和缓存

安全之安全(security)博客目录导读 目录 一、虚拟机结构(VMS) 二、缓存 一、虚拟机结构(VMS) 虚拟机结构(VMS)是SMMU中的概念,是一个由STE.VMSPtr字段指向的结构,包含每个虚拟机的配置设置。在相同安全状态下具有相同虚拟机ID(VMID)的多个STE必须指向相同的VMS。…

php中 cli和cgi的区别

在PHP中,CLI(Command Line Interface)和CGI(Common Gateway Interface)是两种不同的运行PHP脚本的方式,它们各自有不同的用途和特点。 CLI(Command Line Interface) 用途&#xff…

Java中的实用时间API

Java中的时间API有数种,如Date或LocalDateTime,笔者根据实际的开发经验,在这里罗列出一些常用并且尽可能通用的时间API操作,避免由于记忆过多无效API导致效率低下的问题 目录 LocalDateTime LocalDateTime 与 String 的相互转换…

html 中 表格和表单的关系与区别

在 HTML 中&#xff0c;表格 (<table>) 和表单 (<form>) 是两种常用于展示数据和收集用户输入的元素。它们具有不同的功能和结构。以下是关于这两者的详细介绍&#xff1a; 1. HTML 表格&#xff08;<table>&#xff09; 表格用于展示结构化的数据&#xf…