Метод быстрого градиентного знака: большие потери, но нулевые градиенты? - PullRequest
0 голосов
/ 17 июня 2020

Я играю с состязательными атаками. Один из известных методов - это Fast Gradient Sign Method. Я настроил модель VGG16 на наборе данных STL-10, который я использую для извлечения состязательных изображений. Я проверил свой код, и он работает правильно.

Я использую cross_entropy как функцию потерь.

Но я заметил одну вещь, которую не могу объяснить: В качестве примера возьмите следующее изображение: enter image description here

Результат модели:

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.

Почему я получаю нулевые градиенты или, по крайней мере, очень-очень маленькие градиенты на вводе, даже если потеря очень велика? Это может быть общее непонимание градиентного спуска, поэтому я был бы признателен, если у вас есть какие-либо объяснения :)

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...