Breaking Linear Classifiers on ImageNet
Андрей Карпаты разбирает явление «обманных» (fooling) изображений, на которых современная сеть с уверенностью ставит произвольный класс, хотя для человека картинка не изменилась. Он подчёркивает, что проблема не уникальна для ConvNet и Deep Learning: те же атаки работают и на простых линейных классификаторах (Softmax, линейный SVM), что было показано в работе Goodfellow et al. «Explaining and Harnessing Adversarial Examples». В эксперименте автор обучает линейный классификатор на ImageNet (1.2 млн изображений, 64×64, фреймворк Caffe), получает около 3% top-1 и 10% top-5 точности и генерирует обманные образцы, просто прибавляя к картинке доли весов нужного класса — без backpropagation. На игрушечном примере с бинарной логистической регрессией он показывает, что в 10-мерном пространстве сдвиг на 0.5 по каждому измерению повышает вероятность класса с 5% до 88%, а в изображениях с десятками тысяч измерений эти микросдвиги складываются ещё разрушительнее. Сильная регуляризация даёт более плавные веса и устойчивость к атакам, но снижает обобщающую способность. Вывод: уязвимость порождена линейной природой моделей, и для её устранения нужны новые целевые функции, архитектуры или методы оптимизации.
You’ve probably heard that Convolutional Networks work very well in practice and across a wide range of visual recognition problems. You may have also read articles and papers that claim to reach a near “human-level performance”. There are all kinds of caveats to that (e.g. see my G+ post on Human Accuracy is not a point, it lives on a tradeoff curve), but that is not the point of this post. I do think that these systems now work extremely well across many visual recognition tasks, especially ones that can be posed as simple classification.
Вы наверняка слышали, что свёрточные сети (Convolutional Networks) очень хорошо работают на практике и в широком спектре задач визуального распознавания. Возможно, вы также читали статьи и публикации, в которых утверждается, что они приближаются к «человеческому уровню производительности». К этому есть множество оговорок (см., например, мой пост в G+ Human Accuracy is not a point, it lives on a tradeoff curve), но это не предмет данного поста. Я действительно считаю, что эти системы сейчас крайне хорошо справляются со многими задачами визуального распознавания, особенно с теми, которые сводятся к простой классификации.
Yet, a second group of seemingly baffling results has emerged that brings up an apparent contradiction. I’m referring to several people who have noticed that it is possible to take an image that a state-of-the-art Convolutional Network thinks is one class (e.g. “panda”), and it is possible to change it almost imperceptibly to the human eye in such a way that the Convolutional Network suddenly classifies the image as any other class of choice (e.g. “gibbon”). We say that we break, or fool ConvNets. See the image below for an illustration:
Однако появилась и вторая группа результатов, которые на первый взгляд кажутся озадачивающими и порождают видимое противоречие. Я говорю о наблюдениях нескольких исследователей: можно взять изображение, которое state-of-the-art свёрточная сеть относит к одному классу (например, «панда»), и почти незаметным для человеческого глаза образом изменить его так, что сеть внезапно классифицирует картинку как любой другой выбранный класс (например, «гиббон»). Мы говорим, что мы ломаем или обманываем ConvNet. См. иллюстрацию ниже:
This topic has recently gained attention starting with Intriguing properties of neural networks by Szegedy et al. last year. They had a very similar set of images:
Эта тема в последнее время привлекла внимание начиная с работы Intriguing properties of neural networks Szegedy et al. в прошлом году. У них был очень похожий набор изображений:
And a set of very closely related results was later followed by Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images by Nguyen et al. Instead of starting with correctly-classified images and fooling the ConvNet, they had many more examples of performing the same process starting from noise (and hence making the ConvNet confidently classify an incomprehensible noise pattern as some class), or evolving new funny-looking images that the ConvNet is slightly too certain about:
Близкий по духу набор результатов затем последовал в работе Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images Nguyen et al. Вместо того чтобы начинать с правильно классифицированных изображений и обманывать ConvNet, они привели гораздо больше примеров того же процесса, стартуя из шума (и заставляя сеть с высокой уверенностью относить непонятный шумовой паттерн к какому-то классу) или эволюционируя новые забавные изображения, в которых сеть слишком уверена:
I should make the point quickly that these results are not completely new to Computer Vision, and that some have observed the same problems even with our older features, e.g. HOG features. See Exploring the Representation Capabilities of the HOG Descriptor for details.
Замечу сразу, что эти результаты не вполне новы для компьютерного зрения — некоторые исследователи наблюдали те же проблемы и со старыми признаками, например HOG. Подробнее см. Exploring the Representation Capabilities of the HOG Descriptor.
The conclusion seems to be that we can take any arbitrary image and classify it as whatever class we want by adding tiny, imperceptible noise patterns. Worse, it was found that a reasonable fraction of fooling images generalize across different Convolutional Networks, so this isn’t some kind of fragile property of the new image or some overfitting property of the model. There’s something more general about the type of introduced noise that seems to fool many other models. In some sense, it is much more accurate to speak about fooling subspaces rather than fooling images. The latter erroneously makes them seem like tiny points in the super-high-dimensional image space, perhaps similar to rational numbers along the real numbers, when instead they are better thought of as entire intervals. Of course, this work raises security concerns because an adversary could conceivably generate a fooling image of any class on their own computer and upload it to some service with a malicious intent, with a non-zero probability of it fooling the server-side model (e.g. circumventing racy filters).
Вывод, по-видимому, таков: можно взять произвольное изображение и классифицировать его как любой нужный класс, добавив крошечный, незаметный шумовой паттерн. Хуже того, оказалось, что значительная доля обманных изображений обобщается между разными свёрточными сетями, так что это не какая-то хрупкая особенность конкретной картинки или переобучения конкретной модели. Есть нечто более общее в характере вносимого шума, что обманывает и многие другие модели. В каком-то смысле гораздо точнее говорить о fooling subspaces, чем о fooling images. Последнее формулирование ошибочно представляет их как крошечные точки в сверхвысокомерном пространстве изображений — словно рациональные числа на вещественной прямой, — тогда как их лучше мыслить как целые интервалы. Эта работа, конечно же, поднимает вопросы безопасности: злоумышленник может сгенерировать обманное изображение нужного класса на собственном компьютере и загрузить его в некий сервис со злым умыслом, причём с ненулевой вероятностью обмануть серверную модель (например, обойти фильтры на «непристойный» контент).
What is going on?
Что происходит?
These results are interesting and worrying, but they have also led to a good amount of confusion among laymen. The most important point of this entire post is the following:
Эти результаты интересны и тревожны, но также вызвали изрядную путаницу среди неспециалистов. Самый важный тезис всего этого поста таков:
These results are not specific to images, ConvNets, and they are also not a “flaw” in Deep Learning. A lot of these results were reported with ConvNets running on images because pictures are fun to look at and ConvNets are state-of-the-art, but in fact the core flaw extends to many other domains (e.g. speech recognition systems), and most importantly, also to simple, shallow, good old-fashioned Linear Classifiers (Softmax classifier, or Linear Support Vector Machines, etc.). This was pointed out and articulated in Explaining and Harnessing Adversarial Examples by Goodfellow et al. We’ll carry out a few experiments very similar to the ones presented in this paper, and see that it is in fact this linear nature that is problematic. And because Deep Learning models use linear functions to build up the architecture, they inherit their flaw. However, Deep Learning by itself is not the cause of the issue. In fact, Deep Learning offers tangible hope for a solution, since we can use all the wiggle of composed functions to design more resistant architectures or objectives.
Эти результаты не специфичны для изображений и ConvNets, и они не являются «изъяном» Deep Learning. Большинство этих результатов получали со свёрточными сетями на изображениях, потому что на картинки приятно смотреть, а ConvNets — это state-of-the-art, но на самом деле основной изъян распространяется и на многие другие домены (например, системы распознавания речи), и — что важнее всего — также на простые, неглубокие, добрые старые линейные классификаторы (Softmax classifier, линейный Support Vector Machine и т.п.). Это было указано и сформулировано в работе Explaining and Harnessing Adversarial Examples Goodfellow et al. Мы проведём несколько экспериментов, очень похожих на представленные в этой статье, и увидим, что проблема — именно в линейной природе. И поскольку модели Deep Learning используют линейные функции в основе архитектуры, они наследуют этот изъян. Однако сам Deep Learning не является причиной проблемы. Напротив, Deep Learning даёт реальную надежду на её решение, поскольку мы можем использовать всю гибкость композиции функций, чтобы проектировать более устойчивые архитектуры и целевые функции.
How fooling methods work
Как работают методы обмана
ConvNets express a differentiable function from the pixel values to class scores. For example, a ConvNet might take a 227x227 image and transforms these ~100,000 numbers through a wiggly function (parameterized by several million parameters) to 1000 numbers that we interpret as the confidences for 1000 classes (e.g. the classes of ImageNet).
ConvNets выражают дифференцируемую функцию от значений пикселей к оценкам классов. Например, ConvNet может взять изображение 227×227 и преобразовать эти ~100 000 чисел через «извилистую» функцию (параметризованную несколькими миллионами параметров) в 1000 чисел, которые мы интерпретируем как уверенности по 1000 классам (например, классы ImageNet).
We train a ConvNet with repeated process of sampling data, calculating the parameter gradients and performing a parameter update. That is, suppose we feed the ConvNet an image of a banana and compute the 1000 scores for the classes that the ConvNet assigns to this image. We then and ask the following question for every single parameter in the model:
Мы обучаем ConvNet, повторяя процесс выборки данных, вычисления градиентов параметров и обновления параметров. То есть, допустим, мы подаём в ConvNet изображение банана и вычисляем 1000 оценок классов, которые сеть назначает этому изображению. Затем для каждого параметра модели мы задаём вопрос:
Normal ConvNet training: “What happens to the score of the correct class when I wiggle this parameter?”
Обычное обучение ConvNet: «Что произойдёт с оценкой правильного класса, если я слегка пошевелю этот параметр?»
This wiggle influence, of course, is just the gradient. For example, some parameter in some filter in some layer of the ConvNet might get the gradient of -3.0 computed during backpropagation. That means that increasing this parameter by a tiny amount, e.g. 0.0001, would have a negative influence on the banana score (due to the negative sign); In this case, we’d expect the banana score to decrease by approximately 0.0003. Normally we take this gradient and use it to perform a parameter update, which wiggles every parameter in the model a tiny amount in the correct direction, to increase the banana score. These parameter updates hence work in concert to slightly increase the score of the banana class for that one banana image (e.g. the banana score could go up from 30% to 34% or something). We then repeat this over and over on all images in the training data.
Эта чувствительность к шевелению, конечно, и есть градиент. Например, некий параметр некоего фильтра в каком-то слое ConvNet может получить градиент −3.0, вычисленный во время backpropagation. Это означает, что увеличение этого параметра на небольшую величину, скажем 0.0001, окажет отрицательное влияние на оценку «банан» (из-за знака минус); в этом случае мы ожидаем, что оценка «банан» уменьшится примерно на 0.0003. Обычно мы берём этот градиент и используем его для обновления параметров, которое сдвигает каждый параметр модели на малую величину в правильную сторону, чтобы повысить оценку «банан». Эти обновления параметров слаженно слегка повышают оценку класса «банан» для конкретной картинки с бананом (например, оценка банана может подняться с 30% до 34%). Затем мы повторяем это многократно по всем изображениям в обучающих данных.
Notice how this worked: we held the input image fixed, and we wiggled the model parameters to increase the score of whatever class we wanted (e.g. banana class). It turns out that we can easily flip this process around to create fooling images. (In practice in fact, absolutely no changes to a ConvNet code base are required.) That is, we will hold the model parameters fixed, and instead we’re computing the gradient of all pixels in the input image on any class we might desire. For example, we can ask:
Обратите внимание, как это работало: мы фиксировали входное изображение и шевелили параметры модели, чтобы повысить оценку нужного класса (например, класса «банан»). Оказывается, этот процесс легко обратить и создавать обманные изображения. (На практике для этого не требуется вообще никаких изменений в коде ConvNet.) То есть мы фиксируем параметры модели и вместо этого вычисляем градиент по всем пикселям входного изображения относительно любого желаемого класса. Например, можно спросить:
Creating fooling images: “What happens to the score of (whatever class you want) when I wiggle this pixel?”
Создание обманных изображений: «Что произойдёт с оценкой (любого нужного вам класса), если я слегка пошевелю этот пиксель?»
We compute the gradient just as before with backpropagation, and then we can perform an image update instead of a parameter update, with the end result being that we increase the score of whatever class we want. E.g. we can take the banana image and wiggle every pixel according to the gradient of that image on the cat class. This would change the image a tiny amount, but the score of cat would now increase. Somewhat unintuitively, it turns out that you don’t have to change the image too much to toggle the image from being classified correctly as a banana, to being classified as anything else (e.g. cat).
Мы вычисляем градиент тем же backpropagation, что и раньше, а затем выполняем обновление изображения вместо обновления параметров; в итоге мы повышаем оценку любого желаемого класса. Например, можно взять изображение банана и пошевелить каждый пиксель согласно градиенту этой картинки относительно класса «кошка». Это слегка изменит изображение, но оценка кошки теперь возрастёт. Несколько неинтуитивно, но оказывается, что для перевода изображения из правильной классификации «банан» в какую угодно другую (например, «кошка») нужно изменить картинку совсем немного.
In short, to create a fooling image we start from whatever image we want (an actual image, or even a noise pattern), and then use backpropagation to compute the gradient of the image pixels on any class score, and nudge it along. We may, but do not have to, repeat the process a few times. You can interpret backpropagation in this setting as using dynamic programming to compute the most damaging local perturbation to the input. Note that this process is very efficient and takes negligible time if you have access to the parameters of the ConvNet (backprop is fast), but it is possible to do this even if you do not have access to the parameters but only to the class scores at the end. In this case, it is possible to compute the data gradient numerically, or to to use other local stochastic search strategies, etc. Note that due to the latter approach, even non-differentiable classifiers (e.g. Random Forests) are not safe (but I haven’t seen anyone empirically confirm this yet).
Короче говоря, чтобы создать обманное изображение, мы начинаем с любой картинки (реального изображения или даже шумового паттерна), затем при помощи backpropagation вычисляем градиент пикселей изображения по нужной оценке класса и сдвигаем картинку вдоль него. Этот процесс можно повторить несколько раз, но не обязательно. backpropagation в данной постановке можно интерпретировать как динамическое программирование, вычисляющее максимально разрушительное локальное возмущение входа. Заметим, что этот процесс очень эффективен и занимает ничтожное время, если у вас есть доступ к параметрам ConvNet (backprop быстр), но это можно сделать, даже если параметры недоступны и доступны лишь итоговые оценки классов. В таком случае можно вычислять градиент по данным численно или использовать иные стратегии локального стохастического поиска и т.п. Заметим, что благодаря последнему подходу даже недифференцируемые классификаторы (например, Random Forests) не защищены (хотя эмпирически это я пока ни у кого не видел подтверждённым).
Fooling a Linear Classifier on ImageNet
Обман линейного классификатора на ImageNet
As I mentioned before (and as described in more detail in Goodfellow et al.), it is the use of linear functions that makes our models susceptible for an attack. ConvNets, of course, do not express a linear function from images to class scores; They are a complex Deep Learning model that expresses a highly non-linear function. However, the components that make up a ConvNet are linear: Convolution of a filter with its input is a linear operation (we are sliding a filter through the input and computing dot products - a linear operation), and matrix multiplications are also a linear function.
Как я упоминал ранее (и как подробнее описано у Goodfellow et al.), именно использование линейных функций делает наши модели уязвимыми для атаки. ConvNets, конечно, не выражают линейную функцию от изображений к оценкам классов; это сложная Deep Learning-модель, выражающая сильно нелинейную функцию. Однако компоненты, из которых собрана ConvNet, линейны: свёртка фильтра с входом — линейная операция (мы скользим фильтром по входу и вычисляем скалярные произведения — линейная операция), и матричные умножения также линейны.
So here’s a fun experiment we’ll do. Lets forget about ConvNets - they are a distracting overkill as far as the core flaw goes. Instead, lets fool a linear classifier and lets also keep with the theme of breaking models on images because they are fun to look at.
Вот забавный эксперимент, который мы проделаем. Забудем про ConvNets — для сути проблемы это отвлекающий «перебор». Вместо этого обманем линейный классификатор и для верности продолжим тему ломания моделей на изображениях, потому что на них приятно смотреть.
Here is the setup:
Постановка такая:
Возьмём 1,2 миллиона изображений из ImageNet, уменьшим их до 64×64 (полноразмерные обучались бы дольше) и при помощи Caffe обучим линейный классификатор (например, Softmax). Иными словами, идём напрямую от данных к классификатору через единственный полносвязный слой.
Digression: Technical fun parts. The fun part in actually doing this is that the standard AlexNetty ConvNet hyperparameters are of course completely inadequate. For example, normally you’d use weight decay of 0.0005 or so and learning rate of 0.01, and gaussian initialization drawn from a gaussian of 0.01 std. If you’ve trained linear classifiers before on this type of high-dimensional input (64x64x3 ~= 12K numbers), you’ll know that your learning rate will probably have to be much lower, the regularization much larger, and initialization of 0.01 std will probably be inadequate. Indeed, starting Caffe training with default hyperparameters gives a starting loss of about 80, which right away tells you that the initialization is completely out of whack (initial ImageNet loss should be ballpark 7.0, which is -log(1/1000)). I scaled it down to 0.0001 std for Gaussian init which gives sensible starting loss. But then the loss right away explodes which tells you that the learning rate is way too high - I had to scale it all the way down to about 1e-7. Lastly, a weight decay of 0.0005 will give almost negligible regularization loss with 12K inputs - I had to scale it up to 100 to start getting reasonably-looking weights that aren’t super-overfitted noise blobs. It’s fun being a Neural Networks practitioner.
Лирическое отступление: технические забавности. Веселье в реальном проведении этого эксперимента в том, что стандартные гиперпараметры AlexNet-подобной ConvNet здесь совершенно неадекватны. Обычно вы используете weight decay около 0.0005, learning rate 0.01 и гауссову инициализацию со стандартным отклонением 0.01. Если вы раньше обучали линейные классификаторы на входе такого размера (64×64×3 ≈ 12K чисел), вы знаете, что learning rate, вероятно, должен быть гораздо ниже, регуляризация — гораздо больше, а инициализация со std 0.01, скорее всего, неадекватна. Действительно, запуск обучения в Caffe с дефолтными гиперпараметрами даёт стартовую loss около 80, что сразу говорит об абсолютно неадекватной инициализации (стартовая loss на ImageNet должна быть порядка 7.0, то есть −log(1/1000)). Я уменьшил std гауссовой инициализации до 0.0001, что дало разумную стартовую loss. Но затем loss тут же взрывается — это означает, что learning rate слишком велик; пришлось снизить его аж до примерно 1e−7. Наконец, weight decay 0.0005 при 12K входов даёт почти нулевую регуляризационную loss — пришлось поднять его до 100, чтобы получить разумно выглядящие веса, а не сверхпереобученные шумовые кляксы. Весело быть практиком в области нейронных сетей.
A linear classifier over image pixels implies that every class score is computed as a dot product between all the image pixels (stretched as a large column) and a learnable weight vector, one for each class. With input images of size 64x64x3 and 1000 ImageNet classes we therefore have 64x64x3x1000 = 12.3 million weights (beefy linear model!), and 1000 biases. Training these parameters on ImageNet with a K40 GPU takes only a few tens of minutes. We can then visualize each of the learned weights by reshaping them as images:
Линейный классификатор поверх пикселей изображения означает, что оценка каждого класса вычисляется как скалярное произведение всех пикселей изображения (вытянутых в длинный столбец) и обучаемого вектора весов — отдельного на каждый класс. С входными изображениями 64×64×3 и 1000 классами ImageNet у нас получается 64×64×3×1000 = 12.3 миллиона весов (внушительная линейная модель!) и 1000 смещений. Обучение этих параметров на ImageNet на GPU K40 занимает всего несколько десятков минут. Затем мы можем визуализировать каждый из выученных весов, переформатировав их как изображения:
By the way, I haven’t seen anyone report linear classification accuracy on ImageNet before, but it turns out to be about 3.0% top-1 accuracy (and about 10% top-5) on ImageNet. I haven’t done a completely exhaustive hyperparameter sweep but I did a few rounds of manual binary search.
Кстати, я раньше не видел, чтобы кто-то приводил точность линейной классификации на ImageNet, но оказалось, что это около 3.0% top-1 (и около 10% top-5) на ImageNet. Я не делал полностью исчерпывающий перебор гиперпараметров, но прогнал несколько раундов ручного бинарного поиска.
Now that we’ve trained the model parameters we can start to produce fooling images. This turns out to be quite trivial in the case of linear classifiers and no backpropagation is required. This is because when your score function is a dot product \(s = w^Tx\), then the gradient on the image \(x\) is simply \(\nabla_x s = w\). That is, we take an image we would like to start out with, and then if we wanted to fool the model into thinking that it is some other class (e.g. goldfish), we have to take the weights corresponding to the desired class, and add some fraction of those weights to the image:
Теперь, когда параметры модели обучены, можно начать производить обманные изображения. В случае линейных классификаторов это оказывается совсем тривиальным, и backpropagation не требуется. Дело в том, что когда ваша оценочная функция — скалярное произведение \(s = w^Tx\), градиент по изображению \(x\) есть просто \(\nabla_x s = w\). То есть берём изображение, с которого хотим стартовать, и если хотим обмануть модель, чтобы она сочла его другим классом (например, «золотая рыбка»), берём веса, соответствующие желаемому классу, и прибавляем к изображению некоторую долю этих весов:
We can also start from random noise and achieve the same effect:
Можно также начать со случайного шума и достичь того же эффекта:
Of course, these examples are not as impactful as the ones that use a ConvNet because the ConvNet gives state of the art performance while a linear classifier barely gets to 3% accuracy, but it illustrates the point that even with a simple, shallow function it is still possible to play around with the input in imperceptible ways and get almost arbitrary results.
Конечно, эти примеры не столь впечатляющи, как примеры с ConvNet, потому что ConvNet даёт state-of-the-art-результат, а линейный классификатор едва выдаёт 3% точности, но они иллюстрируют тезис: даже с простой, мелкой функцией можно незаметно играть с входом и получать практически любые результаты.
Regularization. There is one subtle comment to make regarding regularization strength. In my experiments above, increasing the regularization strength gave nicer, smoother and more diffuse weights but generalized to validation data worse than some of my best classifiers that displayed more noisy patterns. For example, the nice and smooth templates I’ve shown only achieve 1.6% accuracy. My best model that achieves 3.0% accuracy has noisier weights (as seen in the middle column of the fooling images). Another model with very low regularization reaches 2.8% and its fooling images are virtually indistinguishable yet produce 100% confidences in the wrong class. In particular:
Регуляризация. Здесь есть один тонкий момент насчёт силы регуляризации. В моих экспериментах выше усиление регуляризации давало более красивые, гладкие и размытые веса, но обобщалось на валидационных данных хуже, чем некоторые из моих лучших классификаторов, демонстрировавших более шумные паттерны. Например, красивые и гладкие шаблоны, которые я показал, дают всего 1.6% точности. Моя лучшая модель с 3.0% точности имеет более шумные веса (как видно в средней колонке обманных изображений). Другая модель с очень слабой регуляризацией достигает 2.8%, и её обманные изображения практически неотличимы от оригинала, но дают 100% уверенность в неправильном классе. В частности:
Высокая регуляризация даёт более гладкие шаблоны, но в какой-то момент начинает работать хуже. Зато она устойчивее к обману (обманные изображения заметно отличаются от оригиналов). Низкая регуляризация даёт более шумные шаблоны, но, похоже, работает лучше, чем полностью гладкие шаблоны. Она менее устойчива к обману.
Intuitively, it seems that higher regularization leads to smaller weights, which means that one must change the image more dramatically to change the score by some amount. It’s not immediately obvious if and how this conclusion translates to deeper models.
Интуитивно: чем выше регуляризация, тем меньше веса, а значит, чтобы изменить оценку на ту же величину, нужно сильнее изменить изображение. Не очевидно сразу, переносится ли этот вывод на более глубокие модели и каким образом.
Toy Example
Игрушечный пример
We can understand this process in even more detail by condensing the problem to the smallest toy example that displays the problem. Suppose we train a binary logistic regression, where we define the probability of class 1 as \(P(y = 1 \mid x; w,b) = \sigma(w^Tx + b)\), where \(\sigma(z) = 1/(1+e^{-z})\) is the sigmoid function that squashes the class 1 score \(s = w^Tx+b\) into range between 0 and 1, where 0 is mapped to 0.5. This classifier hence decides that the class of the input is 1 if \(s > 0\), or equivalently if the class 1 probability is more than 50% (i.e. \(\sigma(s) > 0.5\)). Suppose further that we had the following setup:
Мы можем понять процесс ещё детальнее, сведя задачу к минимальному игрушечному примеру, демонстрирующему проблему. Предположим, мы обучаем бинарную логистическую регрессию, в которой вероятность класса 1 определена как \(P(y = 1 \mid x; w,b) = \sigma(w^Tx + b)\), где \(\sigma(z) = 1/(1+e^{-z})\) — сигмоидная функция, сжимающая оценку класса 1 \(s = w^Tx+b\) в диапазон [0, 1], причём 0 отображается в 0.5. Этот классификатор, таким образом, относит вход к классу 1, если \(s > 0\), или эквивалентно, если вероятность класса 1 больше 50% (т.е. \(\sigma(s) > 0.5\)). Допустим далее, что у нас есть следующая постановка:
x = [2, -1, 3, -2, 2, 2, 1, -4, 5, 1] // input w = [-1, -1, 1, -1, 1, -1, 1, 1, -1, 1] // weight vector
x = [2, -1, 3, -2, 2, 2, 1, -4, 5, 1] // вход w = [-1, -1, 1, -1, 1, -1, 1, 1, -1, 1] // вектор весов
If you do the dot product, you get -3. Hence, probability of class 1 is 1/(1+e^(-(-3))) = 0.0474. In other words the classifier is 95% certain that this is example is class 0. We’re now going to try to fool the classifier. That is, we want to find a tiny change to x in such a way that the score comes out much higher. Since the score is computed with a dot product (multiply corresponding elements in x and w then add it all up), with a little bit of thought it’s clear what this change should be: In every dimension where the weight is positive, we want to slightly increase the input (to get slightly more score). Conversely, in every dimension where the weight is negative, we want the input to be slightly lower (again, to get slightly more score). In other words, an adversarial xad might be:
Если посчитать скалярное произведение, получится -3. Следовательно, вероятность класса 1 равна 1/(1+e^(-(-3))) = 0.0474. Другими словами, классификатор на 95% уверен, что этот пример — класс 0. Попробуем теперь обмануть классификатор. То есть мы хотим найти крошечное изменение x, такое, что оценка станет существенно выше. Поскольку оценка вычисляется скалярным произведением (перемножаем соответствующие элементы x и w и складываем), при небольшом размышлении становится ясно, каким должно быть изменение: в каждом измерении, где вес положителен, мы хотим слегка увеличить вход (чтобы получить чуть больше оценки). И наоборот, в каждом измерении, где вес отрицателен, мы хотим, чтобы вход был чуть меньше (опять же — чтобы получить чуть больше оценки). Иначе говоря, состязательный xad мог бы быть таким:
// xad = x + 0.5w gives: xad = [1.5, -1.5, 3.5, -2.5, 2.5, 1.5, 1.5, -3.5, 4.5, 1.5]
// xad = x + 0.5w даёт: xad = [1.5, -1.5, 3.5, -2.5, 2.5, 1.5, 1.5, -3.5, 4.5, 1.5]
Doing the dot product again we see that suddenly the score becomes 2. This is not surprising: There are 10 dimensions and we’ve tweaked the input by 0.5 in every dimension in such a way that we gain 0.5 in each one, adding up to a total of 5 additional score, rising it from -3 to 2. Now when we look at probability of class 1 we get 1/(1+e^(-2)) = 0.88. That is, we tweaked the original x by a small amount and we improved the class 1 probability from 5% to 88%! Moreover, notice that in this case the input only had 10 dimensions, but an image might consist of many tens of thousands of dimensions, so you can afford to make tiny changes across all of them that all add up in concert in exactly the worst way to blow up the score of any class you wish.
Снова посчитав скалярное произведение, видим, что оценка внезапно становится равной 2. Это неудивительно: 10 измерений, в каждом из них мы изменили вход на 0.5 так, чтобы выигрывать 0.5 на каждом измерении, а это суммарно даёт +5 к оценке, поднимая её с −3 до 2. Теперь, посмотрев на вероятность класса 1, получим 1/(1+e^(-2)) = 0.88. То есть мы немного подправили исходный x и подняли вероятность класса 1 с 5% до 88%! Более того, здесь вход всего лишь 10-мерный, а изображение может состоять из десятков тысяч измерений, так что вы можете позволить себе крошечные изменения по каждому из них, которые слаженно складываются ровно в нужную (с точки зрения атакующего) сторону и взрывают оценку любого нужного класса.
Conclusions
Выводы
Several other related experiments can be found in Explaining and Harnessing Adversarial Examples by Goodfellow et al. This paper is a required reading on this topic. It was the first to articulate and point out the linear functions flaw, and more generally argued that there is a tension between models that are easy to train (e.g. models that use linear functions) and models that resist adversarial perturbations.
Несколько других связанных экспериментов можно найти в работе Explaining and Harnessing Adversarial Examples Goodfellow et al. Эта статья — обязательное чтение по теме. Именно она первой сформулировала и указала на «изъян линейных функций», а в более общем виде утверждала, что есть напряжение между моделями, которые легко обучать (например, использующими линейные функции), и моделями, устойчивыми к состязательным возмущениям.
As closing words for this post, the takeaway is that ConvNets still work very well in practice. Unfortunately, it seems that their competence is relatively limited to a small region around the data manifold that contains natural-looking images and distributions, and that once we artificially push images away from this manifold by computing noise patterns with backpropagation, we stumble into parts of image space where all bets are off, and where the linear functions in the network induce large subspaces of fooling inputs.
В качестве заключительных слов: ConvNets всё ещё очень хорошо работают на практике. К сожалению, их компетенция, похоже, ограничена сравнительно небольшой областью вокруг многообразия данных, содержащего естественно выглядящие изображения и распределения, и стоит нам искусственно сдвинуть изображение прочь от этого многообразия — вычислив шумовой паттерн backpropagation, — как мы оказываемся в той части пространства изображений, где все ставки сняты, а линейные функции внутри сети индуцируют большие подпространства обманных входов.
With wishful thinking, one might hope that ConvNets would produce all-diffuse probabilities in regions outside the training data, but there is no part in an ordinary objective (e.g. mean cross-entropy loss) that explicitly enforces this constraint. Indeed, it seems that the class scores in these regions of space are all over the place, and worse, a straight-forward attempt to patch this up by introducing a background class and iteratively adding fooling images as a new background class during training are not effective in mitigating the problem.
При желаемом раскладе можно было бы надеяться, что ConvNet будет выдавать полностью размытые вероятности в областях вне обучающих данных, но в стандартной целевой функции (например, средней кросс-энтропийной loss) нет ничего, что явно навязывало бы это ограничение. И действительно, оценки классов в таких областях пространства, похоже, ведут себя как попало; хуже того, простой попытка залатать это введением фонового класса и итеративным добавлением обманных изображений в этот background-класс во время обучения проблему не снимает.
It seems that to fix this problem we need to change our objectives, our forward functional forms, or even the way we optimize our models. However, as far as I know we haven’t found very good candidates for either. To be continued.
Похоже, чтобы исправить эту проблему, нужно менять наши целевые функции, формы прямого прохода или даже способ оптимизации моделей. Однако, насколько мне известно, мы пока не нашли по-настоящему хороших кандидатов ни на что из этого. Продолжение следует.
Further Reading
Дополнительное чтение
Ian Goodfellow выступил с докладом по этой работе на RE.WORK Deep Learning Summit 2015. Вы можете обмануть ConvNet в рамках CS231n Assignment #3 IPython Notebook. IPython Notebook для этого эксперимента. Также мои прото-файлы линейного классификатора Caffe, если вам интересно.