FGSM敵対的攻撃アルゴリズムの実装

        この記事はブロガーが人工知能等の分野を勉強する際に、個人的な勉強・研究・鑑賞用に記録した勉強の抜粋・メモであり、ブロガーの人工知能等の分野に対する理解に基づいたものです。権利侵害につきましては、ご指摘がございましたら速やかに修正させていただきますので、ご理解賜りますようお願い申し上げます。Pytorchでの記事の分類:

       Pytorch (3) --- FGSM 敵対的攻撃アルゴリズムの実装」

FGSM敵対的攻撃アルゴリズムの実装

目次

1. 実験目的  

2. 実験内容

3. 原理の紹介

4. コード分析

5. 運用結果


1. 実験目的  

        高速勾配シンボル攻撃 (FGSM) の使用法をマスターして、前の実験で得た深層学習畳み込みニューラル ネットワーク CNN 手書き数字認識モデルに対して敵対的攻撃を実行し、MNIST 分類器を欺きます。


2. 実験内容

        Fast Gradient Sign Attack (FGSM) は、Fast Gradient Sign Attack と呼ばれ、ニューラル ネットワークの学習方法である勾配更新を直接使用してニューラル ネットワークを攻撃します。この攻撃は、損失を最大化するために同じ逆伝播勾配に従って入力データを調整します。つまり、攻撃では、入力データに関連する勾配損失法を使用して、入力データを調整することで損失を最大化します。

        参考文献: https://arxiv.org/abs/1412.6572


3. 原理の紹介

        コードに入る前に、有名な FGSM pandas の例を見て、いくつかの表記を抜粋してみましょう。

        上の図は、ディープ ネットワークに適用された高速敵対的な例を示しています。人間には知覚できない小さなベクトルを追加することにより、そのベクトルの値に、誤差に対する入力ピクセルの勾配値の符号値が ϵ 乗算されます。ここで ϵ=0.007 は、ディープ ネットワークによって実数に変換された後の 8 ビット画像エンコードの最小桁数と一致します。画像にノイズを追加した後、パンダはテナガザルとして識別され、信頼度は 99.3% であるため、この方法は高速勾配符号法 (略して FGSM) と呼ばれ、高速勾配降下法と呼ばれます。結果として生じる摂動画像 x' は、明らかに「パンダ」であるにもかかわらず、ターゲット ネットワークによって誤って「テナガザル」として分類されます。

        次に、FGSM アルゴリズムの原理とコードによる敵対的攻撃の実装プロセスについて説明します。


4. コード分析

        コードを実行する前に、実行プロセス中に使用される可能性のあるツールキットをインポートする必要があります。

# -*- coding: utf-8 -*-
import torch.nn as nn
import torch.nn.functional as F
import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
use_cuda = True
device = torch.device("cuda" if (use_cuda and torch.cuda.is_available()) else "cpu")

モデル定義とテストデータのロード

        まず、ネットワーク構造と入出力を含む分類モデルを定義する必要があります。ここでのネット定義とテスト データの読み込みは、前のセクションの MNIST 認識のコードと似ています。

# LeNet 模型定义
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() # dropout层
        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) # dropout层
        x = self.fc2(x) # 全连接层
        return F.log_softmax(x, dim=1) # 输出


# MNIST 测试数据集和数据加载器声明
transform = transforms.Compose([transforms.ToTensor()]) #数据类型定义为Tensor张量
test_dataset = datasets.MNIST(root='./data/', train=False, download=False, transform=transform)  # train=True训练集,=False测试集
test_loader = DataLoader(test_dataset, batch_size=1, shuffle=True) # 批大小为1,打乱数据

# 自动选择 GPU 或 CPU
print("CUDA Available: ",torch.cuda.is_available())
device = torch.device("cuda" if (use_cuda and torch.cuda.is_available()) else "cpu")

攻撃を受けるモデルを定義する

        まず、ネット ネットワークを初期化する必要があります。その後、事前トレーニングされたモデルを攻撃対象のモデル オブジェクトとしてインポートします。ここでの事前トレーニングされたモデルは、実験の前のセクションでトレーニングおよび保存されたモデルにすることも、ダウンロードして保存することもできます。ローカルで提供されている事前トレーニング済みモデルを使用します。モデルをトレーニングし、事前トレーニング済みモデルの重みを読み込みます。

# 初始化网络
model = Net().to(device)

# 加载预训练模型,可以是自己训练好的模型,也可用本地提供的模型lenet_mnist_model.pth
# 添加加载预训练模型的相对路径(路径的前缀可用"./"代替)
pretrained_model =  "./lenet_mnist_model.pth"
model.load_state_dict(torch.load(pretrained_model, map_location='cpu'))

# 将模型设置为评估模式。在本例中,这是针对 Dropout layers 的
model.eval()

FGSM攻撃の実装

これで、次の方法で敵対的な例を作成する関数を定義できます。

fgsm_attach 関数には 3 つの入力が必要です。image は元のクリーンなイメージ (x)、epsilon はピクセルレベルの摂動 (ϵ)、data_grad は入力イメージの損失の勾配です。データの元の範囲を維持するために、摂動イメージは [0, 1] の範囲にトリミングされます。最後に、異なる外乱サイズの下での攻撃効果を調査するために、外乱の量に異なる値が設定されます。

ここで学生は、敵対的なサンプルを生成するためのコード行を追加する必要があります。

# FGSM attack code
def fgsm_attack(image, epsilon, data_grad):  # 此函数的功能是进行fgsm攻击,需要输入三个变量,干净的图片,扰动量和输入图片梯度
    sign_data_grad = data_grad.sign()  # 梯度符号
    # print(sign_data_grad)
    #对抗样本perturbed_image由原始图像叠加epsilon像素级扰动量epsilon与梯度符号sign_data_grad的乘积组成
    perturbed_image = image + epsilon*sign_data_grad
    perturbed_image = torch.clamp(perturbed_image, 0, 1)  # 为了保持图像的原始范围,将受干扰的图像裁剪到一定的范围【0,1】
    return perturbed_image

epsilons = [0, .05, .1, .15, .2, .25, .3]

テスト攻撃効果

        最後に、この実験の核となる結果はテスト モジュールから得られます。このテスト関数を呼び出すたびに、MNIST テスト セットに対して完全なテスト ステップが実行され、最終的な精度が報告されます。ただし、この関数はイプシロン入力も受け取ることに注意してください。これは、「テスト」関数が強力な敵対者 ϵ からの攻撃を受けているモデルの精度を報告するためです。より具体的には、テスト セット内のサンプルごとに、関数は入力データ (data_grad) の損失を計算し、「fgsm_攻撃」による摂動画像 (perturbed_data) を生成します。これがモデルに入力されて、敵対的であるかどうかを検証します。この関数は、モデルの精度をテストすることに加えて、実験の最後の部分で視覚化するために、いくつかの成功した敵対的例を保存して返します。

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)
        data.requires_grad = True
        #添加代码表示模型(model)的输出output,已知模型(model)的输入为data
        # 此处的model已在前面定义过,此处直接调用即可
        output = model(data)
        init_pred = output.max(1, keepdim=True)[1]  # 选取最大的类别概率
        loss = 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
        if len(adv_examples) < 6:
            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


accuracies = []
examples = []

攻撃を実行する

実装の最後の部分は、実際に攻撃を実行することです。ここでは、イプシロン入力の ϵ の各値に対して完全なテスト ステップを実行します。各 ε について、最終的な精度といくつかの成功した結果も保存します。次のコンテンツでは、いくつかの敵対的な例を列挙します。ε の値が増加すると、モデルの精度が低下することに注意してください。また、ϵ=0 は元のテスト精度を表す、つまり攻撃が実行されないことにも注意してください。

# Run test for each epsilon
for eps in epsilons:
    acc, ex = test(model, device, test_loader, eps)
    accuracies.append(acc)
    examples.append(ex)

結果分析

        比較分析のために精度と ϵ を組み合わせます。最初の結果は、精度と ϵ の関係です。前述したように、実験の初期段階で ϵ が増加すると、テスト精度が低下すると予想されます。これは、ϵ が大きいほど、元の画像が勾配方向の損失を最大化することを意味するためです。実験結果も私たちの推測を裏付けました。

plt.figure(figsize=(5,5))
plt.plot(epsilons, accuracies, "*-")
plt.title("Accuracy vs Epsilon")
plt.xlabel("Epsilon")
plt.ylabel("Accuracy")
plt.plot(epsilons, accuracies)

敵対的な例を表示する

実験の最後に、さまざまな摂動値イプシロンの下で敵対的な例を視覚化できます。各敵対サンプルの上には、サンプルの元のラベルと攻撃後の分類ラベルが表示されており、図から、摂動値が 0.15 の場合、モデルに分類誤差があることが容易にわかり、攻撃が有効であることがわかります。 . 妨害値は増加し続け、攻撃成功率が高いほど攻撃効果が向上します。

cnt = 0
plt.figure(figsize=(8, 10))
for i in range(len(epsilons)):
    for j in range(len(examples[i])):
        cnt += 1
        plt.subplot(len(epsilons), len(examples[0]), cnt)
        plt.xticks([], [])
        plt.yticks([], [])
        if j == 0:
            plt.ylabel("Eps: {}".format(epsilons[i]), fontsize=14)
        orig, adv, ex = examples[i][j]
        plt.title("{} -> {}".format(orig, adv),color=("green" if orig==adv else "red"))
        plt.imshow(ex, cmap="gray")
plt.tight_layout()
plt.show()

5. 運用結果


        記事内に不適切や不正確な点がございましたら、ご理解の上ご指摘いただければ幸いです。一部の文章、画像等はインターネット上から取得したものであるため、出典が確認できませんので、紛争等がございましたらブロガーに連絡の上、削除していただきますようお願いいたします。間違い、質問、権利侵害がある場合は、コメントを残して著者に連絡するか、VX 公開アカウントRain21321をフォローして著者に連絡してください。

おすすめ

転載: blog.csdn.net/qq_51399582/article/details/134699501