李宏毅hw-10 ——adversarial attack

一、查漏补缺:
1.关于glob.glob的用法,返回一个文件路径的 列表:

当然,再套用1个sort,就是将所有的文件路径按照字母进行排序了

2.relpath == relative_path返回相对于基准路径的相对路径的函数

二、代码剖析:
1.加载对应的数据 和 引入必要的库+环境设置:
# set up environment
!pip install pytorchcv
!pip install imgaug# download
!wget https://github.com/DanielLin94144/ML-attack-dataset/files/8167812/data.zip# unzip
!unzip ./data.zip
!rm ./data.zipimport torch
import torch.nn as nndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
batch_size = 8
# the mean and std are the calculated statistics from cifar_10 dataset
cifar_10_mean = (0.491, 0.482, 0.447) # mean for the three channels of cifar_10 images
cifar_10_std = (0.202, 0.199, 0.201) # std for the three channels of cifar_10 images# convert mean and std to 3-dimensional tensors for future operations
mean = torch.tensor(cifar_10_mean).to(device).view(3, 1, 1)
std = torch.tensor(cifar_10_std).to(device).view(3, 1, 1)epsilon = 8/255/std #这个epsilon就是边界的限制root = './data' # directory for storing benign images
# benign images: images which do not contain adversarial perturbations
# adversarial images: images which include adversarial perturbations
2.关于Dataset的设计部分的研读:
#引入必要的库
import os
import glob
import shutil
import numpy as np
from PIL import Image
from torchvision.transforms import transforms
from torch.utils.data import Dataset, DataLoader
#定义全局的transform方式
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize(cifar_10_mean, cifar_10_std)
])
#定义这200张adv_picture的攻击方式
#虽然没有看作业视频,但是我估计这个 AdvDataset不过是对选定的200张图片 最终攻击成为 目标的 names
class AdvDataset(Dataset):def __init__(self, data_dir, transform):self.images = []self.labels = []self.names = []'''data_dir├── class_dir│   ├── class1.png│   ├── ...│   ├── class20.png'''for i, class_dir in enumerate(sorted(glob.glob(f'{data_dir}/*'))): #data_dir下面有很多个class_dirimages = sorted(glob.glob(f'{class_dir}/*'))         #class_dir下面有很多的class1.png、class2.png。。。。self.images += images                    #将这个class_dir下面的png的绝对地址依次加到全局的images列表中  self.labels += ([i] * len(images))             #对应的label中加上i这个数值 总共加上该class_dir中的png数目self.names += [os.path.relpath(imgs, data_dir) for imgs in images] #relpath == relative_path相对路径self.transform = transformdef __getitem__(self, idx):image = self.transform(Image.open(self.images[idx]))   label = self.labels[idx]return image, label    #返回 代开后的png+经过transform之后的image对象 以及对应的label(这个label还是原来的label)def __getname__(self):return self.names     #返回的name就是class_dir/class2.png这种东西def __len__(self):return len(self.images)#获取adv_dataloader 和 对应的names
adv_set = AdvDataset(root, transform=transform)
adv_names = adv_set.__getname__()
adv_loader = DataLoader(adv_set, batch_size=batch_size, shuffle=False)print(f'number of images = {adv_set.__len__()}')
3.调用原来训练好的图像分类的model:
# to evaluate the performance of model on benign images
#这个就是原来训练好的图像分类识别的model进行eval,得到对应的dataloader的loss 和 acc
def epoch_benign(model, loader, loss_fn):model.eval()train_acc, train_loss = 0.0, 0.0for x, y in loader:x, y = x.to(device), y.to(device)yp = model(x)loss = loss_fn(yp, y)train_acc += (yp.argmax(dim=1) == y).sum().item()train_loss += loss.item() * x.shape[0]return train_acc / len(loader.dataset), train_loss / len(loader.dataset)
4.总共3中生成adv_image的方式,分别是 fgsm, ifgsm ,mifgsm:

它们的想法都是 输入一张图片,然后利用已经train好的分类器的model得到对应的loss和grad,然后利用这个grad的sign将这张图片在“空间”中“反向”移动(原来我们是" -eta*grad" 现在我们是“+eta*grad”)一些,以致于之后分类器分类出来的和目标label的有区别

(目前mifgsm没有实作,具体实作可以参考这篇paper1710.06081.pdf (arxiv.org))

#定义FGSM一次就达到目的的攻击方式的对应的函数
# perform fgsm attack
def fgsm(model, x, y, loss_fn, epsilon=epsilon):x_adv = x.detach().clone() # initialize x_adv as original benign image xx_adv.requires_grad = True # need to obtain gradient of x_adv, thus set required gradloss = loss_fn(model(x_adv), y) # calculate lossloss.backward() # calculate gradient# fgsm: use gradient ascent on x_adv to maximize lossgrad = x_adv.grad.detach()x_adv = x_adv + epsilon * grad.sign() #直接一锤定音,grad.sign就是正取1,负取-1,一拳超人return x_adv#总共有fgsm , ifgsm ,mifgsm 这3种model,最开始只要理解fgsm的工作方式就好了
# alpha and num_iter can be decided by yourself ,
alpha = 0.8/255/std #其实我觉得,按照李宏毅老师的讲法,这个alpha应该是8/255/std也就是和epsilon的大小一致才对
#哦!原来这里是ifgsm,所以会有20个iter,所以alpha的数值 只取到 epsilon的1/10
def ifgsm(model, x, y, loss_fn, epsilon=epsilon, alpha=alpha, num_iter=20): #参数是model,x图像,y标签,总共20个iterx_adv = x# write a loop of num_iter to represent the iterative timesfor i in range(num_iter):# x_adv = fgsm(model, x_adv, y, loss_fn, alpha) # call fgsm with (epsilon = alpha) to obtain new x_advx_adv = x_adv.detach().clone()x_adv.requires_grad = True # need to obtain gradient of x_adv, thus set required gradloss = loss_fn(model(x_adv), y) # calculate lossloss.backward() # calculate gradient# fgsm: use gradient ascent on x_adv to maximize lossgrad = x_adv.grad.detach()x_adv = x_adv + alpha * grad.sign() #得到攻击之后的图像x_adv',计算方法和李宏毅老师讲到的一致x_adv = torch.max(torch.min(x_adv, x+epsilon), x-epsilon) # clip new x_adv back to [x-epsilon, x+epsilon]return x_adv#让我再看看这个mifgsm到底是个啥东西呢,也就是要额外加上一个momentum的处理 和 decay是吧
#其实,这个mifgsm就是再ifgsm的基础上,类似于原来gradient descend可能遇到的问题一样,都要借助前一次的momentum动量进行处理
def mifgsm(model, x, y, loss_fn, epsilon=epsilon, alpha=alpha, num_iter=20, decay=1.0):x_adv = x# initialze momentum tensormomentum = torch.zeros_like(x).detach().to(device) #一开始设定的momentum的数值就是和x的大小完全一样的全0# write a loop of num_iter to represent the iterative timesfor i in range(num_iter):x_adv = x_adv.detach().clone()x_adv.requires_grad = True # need to obtain gradient of x_adv, thus set required gradloss = loss_fn(model(x_adv), y) # calculate lossloss.backward() # calculate gradient# TODO: Momentum calculation# grad = .....#。。。有待进一步添加计算momentum的代码,应该会用到参数里面的decay这个参数x_adv = x_adv + alpha * grad.sign()x_adv = torch.max(torch.min(x_adv, x+epsilon), x-epsilon) # clip new x_adv back to [x-epsilon, x+epsilon]return x_adv
5.调用上面的fgsm或者ifgsm生成对应 adv_image并进行存储,之后再用model进行预测:
# perform adversarial attack and generate adversarial examples
#调用上述定义的 adv_attack的方法,并且生成对应的 图片的攻击后 图像
def gen_adv_examples(model, loader, attack, loss_fn):model.eval()adv_names = []train_acc, train_loss = 0.0, 0.0for i, (x, y) in enumerate(loader):x, y = x.to(device), y.to(device)x_adv = attack(model, x, y, loss_fn) # obtain adversarial examples ,获取到攻击后的图像yp = model(x_adv)       #攻击后的图像的预测结果yploss = loss_fn(yp, y)    #和原来label之间的losstrain_acc += (yp.argmax(dim=1) == y).sum().item()train_loss += loss.item() * x.shape[0]#上面已经用model生成了我们需要的x_adv的攻击后图像,下面只是对这张图像进行 反向还原罢了# store adversarial examplesadv_ex = ((x_adv) * std + mean).clamp(0, 1) # to 0-1 scaleadv_ex = (adv_ex * 255).clamp(0, 255) # 0-255 scaleadv_ex = adv_ex.detach().cpu().data.numpy().round() # round to remove decimal part,利用round函数取出小数点adv_ex = adv_ex.transpose((0, 2, 3, 1)) # transpose (bs, C, H, W) back to (bs, H, W, C)adv_examples = adv_ex if i == 0 else np.r_[adv_examples, adv_ex]return adv_examples, train_acc / len(loader.dataset), train_loss / len(loader.dataset)#将adv攻击之后的图片 和 对应的攻击需要 绑定的label存储到对应的文件路径种
# create directory which stores adversarial examples
def create_dir(data_dir, adv_dir, adv_examples, adv_names):if os.path.exists(adv_dir) is not True:_ = shutil.copytree(data_dir, adv_dir)for example, name in zip(adv_examples, adv_names):im = Image.fromarray(example.astype(np.uint8)) # image pixel value should be unsigned intim.save(os.path.join(adv_dir, name))
6.实例化已经train过的model 和 需要使用的loss_fn:
from pytorchcv.model_provider import get_model as ptcv_get_model#这里直接使用了已经train好的ciFar-10的图像分类识别的model
model = ptcv_get_model('resnet110_cifar10', pretrained=True).to(device)
loss_fn = nn.CrossEntropyLoss() #loss直接使用crossEntropybenign_acc, benign_loss = epoch_benign(model, adv_loader, loss_fn)
print(f'benign_acc = {benign_acc:.5f}, benign_loss = {benign_loss:.5f}')
7.上面都是定义哈,这里才是真正的调用fgsm 和 ifgsm生成对应的 adv_图像:
#调用fgsm的结果是:
adv_examples, fgsm_acc, fgsm_loss = gen_adv_examples(model, adv_loader, fgsm, loss_fn)
print(f'fgsm_acc = {fgsm_acc:.5f}, fgsm_loss = {fgsm_loss:.5f}')create_dir(root, 'fgsm', adv_examples, adv_names)
adv_examples, ifgsm_acc, ifgsm_loss = gen_adv_examples(model, adv_loader, ifgsm, loss_fn)
print(f'ifgsm_acc = {ifgsm_acc:.5f}, ifgsm_loss = {ifgsm_loss:.5f}')create_dir(root, 'ifgsm', adv_examples, adv_names)
8.总共10个类别的CiFAR-10,每个类别分别show出1张攻击前后的图像 以及 经过同一个model的预测结果:
#这里做的事情,就是输出利用这个训练好的model,分别输入攻击前 和 攻击后的图片, 然后得到的各自的pred的概率
import matplotlib.pyplot as pltclasses = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']plt.figure(figsize=(10, 20))
cnt = 0
for i, cls_name in enumerate(classes): #10个种类,每个种类展示1.png那个图片攻击前后的识别结果path = f'{cls_name}/{cls_name}1.png'# benign imagecnt += 1plt.subplot(len(classes), 4, cnt)im = Image.open(f'./data/{path}')   #这一段 和 下面一段的唯一的区别 只是打开的图片的文件不同罢了logit = model(transform(im).unsqueeze(0).to(device))[0]predict = logit.argmax(-1).item()prob = logit.softmax(-1)[predict].item()plt.title(f'benign: {cls_name}1.png\n{classes[predict]}: {prob:.2%}')plt.axis('off')plt.imshow(np.array(im))# adversarial imagecnt += 1plt.subplot(len(classes), 4, cnt)im = Image.open(f'./fgsm/{path}')logit = model(transform(im).unsqueeze(0).to(device))[0]predict = logit.argmax(-1).item()prob = logit.softmax(-1)[predict].item()plt.title(f'adversarial: {cls_name}1.png\n{classes[predict]}: {prob:.2%}')plt.axis('off')plt.imshow(np.array(im))plt.tight_layout()
plt.show()
9.对1张狗狗的图像,用原来的model可以识别它是dog,但是经过adv_攻击后的图像在model中识别就会变成cat,
最后,我们将这个adv_攻击图像 经过1个JPEG压缩,然后再通过model识别,就成功抵御了这个adv_攻击:
#这一部分只不过是对上面的那段代码的 单次循环的版本而已
# original image
path = f'dog/dog2.png'
im = Image.open(f'./data/{path}')
logit = model(transform(im).unsqueeze(0).to(device))[0]
predict = logit.argmax(-1).item()
prob = logit.softmax(-1)[predict].item()
plt.title(f'benign: dog2.png\n{classes[predict]}: {prob:.2%}')
plt.axis('off')
plt.imshow(np.array(im))
plt.tight_layout()
plt.show()# adversarial image 
adv_im = Image.open(f'./fgsm/{path}')
logit = model(transform(adv_im).unsqueeze(0).to(device))[0]
predict = logit.argmax(-1).item()
prob = logit.softmax(-1)[predict].item()
plt.title(f'adversarial: dog2.png\n{classes[predict]}: {prob:.2%}')
plt.axis('off')
plt.imshow(np.array(adv_im))
plt.tight_layout()
plt.show()

#为啥这里还有1个defence的部分捏,好奇怪哦
#虾米那就是干了这么一件事情,就是对adv攻击之后产生的图片 再通过1个JPEG的压缩,然后再用model进行pred
#观察,这个adv攻击是否就已经失效了
#我觉得,最大的成就感,来源于自己的创造,不是光读懂别人代码就行了,那样也迟早会劝退
#而是要,创造自己的那部分!那样,你才会更想去做这件事情
#所以,就先完成下面这个JPEG压缩的部分吧,有chatGPT,怕什么,什么都可以独立的实现,多花时间,自然能多收获import imgaug.augmenters as iaa# pre-process image
x = transforms.ToTensor()(adv_im)*255
x = x.permute(1, 2, 0).numpy()
x = x.astype(np.uint8)# TODO: use "imgaug" package to perform JPEG compression (compression rate = 70)
# compressed_x =  ... x .. 
seq = iaa.JpegCompression(compression=70)
compressed_x = seq.augment_image(x)logit = model(transform(compressed_x).unsqueeze(0).to(device))[0]
predict = logit.argmax(-1).item()
prob = logit.softmax(-1)[predict].item()
plt.title(f'JPEG adversarial: dog2.png\n{classes[predict]}: {prob:.2%}')
plt.axis('off')plt.imshow(compressed_x)
plt.tight_layout()
plt.show()

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

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

相关文章

STM32单片机入门学习(四)-蜂鸣器

蜂鸣器接线 低平蜂鸣器,低电平发声,高电平不发声, 三个排针,VCC接3.3v,GND接地,I/O接A0口,如图: 蜂鸣器代码:响一秒停半秒 #include "stm32f10x.h" #includ…

LRU、LFU 内存淘汰算法的设计与实现

1、背景介绍 LRU、LFU都是内存管理淘汰算法,内存管理是计算机技术中重要的一环,也是多数操作系统中必备的模块。应用场景:假设 给定你一定内存空间,需要你维护一些缓存数据,LRU、LFU就是在内存已经满了的情况下&#…

2023-2024年最新大数据学习路线

文章目录 2023-2024年最新大数据学习路线大数据开发入门*01*阶段案例实战 大数据核心基础*02*阶段案例实战 千亿级数仓技术*03*阶段项目实战 PB级内存计算04阶段项目实战 亚秒级实时计算*05*阶段项目实战 大厂面试*06* 2023-2024年最新大数据学习路线 新路线图在Spark一章不再…

Android跨进程通信:Binder机制原理

目录 1. Binder到底是什么? 2. 知识储备 2.1 进程空间划分 2.2 进程隔离 & 跨进程通信( IPC ) 2.3 内存映射 2.3.1 作用 2.3.2 实现过程 2.3.3 特点 2.3.4 应用场景 2.3.5 实例讲解 ① 文件读 / 写操作 ② 跨进程通信 3. Bi…

Cron表达式_用于定时调度任务

一、Cron表达式简介 Cron表达式是一个用于设置计划任务的字符串,该字符串以5或6个空格分隔,分为6或7个域,每一个域代表任务在相应时间、日期或时间间隔执行的规则【Cron表达式最初是在类Unix操作中系统中使用的,但现在已经广泛应用…

人机融合需要在事实与价值之间构建新型的拓扑关系

人机融合,这是指将人类智慧(含艺术)与计算机科技相结合,共同解决复杂问题的一种新方式。在人机融合中,我们需要构建事实与价值之间的新型拓扑关系,以实现更有效的知识管理和决策支持。 事实是指客观存在的、…

Python爬虫爬取豆瓣电影短评(爬虫入门,Scrapy框架,Xpath解析网站,jieba分词)

声明:以下内容仅供学习参考,禁止用于任何商业用途 很久之前就想学爬虫了,但是一直没机会,这次终于有机会了 主要参考了《疯狂python讲义》的最后一章 首先安装Scrapy: pip install scrapy 然后创建爬虫项目&#…

力扣26:删除有序数组中的重复项

26. 删除有序数组中的重复项 - 力扣(LeetCode) 题目: 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 …

Leetcode 95. 不同的二叉搜索树 II

文章目录 题目代码&#xff08;9.21 首刷看解析&#xff09; 题目 Leetcode 95. 不同的二叉搜索树 II 代码&#xff08;9.21 首刷看解析&#xff09; class Solution { public:vector<TreeNode*> generateTrees(int n) {return build(1,n);}vector<TreeNode*> bu…

将本地前端工程中的npm依赖上传到Nexus

【问题背景】 用Nexus搭建了内网的依赖仓库&#xff0c;需要将前端工程中node_modules中的依赖上传到Nexus上&#xff0c;但是node_modules中的依赖已经是解压后的状态&#xff0c;如果直接机械地将其简单地打包上传到Nexus&#xff0c;那么无法通过npm install下载使用。故有…

Jenkins Job的Migrate之旅

场景 使用Jenkins 做为应用的定时任务处理&#xff0c; 在上面建立的800个左右的Job, 这个环境运行了很多年&#xff0c; 当初安装的最新版本是Jenkins 1.642.3&#xff0c; 现在因为OS需要升级等原因&#xff0c; 驻在上面的Jenkins 服务器也需要一并升级&#xff0c;在新的服…

Mock.js之Element-ui搭建首页导航与左侧菜单

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《springMvc使用》 ⛺️ 生活的理想&#xff0c;为了不断更新自己 ! 1、Mock.js的使用 1.1.什么是Mock.js Mock.js是一个模拟数据的生成器&#xff0c;用来帮助前…

浅谈C++|文件篇

C中的文件操作是通过使用文件流来实现的。文件流提供了对文件的输入和输出功能。下面是C文件操作的基本步骤&#xff1a; 1. 包含头文件&#xff1a;首先&#xff0c;包含 <fstream> 头文件&#xff0c;它包含了进行文件操作所需的类和函数。 2 . 进行文件读写操作&#…

9领域事件

本系列包含以下文章&#xff1a; DDD入门DDD概念大白话战略设计代码工程结构请求处理流程聚合根与资源库实体与值对象应用服务与领域服务领域事件&#xff08;本文&#xff09;CQRS 案例项目介绍 # 既然DDD是“领域”驱动&#xff0c;那么我们便不能抛开业务而只讲技术&…

Windows专业版的Docker下载、安装与启用Kubenetes、访问Kubernetes Dashboard

到Docker 官网https://www.docker.com/ 下载windows操作系统对应的docker软件安装 Docker Desktop Installer-Win.exe 2023-09版本是4.23 下载后双击安装 重启windows后&#xff0c;继续安装 接受服务继续安装 解决碰到的Docker Engine stopped 打开 控制面板》程序》启用或关…

软件测试/测试开发丨利用人工智能ChatGPT自动生成PPT

点此获取更多相关资料 简介 PPT 已经渗透到我们的日常工作中&#xff0c;无论是工作汇报、商务报告、学术演讲、培训材料都常常要求编写一个正式的 PPT&#xff0c;协助完成一次汇报或一次演讲。PPT相比于传统文本的就是有布局、图片、动画效果等&#xff0c;可以给到观众更好…

第一百五十四回 如何实现滑动菜单

文章目录 概念介绍实现方法示例代码体验分享 我们在上一章回中介绍了滑动窗口相关的内容相关的内容&#xff0c;本章回中将介绍如何实现 滑动菜单.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的滑动菜单表示屏幕上向左或者向右滑动滑动时弹…

自注意力机制

回顾以下注意力机制&#xff1a; 自注意力机制 Self-Attention的关键点 在于 K ≈ \approx ≈V ≈ \approx ≈Q 来源于同一个X&#xff0c;三者是同源的&#xff0c;通过 W Q W_Q WQ​, W K W_K WK​, W V W_V WV​做了一层线性变换。 接下来步骤和注意力机制一模一样。 …

基于微信小程序的线上教育课程付费商城(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

【项目实战】Linux系统下jar包自启动

什么是jar包自启动 在Linux系统中&#xff0c;"jar包自启动"是指通过配置将Java程序打包成可执行的Jar文件&#xff0c;并设置其在系统启动时自动运行。以下是与jar包自启动相关的一些概念&#xff1a; Jar文件&#xff1a;Jar&#xff08;Java Archive&#xff09…