使用lmdb“lightning”数据库快速查询单词嵌入。
lmdb-embeddings的Python项目详细描述
LMDB嵌入
查询词向量(嵌入)非常快速,查询时间开销非常小,内存使用量远低于gensim或其他等效解决方案。这是由Lightning Memory-Mapped Database实现的。
灵感来自Delft。正如他们在自述中所解释的,这种方法允许我们让预先训练好的嵌入立即“热”(无加载时间),以释放内存,并在使用ssd时以类似方式使用任意数量的嵌入,对运行时的影响非常小。
例如,在传统方法中,glove-840B
需要大约2分钟的加载时间和4GB的内存。使用LMDB管理,glove-840B
可以立即访问,只占用几MB内存,对运行时的影响可以忽略不计(大约慢1%)
读取矢量
fromlmdb_embeddings.readerimportLmdbEmbeddingsReaderfromlmdb_embeddings.exceptionsimportMissingWordErrorembeddings=LmdbEmbeddingsReader('/path/to/word/vectors/eg/GoogleNews-vectors-negative300')try:vector=embeddings.get_word_vector('google')exceptMissingWordError:# 'google' is not in the database.pass
写入向量
从gensim模型编写lmdb矢量文件的示例。由于任何产生单词和向量对的迭代器都受支持,如果向量采用了另一种格式,那么只需要适当地修改下面的iter_embeddings
方法。
我将很快编写一个cli接口来转换标准格式。
fromgensim.models.keyedvectorsimportKeyedVectorsfromlmdb_embeddings.writerimportLmdbEmbeddingsWriterGOOGLE_NEWS_PATH='GoogleNews-vectors-negative300.bin.gz'OUTPUT_DATABASE_FOLDER='GoogleNews-vectors-negative300'print('Loading gensim model...')gensim_model=KeyedVectors.load_word2vec_format(GOOGLE_NEWS_PATH,binary=True)defiter_embeddings():forwordingensim_model.vocab.keys():yieldword,gensim_model[word]print('Writing vectors to a LMDB database...')writer=LmdbEmbeddingsWriter(iter_embeddings()).write(OUTPUT_DATABASE_FOLDER)# These vectors can now be loaded with the LmdbEmbeddingsReader.
定制
默认情况下,LMDB嵌入使用pickle将向量序列化为字节(使用最高可用协议进行优化和pickle)然而,使用另一种方法非常容易——只需将序列化器和非序列化器作为可调用项注入LmdbEmbeddingsWriter
和LmdbEmbeddingsReader
。
包含一个msgpack序列化程序,可以以相同的方式使用。
fromlmdb_embeddings.writerimportLmdbEmbeddingsWriterfromlmdb_embeddings.serializersimportMsgpackSerializerwriter=LmdbEmbeddingsWriter(iter_embeddings(),serializer=MsgpackSerializer.serialize).write(OUTPUT_DATABASE_FOLDER)
fromlmdb_embeddings.readerimportLmdbEmbeddingsReaderfromlmdb_embeddings.serializersimportMsgpackSerializerreader=LmdbEmbeddingsReader(OUTPUT_DATABASE_FOLDER,unserializer=MsgpackSerializer.unserialize)
运行测试
pytest