Adversarial training
Введение
Довольно часто можно услышать о том, что нейросеть обошла человека при решении той или иной задачи. Например, модели для CV. Считается, что они стали лучше нас уже в 2015 году.
Это не совсем так. Замеры для сопоставления человека и нейросети проводятся на подвыборках: они лишь похожи на тренировочную систему, а в реальной могут работать хуже, особенно при желании намеренного обмана нейросети человеком 🙂
Давайте посмотрим на следующие два рисунка и подумаем, что на каждом из них изображено.
По мнению resnet152, на первой картинке представлен молоток, а на второй — топор!
Почему так? Вторая картинка была получена при помощи первой за счет добавления специального вектора возмущения (perturbation). Для человеческого глаза разница между изображениями незаметна, однако нейросеть предсказывает ошибочный класс. В случае с молотком и топором это не критично, но если злоумышленник решит попробовать обмануть нейросеть автопилота, это может привести к плачевным последствиям.
Изменение входного вектора с целью “обмана” нейросети называется состязательной (adversarial) атакой.
Adversarial атаки
Самая простая состязательная атака — поиск вектора возмущения
Давайте рассмотрим градиент:
\( \nabla_{\epsilon}(L)= \frac{dL(N_w(x+\epsilon), y)}{d\epsilon} \)
где \( L \) — лосс функция;
\( x \) — исходное изображение;
\( N \) — нейросеть c весами \( w \).
Напомним, что градиент — это направление самого быстрого увеличения функции. Значит, при движении \( \epsilon \) в сторону градиента мы максимизируем лосс функцию, что нам и нужно. Следовательно, мы можем вывести шаг градиентного спуска для оптимизации \( \epsilon \) (на самом деле это градиентный “подъем”, так как мы максимизируем функцию):
\( \epsilon= \epsilon+η⋅\nabla_{\epsilon}(L) \)
где \( η \) — learning rate.
Если мы хотим, чтобы \( \epsilon \) был мал, а значит, незаметен для человека, то мы добавляем регуляризацию (либо для ограничения порогом пользуемся torch.clip).
В коде такую атаку можно реализовать следующим образом:
hummer_class_number = 587 # номер класса hummer из ImageNet
tiger_cat_class_number = 282 # номер класса tiger_cat из ImageNet
model = resnet152(pretrained=True)
model.eval()
eps = torch.zeros_like(img_tensor, requires_grad=True)
opt = optim.SGD([eps], lr=1, weight_decay=1e-3)
for step in range(7):
pred = model(img_tensor + eps)
loss = -F.cross_entropy(pred, torch.LongTensor([hummer_class_number]))
opt.zero_grad()
loss.backward()
opt.step()
print(torch.abs(eps).max().item()) # tensor(0.1409)
prediction = model(img_tensor + eps)
prediction_class_id = prediction.argmax().item()
print(classes[prediction_class_id]) # "hatchet"
Так нейросеть вместо молотка распознала топор. Это несильно страшно, ведь они в целом похожи. А давайте теперь найдем \( \epsilon \), при котором нейросеть вместо молотка предскажет нам тигра?
Для этого мы просто немного изменим лосс функцию и получим targeted attack (направленную атаку):
loss += F.cross_entropy()(pred, torch.LongTensor([tiger_cat_class_number]))
И, вуаля, перед нами изображение тигра, который выглядит как молоток!
Adversarial training
Нам важно сделать наши модели устойчивыми к подобным атакам. Для этого модели должны предсказывать правильный класс при изменении каждого пикселя не более, чем на \( p \):
\( L_{adv}=\underset{(||\epsilon||_{\infty}\le p )}{\max}L(N_w(x+\epsilon),y) \)
Однако есть проблема при оптимизации такой функции с помощью градиентного спуска, ведь мы не знаем чему равен \( \epsilon \), и нам хотелось бы его найти. Следовательно, нужно решить задачу оптимизации:
\( \epsilon=\underset{\epsilon}\argmax(L(N(x+\epsilon),y)) \)
Такая оптимизационная задача может быть решена с помощью градиентного “подъема” (про него мы говорили в части про Adversarial атаки).
Получается, шаг обучения модели, устойчивой к Adversarial атакам, создается следующим образом:
- Берем батч из тренировочной выборки;
- Делаем несколько шагов обновления \( \epsilon= \epsilon+η⋅\nabla_{\epsilon}(L) \);
- Считаем \( \frac {dL(N_w(x+\epsilon),y)}{dw} \);
- Обновляем веса модели.
Если на втором этапе мы делаем один шаг, то такой метод поиска \( \epsilon \) называется Fast Gradient Sign Method (FGSM), а если несколько — Projected gradient descent (PGD). Также \( \epsilon \) можно найти с помощью линейного программирования, но это вычислительно емкий процесс.
Устойчивость к Adversarial атакам оценивается c помощью robust метрик. Они отличаются от обычных тем, что вместо входного вектора в них мы используем вектор, к которому мы применили атаку.
Проблемы устойчивых моделей
У моделей, полученных с помощью Adversarial training, есть несколько проблем, которые мешают их повсеместному использованию.
Во-первых, при повышении устойчивости модели ухудшаются обычные метрики. Эта проблема решается увеличением количества входных данных.
Во-вторых, разница в robust метриках на тренировочной и тестовой выборках очень высока. Такая проблема решается только использованием более сложных подходов. Разница между ошибкой на тренировочной и тестовой выборках называется generalisation gap.
Adversarial weight perturbation
В статье авторы предлагают метод, в котором помимо входного изображения модифицируются еще и веса модели. Они ищут изменение весов, максимизирующее ошибку.
Мотивация подхода следующая: при таком изменении мы получим веса, которые будут лежать в “плоском” минимуме, что уменьшит generalisation gap.
Более подробно об этом можно почитать в статье Sharpness-Aware Minimization.
Сам алгоритм выглядит так:
- Берем батч из тренировочной выборки
- Делаем несколько шагов обновления
\( \epsilon= \epsilon+η_1⋅\nabla_{\epsilon}(L) \)
- Делаем несколько шагов обновления
\( v= v+η_2\frac{dL(N_{w+v}(x+\epsilon), y)}{dv} \)
- Считаем градиент в точке \( w+v \) и обновляем веса модели в точке \( w \) (не в \( w+v \) !!!)
\( w= w-η_3\frac{dL(N_{w+v}(x+\epsilon), y)}{dw} \)
Реализацию алгоритма можно посмотреть в репозитории авторов.
Diffusion Models
В недавнем исследовании предлагается использовать при обучении устойчивых моделей синтетические данные, полученные с помощью диффузных моделей. Авторы показывают, что данный подход значительно увеличивает как обычные метрики полученных моделей, так и robust метрики.
Правда, этот метод очень затратный, так как нужно предварительно обучить диффузную модель и сгенерировать изображения (авторы генерировали 50 миллионов дополнительных картинок).
Заключение
В заключение добавим, что исследования в этой области все увеличиваются, а ученые продолжают заниматься улучшением данных методов. Основные проблемы подхода, которые еще не решены — необходимость значительно большего количества данных для обучения, увеличение скорости обучения и исследование всевозможных атак (мы рассмотрели только добавление вектора, но еще есть, например, повороты).