Обман нейронных сетей: создайте свои собственные состязательные примеры

искусственный интеллект GitHub Нейронные сети модульный тест
Обман нейронных сетей: создайте свои собственные состязательные примеры
Эта статья была первоначально создана "AI Frontline", оригинальная ссылка:Обман нейронных сетей: создайте свои собственные состязательные примеры
Дэниел Генг и Риши Вирапани
Переводчик|Сун Хао
Редактор | Эмили

Руководство по передовой ИИ:Убийство через нейросеть. Звучит безумно? Может быть, когда-нибудь что-то подобное произойдет так, как вы не ожидали. Конечно, нейронные сети могут обучать дроны или управлять другим оружием массового уничтожения, и даже если безобидная (в ее нынешнем виде) сеть обучена вождению автомобиля, она потенциально может пойти против намерений своего владельца. Это связано с тем, что нейронные сети очень восприимчивы к «состязательным примерам».


«Состязательный пример» — это входные данные нейронной сети, из-за которых сеть выдает неверный результат. Вот пример, чтобы лучше проиллюстрировать эту ситуацию. Мы можем начать с изображения панды слева, которую некоторые сети считают «пандой» с достоверностью 57,7%. Категория панды также вызывает наибольшее доверие из всех категорий, поэтому сеть делает вывод, что объект на изображении — панда. Однако, добавив небольшое количество тщательно сконструированного шума, мы можем получить изображение, которое для человека выглядит точно так же, как и раньше, но которое сеть считает на 99,3% «гиббоном». Это сумасшедшая вещь!

Понимание и контроль враждебных примеров от Goodfellow

Итак, как убийство работает с враждебным примером?Представьте себе замену знака «стоп» на враждебный пример, сигнал, который человек может мгновенно распознать, но нейронная сеть, вероятно, даже не заметит. А теперь представьте, что на оживленном перекрестке вы размещаете запрещающий знак «Стоп». Когда беспилотный автомобиль приближается к перекрестку, нейронная сеть в автомобиле не сможет увидеть знак «стоп» и продолжит движение по встречному потоку, ставя его пассажиров на грань смерти (теоретически).

Это может быть просто загадочным, слегка сенсационным примером, но он показывает, как люди могут использовать враждебные примеры, чтобы причинить вред другим, и здесь есть еще много примеров. Например, функция разблокировки iPhone X «Распознавание лиц» использует нейронные сети для распознавания лиц и, следовательно, также уязвима для атак злоумышленников. Можно создавать враждебные изображения, чтобы обойти функции безопасности распознавания лиц. Другие биометрические системы безопасности также будут подвержены риску, поскольку незаконный или ошибочный контент потенциально может обходить фильтры контента на основе нейронных сетей, используя враждебные примеры. Наличие этих враждебных примеров означает, что системы, включающие модели глубокого обучения, на самом деле имеют высокий риск для безопасности.


Вы можете понять состязательные примеры, думая о них как о визуальных иллюзиях нейронной сети. Зрительные иллюзии могут обмануть человеческий мозг точно так же, как враждебные примеры могут обмануть нейронные сети.

Состязательные примеры, упомянутые выше о пандах, являются целевым примером. К изображению было добавлено небольшое количество тщательно сконструированного шума, из-за чего нейронная сеть неправильно классифицировала изображение, хотя для человека оно выглядело так же, как и раньше. Есть также нецелевые примеры попыток найти любые входные данные, которые могут обмануть нейронную сеть. Этот ввод может выглядеть как белый шум для человека, но, поскольку мы не ограничены поиском входных данных, похожих на человека, проблема намного проще.

Немного смущает тот факт, что мы можем найти враждебные примеры для любой нейронной сети, даже для самых современных моделей, которые, как говорят, обладают «сверхчеловеческими» способностями. На самом деле создать враждебные примеры очень просто, и в этой статье мы покажем вам, как это сделать. Весь необходимый код и связанные с ним зависимости можно найти в этом репозитории GitHub.

Имитация вируса, прекрасно демонстрирующая эффективность враждебных образцов

Код для этой части состязательных примеров на MNIST можно найти в следующем репозитории GitHub (загрузка кода не требуется, чтобы понять эту статью): GitHub Repo

Мы попытаемся обучить нейронную сеть с прямой связью на наборе данных MNIST. MNIST — это набор изображений рукописных цифр размером 28x28 пикселей. Их стили следующие:

6 изображений MNIST рядом

Прежде чем мы начнем, мы должны сначала импортировать нужные нам библиотеки.

import network.network as network
import network.mnist_loader as mnist_loader
import pickle
import matplotlib.pyplot as plt
import numpy as np

Имеется 50 000 обучающих изображений и 10 000 тестовых изображений. Мы начинаем с загрузки предварительно обученной нейронной сети (которая дерзко взята из этой замечательной статьи о нейронных сетях):

with open('trained_network.pkl', 'rb') as f:  
    net = pickle.load(f)  

training_data, validation_data, test_data = mnist_loader.load_data_wrapper()

Чтобы объяснить тем, кто не знаком с pickle, это способ сериализации данных в Python (например, запись на диск), по существу сохраняющий классы и объекты. Используйте pickle.load(), чтобы открыть сохраненную версию сетевого слоя.

Об этой предварительно обученной нейронной сети. Он имеет 784 входных нейрона (каждый соответствует 28*28=784 пикселям), слой с 30 скрытыми нейронами и 10 выходными нейронами (по одному на каждую цифру). Все его активные состояния имеют s-образную форму; его выход представляет собой однократный вектор, представляющий прогнозы сети, которая обучается путем минимизации потерь среднеквадратичной ошибки.

Чтобы доказать, что нейронная сеть обучена, мы можем написать простую тестовую функцию:

def predict(n):
    # Get the data from the test set
    x = test_data[n][0]

    # Get output of network and prediction
    activations = net.feedforward(x)
    prediction = np.argmax(activations)

    # Print the prediction of the network
    print('Network output: ')
    print(activations)

    print('Network prediction: ')
    print(prediction)

    print('Actual image: ')

    # Draw the image
    plt.imshow(x.reshape((28,28)), cmap='Greys')

Метод выбирает образец из набора тестов, отображает его и запускает в нейронной сети с помощью метода net.feedforward(x). Вот результат для некоторых картинок:







Слева изображение из MNIST. Справа находятся 3 выхода нейронной сети, называемые активными состояниями. Чем больше выходной сигнал, тем больше нейронная сеть считает, что изображение соответствует этому числу.

Теперь у нас есть обученная сеть, но как мы ее обманем?Мы начнем с простого нецелевого подхода, и как только мы получим намеченную цель, мы можем использовать крутой трюк, чтобы изменить этот метод, изменить его на целевой метод.

Идея нецелевой атаки состоит в том, чтобы генерировать какие-то изображения, чтобы нейронная сеть выдавала определенный вывод. Например, наша целевая метка/вывод:

То есть мы хотим получить изображение, выходом которого через нейронную сеть является вектор выше. Другими словами, найдите изображение, которое нейронная сеть считает цифрой 5 (напоминаю, у нас нулевой индекс). Оказывается, мы можем относиться к этому как к задаче оптимизации, точно так же, как мы обучаем сеть. Мы называем изображение, которое хотим сгенерировать (784-мерный вектор, мы сглаживаем изображение размером 28*28 пикселей для простоты вычислений). Определим функцию стоимости:

является квадратом нормальной формы L2. это целевая метка, которую мы получили сверху. Выход нашего изображения, проходящего через нейронную сеть, таков. Мы видим, что если вывод нашего изображения через нейронную сеть очень близок к нашей целевой метке, то соответствующая стоимость будет низкой. Если выход сети далек от нашей цели, стоимость будет высокой. Следовательно, нахождение вектора, минимизирующего значение стоимости C, изображение, предсказанное нейронной сетью, является нашей целевой меткой. Теперь наша задача — найти этот вектор. Обратите внимание, что эта проблема очень похожа на то, как мы обучаем нейронную сеть, где мы определяем функцию стоимости, а затем выбираем веса и смещения (также известные как параметры), чтобы минимизировать функцию стоимости. В случае генерации состязательных примеров, вместо использования весов и смещений для минимизации стоимости, мы сохраняем веса и смещения постоянными (по сути, сохраняя постоянной всю сеть) и выбираем вход, который минимизирует стоимость.

Для этого воспользуемся тем же подходом, который мы использовали для обучения нейронной сети. То есть мы будем использовать градиентный спуск! Мы можем использовать обратное распространение, чтобы найти производную функции входной стоимости, , , а затем использовать обновления градиентного спуска, чтобы найти лучший вариант, который минимизирует стоимость.

Обратное распространение часто используется для вычисления градиентов весов и смещений стоимости, но в целом обратное распространение — это просто алгоритм, который эффективно вычисляет градиенты на вычислительном графе (это и есть нейронная сеть). Следовательно, его также можно использовать для расчета градиента функции стоимости входа нейронной сети.

Теперь давайте посмотрим на код для генерации состязательных примеров:

def adversarial(net, n, steps, eta):
"""
net : network object
    neural network instance to use
n : integer
    our goal label (just an int, the function transforms it into a one-hot vector)
steps : integer
    number of steps for gradient descent
eta : integer
    step size for gradient descent
"""
# Set the goal output
goal = np.zeros((10, 1))
goal[n] = 1

# Create a random image to initialize gradient descent with
x = np.random.normal(.5, .3, (784, 1))

# Gradient descent on the input
for i in range(steps):
    # Calculate the derivative
    d = input_derivative(net,x,goal)

    # The GD update on x
    x -= eta * d

return x


Сначала мы создаем, называемую цели в коде. Далее мы инициализируем как случайный 784-мерный вектор. С этим вектором мы можем начать использовать градиентный спуск, который на самом деле состоит всего из двух строк кода. Первая строка d = input_derivative(net,x,goal) вычисляется с использованием обратного распространения (полный код в примечании написан для тех, кому он нужен, но мы не будем его здесь описывать, потому что это просто набор математических вычислений). Если вам нужно более подробное описание обратного распространения (что делает input_derivative), вы можете посмотреть его здесь (кстати, мы взяли оттуда реализацию нейронной сети). Вторая и последняя строка цикла градиентного спуска, x- = eta * d, является обновлением предыдущего GD. Мы движемся по направлению градиента и эта-направлению размера шага.

Вот нецелевые состязательные примеры для каждого класса вместе с прогнозами нейронной сети:

Нецелевое "О"



Нецелевой "3"



Нецелевой "5"



Слева — нецелевой состязательный тест (изображение 28 X 28 пикселей). Когда изображение задано, текущее состояние сети рисуется справа.

Невероятно, но нейронная сеть имеет очень высокую степень уверенности в том, что некоторые изображения являются определенными числами. «3» и «5» — хорошие примеры. Для большинства других чисел нейронная сеть показала низкую активность, что указывало на то, что нейронная сеть немного запуталась. Эффект выглядит отлично!

В этот момент вас может беспокоить несколько вещей. Если мы хотим создать состязательный пример, соответствующий «5», то мы хотим найти тот, который при вводе в нейронную сеть будет выводить как можно ближе к одномерному вектору, представляющему «5». Однако почему градиентный спуск не нашел изображение «5»?В конце концов, нейросеть почти наверняка подумает, что изображение «5» на самом деле «5» (потому что это действительно «5»). Одна из возможных теорий, почему это происходит:

Расстояние между всеми доступными изображениями размером 28x28 пикселей огромно. Существует другое черно-белое изображение размером 28x28 пикселей. Для сравнения, наша общая оценка количества атомов в наблюдаемой Вселенной равна . Если бы каждый атом во вселенной содержал другую вселенную, тогда у нас был бы атом. Если каждый атом содержит другой атом, который также содержит вселенную и, таким образом, содержит друг друга примерно 23 раза, то мы почти можем получить атом. Итак, в целом видно, что количество анализируемых изображений на удивление велико.

Из всех этих фотографий лишь малая часть может быть распознана человеческим глазом как числа. Столкнувшись с множеством изображений, нейронная сеть может распознать большинство изображений как числа (отчасти потому, что наша нейронная сеть никогда не обучалась на изображениях, не похожих на числа, поэтому, если это изображение, не похожее на число ) изображения чисел результаты вывода нейросети будут практически случайными). Поэтому, когда мы начинаем искать изображение, которое выглядит как число для нейронной сети, мы с большей вероятностью найдем изображение, которое выглядит как шум или статика, а не найдем изображение, которое выглядит как число для людей просто по вероятности.

целенаправленная атака

Эти враждебные примеры круты, но для человека они выглядят как шум. Разве не было бы круче, если бы у нас был состязательный пример, похожий на что-то вроде изображения «2», которое нейронная сеть приняла бы за «5»? Оказывается можно! Мы внесли лишь очень незначительные изменения в исходный код. Мы добавляем член к функции стоимости, которую минимизируем. Новая функция затрат выглядит следующим образом:

Это то, как мы ожидаем, что состязательный пример будет выглядеть (784-мерный вектор, того же размера, что и наш ввод). Итак, что нам нужно сделать сейчас, это свести к минимуму и то, и другое. Элемент слева мы уже видели. После того, как это будет задано, минимизация этого сделает вывод нейронной сети. Минимизация второго члена попытается максимально приблизить наши враждебные образы (поскольку два вектора будут тем меньше, чем ближе они к норме), а это именно то, что нам нужно! Кроме того, предыдущий λ является гиперпараметром, который определяет, что важнее. Как и большинство гиперпараметров, после проб и ошибок мы обнаружили, что 0,05 — очень хорошее значение для λ.

Если вы знаете регрессию хребта, вы, вероятно, знакомы с приведенной выше функцией стоимости. На самом деле, мы можем интерпретировать приведенную выше функцию стоимости как размещение предшествующего примера в нашей модели для наших враждебных примеров.

Если вы не знаете о регуляризации, вы можете найти дополнительную информацию в поисковой системе.

Код, который реализует функцию, минимизирующую новую стоимость, почти идентичен исходному коду (мы называем эту функцию скрытой_адверсариальной(), потому что мы умеем скрытно проводить целевые атаки. Именование всегда было самой сложной частью программирования).

def sneaky_adversarial(net, n, x_target, steps, eta, lam=.05):
    """
    net : network object
        neural network instance to use
    n : integer
        our goal label (just an int, the function transforms it into a one-hot vector)
    x_target : numpy vector
        our goal image for the adversarial example
    steps : integer
        number of steps for gradient descent
    eta : integer
        step size for gradient descent
    lam : float
        lambda, our regularization parameter. Default is .05
    """

    # Set the goal output
    goal = np.zeros((10, 1))
    goal[n] = 1

    # Create a random image to initialize gradient descent with
    x = np.random.normal(.5, .3, (784, 1))

    # Gradient descent on the input
    for i in range(steps):
        # Calculate the derivative
        d = input_derivative(net,x,goal)

        # The GD update on x, with an added penalty 
        # to the cost function
        # ONLY CHANGE IS RIGHT HERE!!!
        x -= eta * (d + lam * (x - x_target))

    return x

Единственное, что мы изменили, это обновление градиентного спуска:

x -= eta
 (d + lam
 (x - x_target)) 。

Термин «эта» — это новый термин для нашей функции стоимости. Давайте посмотрим на результаты, полученные новой итерацией метода:

Таргетинг "7" [x_target=3]



Таргетинг "9" [x_target=5]



Таргетинг "2" [x_target=8]



Слева — пример целевого состязания (изображение 28 X 28 пикселей). Когда изображение задано, текущее состояние сети рисуется справа.

Важно отметить, что, как и в случае с нецелевыми атаками, здесь есть два варианта поведения. Либо нейронная сеть полностью обманута, и активность для нужного нам числа очень высока (например, изображение «целевой 5»), либо сеть сбита с толку, и вся активность низкая (например, изображение «целевое 5»). Изображение «Секс 7» ). Интересно, что в предыдущей категории теперь больше изображений, которые полностью обманывают нейронную сеть, а не просто сбивают ее с толку. Кажется, что во время градиентного спуска состязательные примеры, нормализованные к «числовым классам», имеют тенденцию сходиться лучше.

Предотвратить атаку противника

Невероятно! Мы только что создали несколько изображений, чтобы обмануть нейронную сеть. Наш следующий вопрос заключается в том, можем ли мы предотвратить атаки такого типа. Если вы внимательно посмотрите на исходное изображение и враждебные примеры, вы увидите серый фон в враждебных примерах.

целевое изображение



Исходное изображение



Состязательный пример с шумом на заднем плане.

Сначала мы можем попробовать более простой подход, используя двоичное пороговое значение, чтобы полностью отбелить цвет фона:

def binary_thresholding(n, m):
"""
n: int 0-9, the target number to match
m: index of example image to use (from the test set)
"""

# Generate adversarial example
x = sneaky_generate(n, m)

# Binarize image
x = (x > .5).astype(float)

print("With binary thresholding: ")

plt.imshow(x.reshape(28,28), cmap="Greys")
plt.show()

# Get binarized output and prediction
binary_activations = net.feedforward(x)
binary_prediction = np.argmax(net.feedforward(x))

print("Prediction with binary thresholding: ")
print(binary_prediction)

print("Network output: ")
print(binary_activations)

Вот результат:

Против картины:



бинаризованное изображение



Влияние бинарного порога на состязательные изображения MNIST. Слева изображение, справа вывод нейросети.

Оказывается, бинарный порог работает! Но этот метод защиты от атак не очень хорош. Не все изображения имеют белый фон. Например, в начале этой статьи посмотрите на изображение панды. Бинарная пороговая обработка изображения может удалить шум, но она в значительной степени мешает изображению панды. Это может даже дойти до того, что интернет (и люди) даже не смогут распознать в нем панду.

Бинарная пороговая обработка в pandas создает изображение, полное пятен

Другой более общий подход, который мы можем попробовать, состоит в том, чтобы обучить новую нейронную сеть как на правильно помеченных состязательных примерах, так и на исходном наборе обучающих тестов. В блокноте ipython есть код реализации (обратите внимание, что выполнение кода занимает около 15 минут). После этого мы можем достичь точности 94% на тестовом наборе всех враждебных изображений, что очень хорошо. Однако этот подход имеет свои ограничения. В реальной жизни вы вряд ли узнаете, как ваши злоумышленники генерируют враждебные примеры.

Есть много других способов защитить нас от атак со стороны противника, которые мы не рассмотрели в этой вводной статье, но проблема все еще остается открытой темой для исследований, и если вам интересно, на эту тему есть множество статей.

атака черного ящика

Интересное, но важное наблюдение о состязательных примерах заключается в том, что они обычно не имеют конкретной модели или архитектуры. Состязательные примеры, сгенерированные для одной архитектуры нейронной сети, могут быть хорошо перенесены на другую. Другими словами, если вы хотите обмануть модель, вы можете построить свою собственную модель и состязательные примеры на ее основе. Затем эти же враждебные примеры могут обмануть и другие модели.

Это имеет важные последствия, поскольку означает, что мы можем создать состязательный пример для полной модели черного ящика без нашего предварительного знания ее внутренних механизмов. Фактически, команда из Беркли успешно использовала этот подход для атаки на коммерческую систему классификации ИИ.

в заключении

По мере того, как мы движемся в будущее, где наша повседневная жизнь включает в себя все больше и больше нейронных сетей и алгоритмов глубокого обучения, мы должны быть очень осторожными и помнить, что эти модели легко обмануть. Хотя нейронные сети в некоторой степени вдохновлены биологией и способны приблизиться (или даже превзойти) людей в самых разных задачах, состязательные примеры говорят нам, что они действуют так же, как и реальные организмы. Как мы видели, нейронные сети могут легко и катастрофически выйти из строя, что совершенно чуждо нам, людям.

Мы не до конца понимаем нейронные сети, поэтому было бы неразумно описывать нейронные сети с точки зрения нашей человеческой интуиции. Например, вы часто слышите, как люди говорят: «Нейронная сеть думает, что это изображение кошки, потому что она оранжевая». По сути, это просто ряд матриц, умноженных на некоторые аддитивные нелинейные данные. Как показывают враждебные примеры, выход этих моделей очень хрупок. Мы должны быть осторожны, чтобы не возлагать надежды на нейронные сети, чтобы заставить машины достигать человеческих качеств, несмотря на их человеческие способности. То есть мы не можем антропоморфизировать модели машинного обучения.



Нейронная сеть, обученная обнаруживать гантели, «считает», что «гантели» иногда соединяются с высвобожденной рукой. Это явно не то, что мы ожидали. Из исследований Google.

В общем, наличие враждебных примеров должно держать нас в смирении. Они показывают нам, что, несмотря на наш огромный прогресс, мы еще многого не знаем.

Оригинальная английская ссылка:

Beautiful.Berkeley.Amount/blog/2018/0…

Для большего содержания сухих товаров вы можете обратить внимание на AI Frontline, ID:ai-front, фоновый ответ "AI", "TF", "Большие данные«Вы можете получить серию мини-книг в формате PDF и карт навыков «AI Frontline».