fasttext:有没有办法导出ngram?

时间:2019-03-12 12:06:42

标签: export gensim n-gram fasttext oov

我是DL和NLP的新手,最近开始通过gensim使用预先训练的fastText嵌入模型(cc.en.300.bin)。

我希望能够通过将单词拆分为n-gram并为每个n-gram查找矢量来自己计算出词汇量以外的单词的向量。

我找不到导出模型中n元语法向量的方法。我意识到它们是经过哈希处理的,但是也许有一种方法(不一定使用gensim)来获取它们?

任何见识将不胜感激!

2 个答案:

答案 0 :(得分:0)

通过直接检查其gensimFastTextKeyedVectors方法的源代码,您可以确切地了解word_vec()代码如何为词汇外单词创建FastText单词向量: / p>

https://github.com/RaRe-Technologies/gensim/blob/3aeee4dc460be84ee4831bf55ca4320757c72e7b/gensim/models/keyedvectors.py#L2069

(请注意,gensim的{​​{1}}分支中的此源代码可能反映了最新的FastText修复,这些修复与通过develop版本3.7.1安装的软件包不匹配;您可能需要查阅已安装软件包的本地源代码,或等待这些修补程序发布在官方版本中。)

由于Python不会保护相关对象的任何部分免受外部访问(例如使用强制性的“私有”指定),因此您可以从类外部执行完全相同的操作。

特别要注意的是,在当前代码(与Facebook原始实现的行为相匹配)中,无论您当前的n-gram是否为n,从哈希表gensim结构的存储桶中提取n-gram向量。是否在训练数据中真正知道。在训练数据中已知这些n-gram且有意义的情况下,这应该对OOV向量有所帮助。在获取任意其他向量的情况下,这种随机性应该不会有太大的伤害。

答案 1 :(得分:0)

我最近亲自遇到了这个问题,不得不编写脚本来减小模型大小。快速文本C代码包括一个方便的函数“阈值”以减小字典的大小,但是它没有暴露给python绑定。在减少字典之后,您还需要重新构建输入矩阵,包括主要单词向量之后的ngram桶。以这种方式保存模型后,将仅根据子词信息生成所有词向量(剩余的词典词除外)

对于单词相似性搜索,不使用output_和model_。要节省更多内存,您也可以只注释掉在saveModel中写output_的部分

请注意,在英语预训练模型中,ngram条目本身大约为2Gb,因此即使删除了所有词典单词,这也可以使模型最小。

/* note: some dict_ members are public for easier access */
void FastText::quantize(const Args& qargs) {
  /*if (args_->model != model_name::sup) {
    throw std::invalid_argument(
        "For now we only support quantization of supervised models");
  }*/
  args_->input = qargs.input;
  args_->qout = qargs.qout;
  args_->output = qargs.output;
  std::shared_ptr<DenseMatrix> input =
      std::dynamic_pointer_cast<DenseMatrix>(input_);
  std::shared_ptr<DenseMatrix> output =
      std::dynamic_pointer_cast<DenseMatrix>(output_);
  bool normalizeGradient = (args_->model == model_name::sup);

  if (qargs.cutoff > 0 && qargs.cutoff < input->size(0)) {
    /*auto idx = selectEmbeddings(qargs.cutoff);
    dict_->prune(idx);*/
    int32_t rows = dict_->size_+args_->bucket;
    dict_->threshold(2000, 2000);
    std::cerr << "words:  " << dict_->size_ << std::endl;
    std::cerr << "rows:  " << rows << std::endl;
    /*std::shared_ptr<DenseMatrix> ninput =
        std::make_shared<DenseMatrix>(idx.size(), args_->dim);*/
    int32_t new_rows = dict_->size_+args_->bucket;
    std::shared_ptr<DenseMatrix> ninput = std::make_shared<DenseMatrix>(dict_->size_+args_->bucket, args_->dim);
    for (auto i = 0; i < dict_->size_; i++) {
      for (auto j = 0; j < args_->dim; j++) {
        int32_t index = dict_->getId(dict_->words_[i].word);
        ninput->at(i, j) = input->at(index, j);
      }
    }

    int32_t offset = rows-new_rows;
    for (auto i = dict_->size_; i < new_rows; i++) {
      for (auto j = 0; j < args_->dim; j++) {
        ninput->at(i, j) = input->at(i+offset, j);
      }
    }
    /*input = ninput;*/
    input_ = ninput;
    if (qargs.retrain) {
      args_->epoch = qargs.epoch;
      args_->lr = qargs.lr;
      args_->thread = qargs.thread;
      args_->verbose = qargs.verbose;
      auto loss = createLoss(output_);
      model_ = std::make_shared<Model>(input, output, loss, normalizeGradient);
      startThreads();
    }
  }

  /*input_ = std::make_shared<QuantMatrix>(
      std::move(*(input.get())), qargs.dsub, qargs.qnorm);*/

  /*if (args_->qout) {
    output_ = std::make_shared<QuantMatrix>(
        std::move(*(output.get())), 2, qargs.qnorm);
  }
*/
  /*quant_ = true;*/
  auto loss = createLoss(output_);
  model_ = std::make_shared<Model>(input_, output_, loss, normalizeGradient);
}