Метод быстрого градиентного знака: большие потери, но нулевые градиенты?

Я играю с состязательными атаками. Один из известных методов - это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.

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

Спасибо!

0 ответов

Другие вопросы по тегам