将 torch.nn.Embedding 用于 GloVe:我们应该微调嵌入还是直接使用它们?
Using torch.nn.Embedding for GloVe: should we fine-tune the embeddings or just use them as they are?
虽然迁移学习/微调最近的语言模型(例如 BERT 和 XLNET)是迄今为止非常普遍的做法,但对于 GloVe 来说如何?
基本上,在使用 GloVe 获得可供下游神经网络使用的密集向量表示时,我看到了两个选项。
1) 微调 GloVe 嵌入(在 pytorch 术语中,启用梯度)
2) 只使用没有梯度的嵌入。
例如,给定 GloVe 的嵌入矩阵,我这样做
embed = nn.Embedding.from_pretrained(torch.tensor(embedding_matrix, dtype=torch.float))
...
dense = nn.Linear(...)
最好的做法是单独使用 GloVe 来获得向量表示(并且只训练密集层和可能的其他层)还是微调嵌入矩阵?
没有理由不微调 GloVe 嵌入以获得更好的最终任务分数,除非您必须与另一个使用原始嵌入的模型保持 link(对于例如解释你的结果)。
在为您的 objective 函数微调嵌入时,词嵌入将(可能)失去其初始属性(在词相似性和类比任务中表现良好)。
使用词嵌入只是一种不使用随机向量进行初始化的方法,那么保持随机向量固定是否有意义?
有几篇文章微调词嵌入,例如这篇:https://arxiv.org/abs/1505.07931
我假设你有足够的训练数据。否则最好让词嵌入固定,因为它涉及较少的训练参数,从而避免过度拟合。
你绝对应该微调你的词嵌入矩阵。事情是这样的,当你用 GloVe 词嵌入初始化词嵌入矩阵时,你的词嵌入已经捕获了数据的大部分语义属性。但是,您希望词嵌入适合您解决的任务,即特定任务(检查 Yang)。现在,假设你的数据集中没有足够的数据,你不能自己学习词嵌入矩阵(如果你用随机向量初始化词嵌入矩阵)。正因为如此,你想用在巨大数据集上训练过的通用向量来初始化它。
记住一件非常重要的事情 → 因为你的模型的其余部分将被随机初始化,当你开始训练你的词嵌入矩阵时可能会遭受灾难性遗忘(检查 Howard and Ruder and Kirkpatrick et al. 的工作),即梯度会很大,因为您的模型将严重欠拟合前几批数据,并且您将完全丢失初始向量。您可以通过以下方式克服此问题:
前几个epochs不要微调词嵌入矩阵,保持原样:embeddings = nn.Embedding.from_pretrained(glove_vectors, freeze=True)
.
在模型的其余部分学会适应您的训练数据后,降低学习率,解冻您的嵌入模块 embeddings.weight.requires_grad = True
,然后继续训练。
通过执行上述步骤,您将两全其美。换句话说,您的词嵌入仍将捕获语义属性,同时为您自己的下游任务量身定制。最后,有一些作品(例如检查Ye Zhang)表明立即微调是可以的,但我会选择更安全的选项。
虽然迁移学习/微调最近的语言模型(例如 BERT 和 XLNET)是迄今为止非常普遍的做法,但对于 GloVe 来说如何?
基本上,在使用 GloVe 获得可供下游神经网络使用的密集向量表示时,我看到了两个选项。
1) 微调 GloVe 嵌入(在 pytorch 术语中,启用梯度)
2) 只使用没有梯度的嵌入。
例如,给定 GloVe 的嵌入矩阵,我这样做
embed = nn.Embedding.from_pretrained(torch.tensor(embedding_matrix, dtype=torch.float))
...
dense = nn.Linear(...)
最好的做法是单独使用 GloVe 来获得向量表示(并且只训练密集层和可能的其他层)还是微调嵌入矩阵?
没有理由不微调 GloVe 嵌入以获得更好的最终任务分数,除非您必须与另一个使用原始嵌入的模型保持 link(对于例如解释你的结果)。
在为您的 objective 函数微调嵌入时,词嵌入将(可能)失去其初始属性(在词相似性和类比任务中表现良好)。
使用词嵌入只是一种不使用随机向量进行初始化的方法,那么保持随机向量固定是否有意义?
有几篇文章微调词嵌入,例如这篇:https://arxiv.org/abs/1505.07931
我假设你有足够的训练数据。否则最好让词嵌入固定,因为它涉及较少的训练参数,从而避免过度拟合。
你绝对应该微调你的词嵌入矩阵。事情是这样的,当你用 GloVe 词嵌入初始化词嵌入矩阵时,你的词嵌入已经捕获了数据的大部分语义属性。但是,您希望词嵌入适合您解决的任务,即特定任务(检查 Yang)。现在,假设你的数据集中没有足够的数据,你不能自己学习词嵌入矩阵(如果你用随机向量初始化词嵌入矩阵)。正因为如此,你想用在巨大数据集上训练过的通用向量来初始化它。
记住一件非常重要的事情 → 因为你的模型的其余部分将被随机初始化,当你开始训练你的词嵌入矩阵时可能会遭受灾难性遗忘(检查 Howard and Ruder and Kirkpatrick et al. 的工作),即梯度会很大,因为您的模型将严重欠拟合前几批数据,并且您将完全丢失初始向量。您可以通过以下方式克服此问题:
前几个epochs不要微调词嵌入矩阵,保持原样:
embeddings = nn.Embedding.from_pretrained(glove_vectors, freeze=True)
.在模型的其余部分学会适应您的训练数据后,降低学习率,解冻您的嵌入模块
embeddings.weight.requires_grad = True
,然后继续训练。
通过执行上述步骤,您将两全其美。换句话说,您的词嵌入仍将捕获语义属性,同时为您自己的下游任务量身定制。最后,有一些作品(例如检查Ye Zhang)表明立即微调是可以的,但我会选择更安全的选项。