如何在Gensim Word2Vec中比较基于更改参数的嵌入"Betterness"



TL;DR:如何比较具有不同参数集的两个Word2Vec嵌入的优度

我正在使用Gensim从头开始训练我的数据,包括大约200万个句子的Vocab和20万个单词的Vocab。由于损失是在训练结束时给出的,我找到了一些答案,告诉你上一次的损失与当前损失之间的区别。所以我修改了代码并将其用于我自己。我正在努力获得基于最小损失的最佳模型。我正在使用Optuna进行参数调整,或者说GridSearch。对于任何调整过的参数,我都会使用Callback将我的模型保存在迄今为止损失最小的地方。

我计划在我的分类模型中使用这些嵌入。但是与模型一起训练嵌入将是一项艰巨的任务,因为:

  1. 两者都很耗时
  2. Gensim在多处理器(我有8个(上的工作速度比在GPU上更快(它没有那种支持(,但mu Model在GPU上工作

我如何才能得到一些东西,告诉我嵌入数据的更好性?下面是我使用的代码

from gensim.models import Word2Vec, FastText
from gensim.models.callbacks import CallbackAny2Vec

class LossCallback(CallbackAny2Vec):
    """
    Callback to print loss after each epoch
    """
    def __init__(self):
        self.epoch = 0
        self.min_loss = np.inf
        self.loss_previous_step = np.inf
    def on_epoch_end(self, model):
        total_loss = model.get_latest_training_loss()
        current_loss = (total_loss - self.loss_previous_step) if self.epoch > 0 else total_loss
        
        if current_loss < self.min_loss:
            self.min_loss = current_loss
            print('Minimum Loss. Saving Model')
            model.save(f'word2vec_{round(current_loss,2)}_loss.model')
            
        if current_loss < self.loss_previous_step :
            print(f"Loss Decreased from {self.loss_previous_step} to {current_loss} in Epoch {self.epoch}")
            
        self.epoch += 1
        self.loss_previous_step = current_loss
              
# Below code is in a Gris Search such as eopchs, window, loss etc etc
def tune(trial):
    
    vector_size = trial.suggest_int('vector_size', 32, 128)
    alpha = trial.suggest_uniform('alpha', 1e-3, 1e-1)
    window = trial.suggest_int('window', 3,9)
    min_count = trial.suggest_int('min_count', 2,10)
    sg = trial.suggest_categorical('hs', [0,1],)
    hs = trial.suggest_categorical('sg', [0,1],)
    negative = trial.suggest_int('negative', 0,20)
    cbow_mean = trial.suggest_categorical('cbow_mean',[0,1],)
    ns_exponent = trial.suggest_float('ns_exponent', 0.4,0.9)
    sample = trial.suggest_uniform('sample',1e-5, 1e-1)
    epochs = trial.suggest_int('epochs', 5, 100)
                                        
    w2v = Word2Vec(sentences = data, workers = 6, epochs = epochs, seed = SEED,
                  vector_size = vector_size, alpha = alpha, window = window, min_count = min_count, sg = sg, hs = hs, negative = negative, cbow_mean = cbow_mean, 
                  sample = sample, ns_exponent = ns_exponent)
    
    w2v.build_vocab(corpus_iterable = data)
    w2v.train(data,epochs = w2v.epochs,total_examples = w2v.corpus_count, total_words = w2v.corpus_total_words, compute_loss = True, callbacks=[LossCallback()])
    
    return w2v.get_latest_training_loss()

direction = 'minimize'
name = 'Word2Vec'
study = optuna.create_study(direction=direction,study_name=name, storage = f"sqlite:///fine_tune_emb/{name}.db", load_if_exists=True)
study.optimize(tune, n_trials=50)

模型用于内部优化的内部损失是下游应用程序的错误目标。

例如,扩展模型的大小几乎总是会减少其历元损失。它将有更多的内部状态,基本上可以"记住"训练数据的各个方面,包括训练数据的特殊方面,这些方面不会在其他地方推广到有用的地方。但最终这会降低任何有趣的下游任务的性能:"过拟合"。也就是说:选择内部损失最小的模型几乎肯定会让你误入歧途。

没有一套单词嵌入对每个目的都是最好的。如果你想优化你的训练参数,你应该开发(并不断扩展/改进(一种方法,根据特定于你需求的可重复评估,对任何一组单词向量进行评分。

在最初的word2vec论文中使用的评估之一是单词向量在多大程度上可以用来解决语言类比问题,比如";WORD_A对WORD_B的意义就像WORD_C对的意义一样";。你也可以使用它——Gensim包括针对单词向量运行它的方法,可以使用word2vec论文中使用的确切问题集,也可以使用其他你可以在其他地方找到或自己创建的问题集。例如,参见KeyedVectors.evaluate_word_analogies()方法:

https://radimrehurek.com/gensim/models/keyedvectors.html#gensim.models.keyedvectors.KeyedVectors.evaluate_word_analogies

但是,在这个人工任务中表现最好的词向量可能不适合其他任务,比如类似的信息检索或各种分类器。

Levy&Goldberg观察到,较小的窗口倾向于将单词放在彼此直接句法替换的其他单词附近,而较大的窗口则倾向于将在讨论相同主题/领域时使用的单词放在相互附近。(尤其是他们的表格显示了"霍格沃茨"或"佛罗里达"的邻居:他们是同一类别的其他单词——其他学校或其他州?还是选民/相关实体——城市或字符?(

最新更新