Онлайн состязательный тренинг по заданию НЛП - PullRequest
1 голос
/ 16 апреля 2020

Я хотел бы реализовать пользовательскую функцию потерь для своей нейронной сети, чтобы учесть также влияние состязательных примеров во время обучения, вычисленных с помощью метода быстрого градиентного знака.

Custom Loss Function

, где J - это классическая c категориальная кросс-энтропия, рассчитанная по входам. И x + delta является примером состязательности.

Структура сети

Более подробно моя сеть выглядит следующим образом :

sentence = Input(shape=(story_maxlen,))
encoded_sentence = Embedding(vocab_size, embed_size, input_length=story_maxlen)(sentence)

question = Input(shape=(query_maxlen,))
encoded_question = Embedding(vocab_size, embed_size, input_length=query_maxlen)(question)

merged = concatenate([encoded_sentence, encoded_question], axis=1)
answer = LSTM(lstm_size, return_sequences=True)(merged)
answer = Dense(mlp_size, activation='tanh')(merged)
answer = Dropout(dropout_rate)(answer)
answer = Flatten()(answer)
answer = Dense(vocab_size, activation='softmax')(answer)

model = Model([sentence, question], answer)
model.compile(optimizer="adam", loss=my_loss_wrapper([sentence,question]), metrics=['accuracy'])

А затем моя пользовательская функция потерь с функцией генерирования альтернативных примеров:

def generate_advers(model, epsilon):

    x1 = input_tensor[0]
    x2 = input_tensor[1]
    answer = y_true

    x1 = tf.Variable(x1)
    x2 = tf.Variable(x2)

    with tf.GradientTape() as tape:
        tape.watch([x1, x2])

        proba = model([x1, x2])            
        loss = K.categorical_crossentropy(answer, proba[0])

    # Get the gradients of the loss w.r.t to the input.
    gradient = tape.gradient(loss, [x1, x2])

    g1 = gradient[0]
    g2 = gradient[1]

    signed_grad_st = tf.sign(g1)
    signed_grad_qu = tf.sign(g2)

    delta_1 = tf.multiply(signed_grad_st, epsilon)
    delta_2 = tf.multiply(signed_grad_qu, epsilon)

    x1_adv = tf.add(x1, delta_1)
    x2_adv = tf.add(x2, delta_2)

    proba_adv = model([x1_adv, x2_adv])

    loss_advers = K.categorical_crossentropy(label, proba_adv[0])

    return loss_advers

def my_loss_wrapper(input_tensor):

    def my_loss(y_true, y_pred):
        alpha = 0.05
        alpha_compl = 1.0 - alpha
        epsilon = 0.15

        loss_advers = generate_advers(model, epsilon)
        loss_advers = alpha_compl*loss_advers
        loss_true = K.categorical_crossentropy(y_true, y_pred)
        loss_true = alpha*loss_true

        total = loss_true + loss_advers
        return total

    return my_loss

Предоставление того, что мой ввод является закодированным вектором словарных индексов в форме:

[1,5,4,3,6,9...]

Я не понимаю, как вычислить градиент потерь по отношению к входу (он всегда отсутствует), что является фундаментальным для реализации FGSM. Есть ли у вас какие-либо предложения? Кроме того, как вы думаете, я на правильном пути?

Важно

Я могу вычислить градиент, если и только если я удалить Уровень встраивания из сети. Но тогда проблема в том, что я не могу тренировать свои вложения, и поэтому точность не увеличивается. Поэтому мне нужно, чтобы слой Embedded был в сети.

1 Ответ

1 голос
/ 16 апреля 2020

Нейронные сети работают в непрерывном пространстве и не знают, что делать с дискретным пространством, таким как слова. Вот почему задачи НЛП начинаются с встраивания дискретных идентификаторов слов в непрерывное пространство.

Метод быстрого знака градиента, который четко использует градиент и также управляет этим непрерывным пространством, может привести вас к враждебному внедрению. Но если вам нужен состязательный пример , то вам нужно как-то go из этого состязательного вложения в состязательное слово.

Этот документ на Генерация состязательного текста в черном ящике Последовательности описывают одну такую ​​идею.

Многочисленные недавние исследования [21, 25] определили состязательные возмущения на основанных на RNN текстовых классификаторах. [21] сначала выбрали слово в произвольной позиции при вводе текста, а затем использовали метод проецируемого быстрого знака градиента, чтобы возмущать вектор встраивания слова. Возмущенный вектор проецируется на ближайший вектор слова в пространстве вложения слов, что приводит к состязательной последовательности (примеры состязаний в текстовом случае).

Но сразу после этой цитаты они сказали, что этот метод не всегда генерировать отличные примеры. Возможно, это подойдет для ваших целей, или, возможно, вы захотите глубже погрузиться в бумагу, чтобы увидеть, как работает идея их черного ящика.

Или, может быть, вам не нужно генерировать состязательные слова и состязательное вложение достаточно. Если да, то читайте дальше.


Моя более старая идея, не подкрепленная исследованиями.

Еще один путь вперед - создать пример состязательности на вершине Вложение, а не индексы, на которых основано вложение. То есть:

  1. Запустите встраивание.
  2. Подайте его непосредственно в answer часть вашей модели, которая дает половину вашей потери.
  3. Обновление вложение состязательным образом. Теперь это будет работать, потому что вы работаете с вложениями, которые являются плавающей точкой и подходят для обновления FGSM.
  4. Передайте пример состязательности вашему answer su bnet, который дает вторую половину вашего потеря.

Это просто сделать в PyTorch, но, к сожалению, я не знаю удобного способа сделать это в Керасе, учитывая предварительное требование compile() модели вместо того, чтобы оставить ее в две части.

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