Метод быстрого градиентного знака: большие потери, но нулевые градиенты?
Я играю с состязательными атаками. Один из известных методов - это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
.
Почему я получаю нулевые градиенты или, по крайней мере, очень-очень маленькие градиенты на вводе, даже если потери очень велики? Это может быть общее недопонимание градиентного спуска, поэтому я был бы признателен, если у вас есть какие-либо объяснения:)
Спасибо!