主要内容
主要讲述通过对原始数据加入细微的噪声得到一组新数据,在新旧两个数据通过人眼难以辨别的情况下,新数据可以欺骗分类器,从而使分类器做出错误的判断。这种方法可以用来攻击一些分类器,并且是完全可行的。
教程以手写数字MINST数据集为例,展示了这种方法。
首先加载包:
from __future__ import print_functionimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimfrom torchvision import datasets, transformsimport numpy as npimport matplotlib.pyplot as plt
加载数据集:
test_loader = torch.utils.data.DataLoader(datasets.MNIST('../data', train=False, download=True, transform=transforms.Compose([transforms.ToTensor(),])),batch_size=1, shuffle=True)
定义一个网络模型(分类器):
class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 10, kernel_size=5)self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d()self.fc1 = nn.Linear(320, 50)self.fc2 = nn.Linear(50, 10)
def forward(self, x):x = F.relu(F.max_pool2d(self.conv1(x), 2))x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = x.view(-1, 320)x = F.relu(self.fc1(x))x = F.dropout(x, training=self.training)x = self.fc2(x)return F.log_softmax(x, dim=1)
定义其他的参数
device = torch.device("cuda" if (use_cuda and torch.cuda.is_available()) else "cpu")#是否CUDAepsilons = [0, .05, .1, .15, .2, .25, .3]#pretrained_model = "data/lenet_mnist_model.pth"#模型的路径
实例化模型
model = Net()#实例化model=model.to(device)#放入GPUmodel.load_state_dict(torch.load(pretrained_model, map_location='cpu'))#将之前训练好的参数加载model.eval()#转化为测试模式
定义FGSM攻击函数
def fgsm_attack(image, epsilon, data_grad):#获取梯度的符号sign_data_grad = data_grad.sign()#在原始图片的基础上加上epsilon成符号perturbed_image = image + epsilon*sign_data_grad#将数值裁剪到0-1的范围内perturbed_image = torch.clamp(perturbed_image, 0, 1)return perturbed_image
sign()函数返回数值的符号,如果为正数返回1,如果为负数返回-1.否则返回0.
测试函数:
def test( model, device, test_loader, epsilon ):correct = 0#攻击之后预测依然正确的个数adv_examples = []#受攻击的样本for data, target in test_loader:data, target = data.to(device), target.to(device)#将数据加载进GPUdata.requires_grad = True#需要保存梯度output = model(data)#利用分类器区分结果init_pred = output.max(1, keepdim=True)[1] #获取最大概率的索引值if init_pred.item() != target.item():#如果分类错误,则不攻击该样本continueloss = F.nll_loss(output, target)#计算损失值model.zero_grad()loss.backward()# 抽取梯度值data_grad = data.grad.data#攻击样本perturbed_data = fgsm_attack(data, epsilon, data_grad)# 再次分类output = model(perturbed_data)final_pred = output.max(1, keepdim=True)[1] # 得到最终分类结果if final_pred.item() == target.item():#如果最终分类结果和真实结果相同correct += 1# 保存epsilon为0if (epsilon == 0) and (len(adv_examples) < 5):adv_ex = perturbed_data.squeeze().detach().cpu().numpy()adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )else:# 保存其他的一些结果,用于后期的可视化操作if len(adv_examples) < 5:adv_ex = perturbed_data.squeeze().detach().cpu().numpy()adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )#计算准确率final_acc = correct/float(len(test_loader))print("Epsilon: {}\tTest Accuracy = {} / {} = {}".format(epsilon, correct, len(test_loader), final_acc))#返回准确率和攻击样例return final_acc, adv_examples
如对于以上代码中 final_pred = output.max(1, keepdim=True)[1]有疑问,请移步至
输出准确率
#依次迭代epsilonfor eps in epsilons:acc, ex = test(model, device, test_loader, eps)accuracies.append(acc)examples.append(ex)
Epsilon: 0 Test Accuracy = 9810 / 10000 = 0.981Epsilon: 0.05 Test Accuracy = 9426 / 10000 = 0.9426Epsilon: 0.1 Test Accuracy = 8510 / 10000 = 0.851Epsilon: 0.15 Test Accuracy = 6826 / 10000 = 0.6826Epsilon: 0.2 Test Accuracy = 4301 / 10000 = 0.4301Epsilon: 0.25 Test Accuracy = 2082 / 10000 = 0.2082Epsilon: 0.3 Test Accuracy = 869 / 10000 = 0.0869
可以发现epsilon越大,则准确度越低,且剧烈下降。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可,转载请附上原文出处链接和本声明。
本文链接地址:https://www.flyai.com/article/artc2d5aeff7778460c86bb7687

本文介绍了一种通过向原始数据添加细微噪声来欺骗分类器的方法,使用手写数字MNIST数据集作为案例,展示了如何实现FGSM攻击并测试其效果。
5329

被折叠的 条评论
为什么被折叠?



