このページは Cloud Translation API によって翻訳されました。
Switch to English

FGSMを使用した敵対的な例

TensorFlow.orgで見る Google Colabで実行 GitHubでソースを表示する ノートブックをダウンロード

このチュートリアルでは、Fast Gradient Signed Method(FGSM)攻撃を使用して敵対的な例を作成します。これについては、Goodfellow らによる 敵対例の説明と利用説明しています。これは、ニューラルネットワークをだますための最初で最も一般的な攻撃の1つでした。

敵対的な例とは何ですか?

敵対的な例は、ニューラルネットワークを混乱させる目的で作成された特定の入力であり、特定の入力の誤分類を引き起こします。これらの悪名高い入力は人間の目では区別できませんが、ネットワークが画像の内容を識別できなくなります。このような攻撃にはいくつかの種類がありますが、ここでは、高速勾配符号法攻撃に焦点を当てています。これは、誤分類を確実にすることを目的とするホワイトボックス攻撃です。ホワイトボックス攻撃は、攻撃者が攻撃されているモデルに完全にアクセスできる場所です。以下に示す敵対的なイメージの最も有名な例の1つは、前述の論文からの引用です。

敵対的な例

ここでは、パンダの画像から始めて、攻撃者は元の画像に小さな摂動(歪み)を追加します。これにより、モデルはこの画像をテナガザルとして、高い信頼度でラベル付けします。これらの摂動を追加するプロセスを以下で説明します。

高速勾配符号法

高速勾配符号法は、ニューラルネットワークの勾配を使用して敵対的な例を作成することによって機能します。入力画像の場合、このメソッドは、入力画像に対する損失の勾配を使用して、損失を最大化する新しい画像を作成します。この新しい画像は敵対的な画像と呼ばれます。これは、次の式を使用して要約できます。

$$ adv \ _x = x + \ epsilon * \ text {sign}(\ nabla_xJ(\ theta、x、y))$$

どこ

  • adv_x:敵対的な画像。
  • x:元の入力画像。
  • y:元の入力ラベル。
  • $ \ epsilon $:摂動を確実に小さくするための乗数。
  • $ \ theta $:モデルパラメータ。
  • $ J $:損失。

ここで興味深いプロパティは、グラデーションが入力画像に対して取得されるという事実です。これは、損失を最大化するイメージを作成することが目的であるためです。これを達成する方法は、画像の各ピクセルが損失値に寄与する量を見つけ、それに応じて摂動を追加することです。チェーンルールを使用して必要な勾配を見つけることにより、各入力ピクセルがどのように損失に寄与するかを簡単に見つけることができるため、これはかなり高速に機能します。したがって、勾配は画像に対して取得されます。さらに、モデルはもはやトレーニングされていないため(したがって、勾配はトレーニング可能な変数、つまりモデルパラメーターに関して取得されません)、モデルパラメーターは一定のままです。唯一の目標は、すでに訓練されたモデルをだますことです。

では、事前トレーニング済みのモデルをだましてみましょう。このチュートリアルでは、モデルはImageNetで事前トレーニングされたMobileNetV2モデルです

 import tensorflow as tf
import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.rcParams['figure.figsize'] = (8, 8)
mpl.rcParams['axes.grid'] = False
 

事前トレーニング済みのMobileNetV2モデルとImageNetクラス名をロードしてみましょう。

 pretrained_model = tf.keras.applications.MobileNetV2(include_top=True,
                                                     weights='imagenet')
pretrained_model.trainable = False

# ImageNet labels
decode_predictions = tf.keras.applications.mobilenet_v2.decode_predictions
 
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5
14540800/14536120 [==============================] - 0s 0us/step

 # Helper function to preprocess the image so that it can be inputted in MobileNetV2
def preprocess(image):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, (224, 224))
  image = tf.keras.applications.mobilenet_v2.preprocess_input(image)
  image = image[None, ...]
  return image

# Helper function to extract labels from probability vector
def get_imagenet_label(probs):
  return decode_predictions(probs, top=1)[0][0]
 

元の画像

ウィキメディア・コモンのミルコCC-BY-SA 3.0によるラブラドールレトリバーのサンプル画像を使用して、そこから敵対的な例を作成してみましょう。最初のステップは、それをMobileNetV2モデルへの入力としてフィードできるように前処理することです。

 image_path = tf.keras.utils.get_file('YellowLabradorLooking_new.jpg', 'https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg')
image_raw = tf.io.read_file(image_path)
image = tf.image.decode_image(image_raw)

image = preprocess(image)
image_probs = pretrained_model.predict(image)
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg
90112/83281 [================================] - 0s 0us/step

画像を見てみましょう。

 plt.figure()
plt.imshow(image[0]*0.5+0.5) # To change [-1, 1] to [0,1]
_, image_class, class_confidence = get_imagenet_label(image_probs)
plt.title('{} : {:.2f}% Confidence'.format(image_class, class_confidence*100))
plt.show()
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/imagenet_class_index.json
40960/35363 [==================================] - 0s 0us/step

png

敵対的なイメージを作成する

高速勾配符号法の実装

最初のステップは、元の画像を歪めて敵対的な画像を生成するために使用される摂動を作成することです。前述のように、このタスクでは、グラデーションは画像に対して取得されます。

 loss_object = tf.keras.losses.CategoricalCrossentropy()

def create_adversarial_pattern(input_image, input_label):
  with tf.GradientTape() as tape:
    tape.watch(input_image)
    prediction = pretrained_model(input_image)
    loss = loss_object(input_label, prediction)

  # Get the gradients of the loss w.r.t to the input image.
  gradient = tape.gradient(loss, input_image)
  # Get the sign of the gradients to create the perturbation
  signed_grad = tf.sign(gradient)
  return signed_grad
 

結果として生じる摂動も視覚化できます。

 # Get the input label of the image.
labrador_retriever_index = 208
label = tf.one_hot(labrador_retriever_index, image_probs.shape[-1])
label = tf.reshape(label, (1, image_probs.shape[-1]))

perturbations = create_adversarial_pattern(image, label)
plt.imshow(perturbations[0]*0.5+0.5); # To change [-1, 1] to [0,1]
 

png

イプシロンのさまざまな値でこれを試して、結果の画像を観察してみましょう。イプシロンの値が増えると、ネットワークをだますのが簡単になることに気づくでしょう。ただし、これはトレードオフとして発生し、摂動がより識別可能になります。

 def display_images(image, description):
  _, label, confidence = get_imagenet_label(pretrained_model.predict(image))
  plt.figure()
  plt.imshow(image[0]*0.5+0.5)
  plt.title('{} \n {} : {:.2f}% Confidence'.format(description,
                                                   label, confidence*100))
  plt.show()
 
 epsilons = [0, 0.01, 0.1, 0.15]
descriptions = [('Epsilon = {:0.3f}'.format(eps) if eps else 'Input')
                for eps in epsilons]

for i, eps in enumerate(epsilons):
  adv_x = image + eps*perturbations
  adv_x = tf.clip_by_value(adv_x, -1, 1)
  display_images(adv_x, descriptions[i])
 

png

png

png

png

次のステップ

敵対的攻撃について理解したところで、さまざまなデータセットとアーキテクチャでこれを試してください。独自のモデルを作成してトレーニングし、同じ方法を使用してそれをだますこともできます。イプシロンを変更すると、予測の信頼度がどのように変化するかを試すこともできます。

このチュートリアルで示した攻撃は強力ではありますが、敵対的な攻撃の研究の始まりにすぎず、それ以来、より強力な攻撃を作成する複数の論文があります。敵対的な攻撃に加えて、研究はまた、堅牢な機械学習モデルの作成を目的とする防御の作成につながっています。敵対的な攻撃と防御の包括的なリストについては、この調査ペーパーを確認できます。

敵対的な攻撃と防御のより多くの実装については、敵対的なサンプルライブラリCleverHansを参照することをお勧めします。