#导入库
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import numpy as np
import matplotlib.pyplot as plt
# 加载mnist数据
mnist_train = torchvision.datasets.MNIST(root = 'D:\\train_datasets\\mnist\\torch_mnist',
transform=torchvision.transforms.ToTensor(),
train=True,
download=True)
train_loader = torch.utils.data.DataLoader(dataset=mnist_train,
batch_size=128,
shuffle=True)
mnist_test = torchvision.datasets.MNIST(root = 'D:\\train_datasets\\mnist\\torch_mnist',
transform=torchvision.transforms.ToTensor(),
train=False,
download=True)
test_loader = torch.utils.data.DataLoader(dataset=mnist_test,
batch_size=10000, # 把所有test图像放入一个batch,后续用自然向量基好提取特征
shuffle=False)
# 创建FC100模型
class FC_model(nn.Module):
def __init__(self):
super(FC_model,self).__init__()
self.layer1 = nn.Sequential(
nn.Linear(28*28,100),
nn.ReLU()
)
self.layer2 = nn.Sequential(
nn.Linear(100,100),
nn.ReLU()
)
self.layer3 = nn.Sequential(
nn.Linear(100,10)
)
def forward(self,x):
x = x.view(-1,28*28)
y_1 = self.layer1(x)
y_2 = self.layer2(y_1)
y_3 = self.layer3(y_2)
return y_1,y_2,y_3 # 因为后面需要提取特征向量,所以把每一层的输出都返回
# 损失函数与优化
FC_100 = FC_model()
Loss = nn.CrossEntropyLoss()
Optimizer_1 = optim.Adam(FC_100.parameters(),lr=0.001, weight_decay=0)
# 训练模型
for epoch in range(10):
for i,(images,labels) in enumerate(train_loader):
X = images
Y = labels
_,_,y = FC_100(X)
cost = Loss(y,Y)
Optimizer_1.zero_grad()
cost.backward()
Optimizer_1.step()
_,y_ = torch.max(y.data,1)
correct = (y_ == Y).sum()
Acc = correct/128.
if (i+1)%128 == 0:
print('Epoch [%d/%d], lter [%d], Loss: %.4f,Acc:%.4f'%(epoch+1, 10, i+1, cost.item(),Acc))
print("Train Finshed")
# 测集上的正确率
total = 0
correct = 0
for images, labels in test_loader:
test_images = images
test_labels = labels
_,_,outputs = FC_100(test_images)
_, predicted = torch.max(outputs.data, 1)
total += len(labels)
correct += (predicted == labels).sum()
print('Accuracy of test images: %.2f %%' % (100 * float(correct) / total))
# 画图函数
def img_show(imgs,title):
imgs = torchvision.utils.make_grid(imgs) # 将多张图拼为一张图,方便图片显示
imgs = imgs.numpy()
font_d = {'size':28}
fig = plt.figure(figsize = (28, 28))
plt.imshow(imgs.transpose(1,2,0))
plt.title(title,fontdict=font_d)
plt.show()
测试Unit函数提取特征,可以看到提取出的图片有基本的特征
# 1.自然向量基
FC_100.eval()
for i in range(5) :
unit_vector_1 = torch.eye(100)[i,:]
for images, labels in test_loader:
_, phi_x_1, _ = FC_100(images)
values_1 = torch.mv(phi_x_1, unit_vector_1)
top_idx_1 = np.argsort(values_1.data.numpy())[-8:]
top_img_1 = images[top_idx_1]
img_show(top_img_1,str(i+1) + "th vector")
# 2.随机向量
for i in range(5) :
unit_vector_2 = torch.rand(100)
for images, labels in test_loader:
_, phi_x_2, _ = FC_100(images)
values_2 = torch.mv(phi_x_2, unit_vector_2)
top_idx_2 = np.argsort(values_2.data.numpy())[-8:]
top_img_2 = images[top_idx_2]
img_show(top_img_2,str(i+1) + "th vector")
print(top_idx_1)
print(top_idx_2)
#output
#[8013 461 2337 9086 2170 6128 6130 6068]
#[6096 923 6333 9409 6139 6123 2080 7117]
实现对抗样本攻击
# 从测试集选取一张没有训练过的图片
attack_img = mnist_test[1][0]
plt.figure()
show_img = np.transpose(attack_img.numpy(),(1,2,0))
plt.imshow(show_img)
plt.show()
for param in FC_model.parameters():
param.requires_grad = False
for num in range(10):
r = torch.rand(1, 28, 28)
r.requires_grad = True
optimizer_adv = optim.Adam([r], lr=0.001)
for i in range(3000):
X = torch.clamp(attack_img + r, 0, 1)
Y = torch.tensor([num])
_,_,outputs = FC_model(X)
_, predicted = torch.max(outputs.data, 1)
loss_adv =0.1*r.abs().sum() + Loss(outputs, Y)
optimizer_adv.zero_grad()
loss_adv.backward(retain_graph=True)
optimizer_adv.step()
if i%100 == 0:
print("Loss_adv={}".format(loss_adv))
if predicted.item() != 2 :
print("Attack successed!")
break
攻击成功后可以看到输出标签是3
增加扰动后得图片显示
plt.figure(figsize=(5,20))
show_img = np.transpose(X.data.numpy()*255,(1,2,0))
plt.imshow(show_img)
plt.show()
可以看到用文献中的方法生成扰动后,能顾实现模型的识别误分类。
代码菜鸟,而且对Pytorch框架还不够熟悉,因此代码写的乱七八糟……大神请飘过。后续需要提高代码能力,以及代码的规范化。