¡El Día de la Comunidad de ML es el 9 de noviembre! Únase a nosotros para recibir actualizaciones de TensorFlow, JAX, y más Más información

Ejemplo de enfrentamiento con mutilación genital femenina

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Este tutorial crea un ejemplo contradictorio utilizando el ataque Fast Gradient Signed Method (FGSM) como se describe en Explicación y aprovechamiento de ejemplos adversarios por Goodfellow et al . Este fue uno de los primeros y más populares ataques para engañar a una red neuronal.

¿Qué es un ejemplo contradictorio?

Los ejemplos contradictorios son entradas especializadas creadas con el propósito de confundir una red neuronal, lo que da como resultado la clasificación errónea de una entrada determinada. Estas entradas notorias son indistinguibles para el ojo humano, pero hacen que la red no identifique el contenido de la imagen. Hay varios tipos de ataques de este tipo, sin embargo, aquí la atención se centra en el ataque del método de signo de gradiente rápido, que es un ataque de caja blanca cuyo objetivo es garantizar una clasificación errónea. Un ataque de caja blanca es donde el atacante tiene acceso completo al modelo que está siendo atacado. Uno de los ejemplos más famosos de una imagen contradictoria que se muestra a continuación está tomado del documento mencionado anteriormente.

Ejemplo Adversario

Aquí, comenzando con la imagen de un panda, el atacante agrega pequeñas perturbaciones (distorsiones) a la imagen original, lo que da como resultado que el modelo etiquete esta imagen como un gibón, con alta confianza. El proceso de agregar estas perturbaciones se explica a continuación.

Método de signo de gradiente rápido

El método de signo de gradiente rápido funciona utilizando los gradientes de la red neuronal para crear un ejemplo de confrontación. Para una imagen de entrada, el método usa los gradientes de la pérdida con respecto a la imagen de entrada para crear una nueva imagen que maximiza la pérdida. Esta nueva imagen se llama imagen adversaria. Esto se puede resumir usando la siguiente expresión:

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

dónde

  • adv_x: Imagen adversa.
  • x: imagen de entrada original.
  • y: Etiqueta de entrada original.
  • $ \ epsilon $: multiplicador para asegurar que las perturbaciones sean pequeñas.
  • $ \ theta $: Parámetros del modelo.
  • $ J $: Pérdida.

Una propiedad intrigante aquí es el hecho de que los gradientes se toman con respecto a la imagen de entrada. Esto se hace porque el objetivo es crear una imagen que maximice la pérdida. Un método para lograr esto es encontrar cuánto contribuye cada píxel de la imagen al valor de pérdida y agregar una perturbación en consecuencia. Esto funciona bastante rápido porque es fácil encontrar cómo cada píxel de entrada contribuye a la pérdida mediante el uso de la regla de la cadena y la búsqueda de los gradientes necesarios. Por tanto, los degradados se toman con respecto a la imagen. Además, dado que el modelo ya no se está entrenando (por lo tanto, el gradiente no se toma con respecto a las variables entrenables, es decir, los parámetros del modelo), por lo que los parámetros del modelo permanecen constantes. El único objetivo es engañar a un modelo ya entrenado.

Así que intentemos engañar a un modelo previamente entrenado. En este tutorial, el modelo es MobileNetV2 modelo, pretrained en IMAGEnet .

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

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

Carguemos el modelo MobileNetV2 previamente entrenado y los nombres de clase de 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 [==============================] - 1s 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]

Imagen original

Usemos una imagen de muestra de un Labrador Retriever de Mirko CC-BY-SA 3.0 de Wikimedia Common y creemos ejemplos de confrontación a partir de ella. El primer paso es preprocesarlo para que se pueda alimentar como entrada al modelo 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

Echemos un vistazo a la imagen.

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

Crea la imagen de adversario

Implementación del método de signo de gradiente rápido

El primer paso es crear perturbaciones que se utilizarán para distorsionar la imagen original y generar una imagen contradictoria. Como se mencionó, para esta tarea, los degradados se toman con respecto a la imagen.

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

Las perturbaciones resultantes también se pueden visualizar.

# 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]
<matplotlib.image.AxesImage at 0x7f4171d66690>

png

Probemos esto para diferentes valores de épsilon y observemos la imagen resultante. Notará que a medida que aumenta el valor de épsilon, se vuelve más fácil engañar a la red. Sin embargo, esto viene como una compensación que da como resultado que las perturbaciones se vuelvan más identificables.

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

Próximos pasos

Ahora que conoce los ataques adversarios, pruebe esto en diferentes conjuntos de datos y diferentes arquitecturas. También puede crear y entrenar su propio modelo y luego intentar engañarlo usando el mismo método. También puede probar y ver cómo varía la confianza en las predicciones a medida que cambia épsilon.

Aunque poderoso, el ataque que se muestra en este tutorial fue solo el comienzo de la investigación sobre los ataques adversarios, y desde entonces ha habido varios artículos que han creado ataques más poderosos. Además de los ataques adversarios, la investigación también ha llevado a la creación de defensas, cuyo objetivo es crear modelos robustos de aprendizaje automático. Puede revisar este documento de la encuesta para obtener una lista completa de los ataques y las defensas adversas.

Para muchas más implementaciones de ataques y defensas adversarios, es posible que desee ver la biblioteca de ejemplos adversarios CleverHans .