【问题标题】:Online adversarial training on NLP taskNLP 任务的在线对抗训练
【发布时间】:2020-04-17 12:13:08
【问题描述】:

我想为我的神经网络实现一个自定义损失函数,以便同时考虑对抗性示例在训练期间的贡献,使用快速梯度符号法计算。

其中 J 是针对输入计算的经典分类交叉熵。而 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 的基础。你有什么建议吗?另外,你认为我走对了吗?

重要

当且仅当我从网络中移除嵌入层时,我才能计算梯度。但是问题是我无法训练我的嵌入,因此准确性不会增加。所以我需要嵌入层在网络中。

【问题讨论】:

    标签: python tensorflow keras neural-network


    【解决方案1】:

    神经网络在连续空间上运行,不知道如何处理像单词这样的离散空间。这就是为什么 NLP 任务首先将离散的单词 ID 嵌入到一个连续的空间中。

    Fast Gradient Sign Method,它清楚地使用了梯度并且还操作了那个连续的空间,可以让你达到对抗性嵌入的程度。但是如果你想要一个对抗性的示例,那么你需要以某种方式从对抗性嵌入转换为对抗性词。

    Black-box Generation of Adversarial Text Sequences 上的这篇论文描述了一个这样的想法。

    最近的多项研究 [21, 25] 定义了对抗性扰动 基于RNN的文本分类器。 [21] 先随机选词 在文本输入中定位,然后使用投影的快速渐变符号 扰动单词嵌入向量的方法。扰动向量被投影到词嵌入中最近的词向量 空间,导致对抗序列(对抗示例 在文本情况下)。

    但是在引用之后,他们说这种技术并不总是能产生很好的例子。也许它适合您的目的,或者您可能想深入研究论文,看看他们的黑匣子想法是如何运作的。

    或者也许您不需要生成对抗性词,对抗性嵌入就足够了。如果是这样,请继续阅读。


    我的旧想法,没有研究支持。

    另一个前进的道路是在嵌入之上生成对抗样本,而不是嵌入所基于的索引。那就是:

    1. 运行嵌入。
    2. 将其直接馈送到模型的 answer 部分,这会产生一半的损失。
    3. 以对抗的方式更新嵌入。这现在可以工作了,因为您正在处理嵌入,它是浮点型并且适合 FGSM 更新。
    4. 将对抗样本提供给您的 answer 子网,这会导致损失的后半部分。

    这在 PyTorch 中很简单,但不幸的是我不知道在 Keras 中执行此操作的便捷方法是对模型的 compile() 的前期要求,而不是将其分成两部分。

    【讨论】:

    • 我认为我有一些很好的材料可以使用。我真的很感谢你的建议。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2019-10-08
    • 2013-05-05
    • 2016-01-19
    • 2018-02-13
    • 1970-01-01
    • 2014-02-10
    • 2020-11-07
    • 1970-01-01
    相关资源
    最近更新 更多