Я играю с состязательными атаками. Один из известных методов - это Fast Gradient Sign Method
. Я настроил модель VGG16 на наборе данных STL-10, который я использую для извлечения состязательных изображений. Я проверил свой код, и он работает правильно.
Я использую cross_entropy
как функцию потерь.
Но я заметил одну вещь, которую не могу объяснить: В качестве примера возьмите следующее изображение: 
Результат модели:
model_pred=[2.9802322e-08, 3.9100647e-04, 8.3446503e-07, 7.8368187e-04,
3.3617020e-05, 9.9810326e-01, 8.8602304e-05, 7.6818466e-04,
5.9614644e-07, 9.8974469e-06]
Таким образом, модель почти уверена, что изображение показывает собаку (класс 5), что является правильным.
Во время целевой атаки я хочу, чтобы модель предсказывала метку airplane(class0)
для этого изображения. Градиенты вычисляются в этих функциях:
def _build(self):
target_ph = k.placeholder(shape=self.classifier.output.shape) # target placeholder
loss_function = k.categorical_crossentropy # loss function = model.loss
loss = loss_function(target_ph, self.classifier.output, from_logits=False) # we pass probabilities
loss_gradients = k.gradients(loss, self.classifier.input)[0] # remove outer dimension
self._loss_gradients = k.function([self.classifier.input, target_ph], [loss, loss_gradients]) # create function
def _get_loss_gradient(self, x, target):
loss, gradients = self._loss_gradients([x, target])
print(loss, gradients)
return np.sign(gradients)
Потери между прогнозом модели и целевой меткой [1 0 0 0 0 0 0 0 0 0]
(самолет) составляют 16.11
, что очень велико. В этом есть смысл, потому что разница между этими классами огромна. Если я напечатаю результирующие градиенты (относительно ввода) из loss, gradients = self._loss_gradients([x, target])
, я вижу, что все они равны нулю. Поэтому к изображению не добавляется никаких возмущений, и атака терпит неудачу.
Как только градиенты не равны нулю, независимо от того, насколько они малы, атака работает, потому что тогда np.sign(gradients)
преобразует маленькие значения в 1
или -1
.
Почему я получаю нулевые градиенты или, по крайней мере, очень-очень маленькие градиенты на вводе, даже если потеря очень велика? Это может быть общее непонимание градиентного спуска, поэтому я был бы признателен, если у вас есть какие-либо объяснения :)
Спасибо!