Gensim word2vec/doc2vec многопоточные параллельные запросы

Я хотел бы вызвать model.wv.most_similar_cosmul на той же копии объекта model, используя multiple cores, на batches of input pairs.

Для модуля multiprocessing требуется несколько копий модуля model, что потребует слишком много оперативной памяти, поскольку объем оперативной памяти моего модуля model составляет 30+ ГБ.

Я попытался оценить свои пары запросов. На первый раунд у меня ушло ~12 часов. Возможно, будут еще раунды. Вот почему я ищу решение для потоковой передачи. Я понимаю, что у Python есть проблема Global Interpreter Lock.

Какие-либо предложения?


person Mai    schedule 28.11.2017    source источник
comment
Какая операционная система? multiprocessing использует fork в Linux, поэтому данные должны быть общими и копироваться только при доступе для записи.   -  person BlackJack    schedule 29.11.2017
comment
@BlackJack Это странно. Как Python заранее узнает, требуется ли сегменту кода доступ для записи или нет? Я думал, что если он не знает, он должен копировать объект для каждого дочернего элемента во время разветвления.   -  person Mai    schedule 29.11.2017
comment
Python не знает, операционная система знает. Это не имеет ничего общего с объектами Python или Python в целом, но с процессами уровня операционной системы и страницами памяти.   -  person BlackJack    schedule 29.11.2017
comment


Ответы (2)


Разветвление процессов с помощью multiprocessing после, когда ваша модель текстового вектора находится в памяти, и неизменная может работать, чтобы позволить многим процессам совместно использовать один и тот же объект в памяти.

В частности, вы хотели бы быть уверены, что автоматическая генерация единично-нормированных векторов (в syn0norm или doctag_syn0norm) уже произошла. Он будет автоматически запущен при первой необходимости вызовом most_similar(), или вы можете принудительно вызвать его с помощью метода init_sims() для соответствующего объекта. Если вы будете только выполнять наиболее похожие запросы между единично-нормированными векторами, никогда не нуждаясь в исходных необработанных векторах, используйте init_sims(replace=True) для затирания необработанных векторов смешанной величины syn0 на месте и, таким образом, сэкономите много адресуемой памяти.

В Gensim также есть варианты использования файлов с отображением памяти в качестве источников гигантских массивов моделей, и когда несколько процессов используют один и тот же файл с отображением памяти только для чтения, ОС будет достаточно умна, чтобы отображать этот файл в физическую память только один раз, предоставляя оба процесса указывают на общий массив.

Более подробное обсуждение сложных моментов использования этой техники в похожем, но не идентичном случае использования см. в моем ответе по адресу:

Как ускорить время загрузки модели Gensim Word2vec?

person gojomo    schedule 30.11.2017

Gensim v4.x.x упростил многое из того, что @gojomo описал выше, как он также объяснил в своем другом ответе здесь. Основываясь на этих ответах, вот пример того, как вы можете использовать многопроцессорную обработку most_similar с эффективным использованием памяти, включая ведение журнала прогресса с помощью tqdm. Поменяйте местами свою собственную модель/набор данных, чтобы увидеть, как это работает в масштабе.

import multiprocessing
from functools import partial
from typing import Dict, List, Tuple

import tqdm
from gensim.models.word2vec import Word2Vec
from gensim.models.keyedvectors import KeyedVectors
from gensim.test.utils import common_texts


def get_most_similar(
    word: str, keyed_vectors: KeyedVectors, topn: int
) -> List[Tuple[str, float]]:
    try:
        return keyed_vectors.most_similar(word, topn=topn)
    except KeyError:
        return []


def get_most_similar_batch(
    word_batch: List[str], word_vectors_path: str, topn: int
) -> Dict[str, List[Tuple[str, float]]]:
    # Load the keyedvectors with mmap, so memory isn't duplicated
    keyed_vectors = KeyedVectors.load(word_vectors_path, mmap="r")
    return {word: get_most_similar(word, keyed_vectors, topn) for word in word_batch}


def create_batches_from_iterable(iterable, batch_size=1000):
    return [iterable[i : i + batch_size] for i in range(0, len(iterable), batch_size)]


if __name__ == "__main__":
    model = Word2Vec(
        sentences=common_texts, vector_size=100, window=5, min_count=1, workers=4
    )

    # Save wv, so it can be reloaded with mmap later
    word_vectors_path = "word2vec.wordvectors"
    model.wv.save(word_vectors_path)

    # Dummy set of words to find most similar words for
    words_to_match = list(model.wv.key_to_index.keys())

    # Multiprocess
    batches = create_batches_from_iterable(words_to_match, batch_size=2)
    partial_func = partial(
        get_most_similar_batch,
        word_vectors_path=word_vectors_path,
        topn=5,
    )

    words_most_similar = dict()
    num_workers = multiprocessing.cpu_count()
    with multiprocessing.Pool(num_workers) as pool:
        max_ = len(batches)
        with tqdm.tqdm(total=max_) as pbar:
            # imap required for tqdm to function properly
            for result in pool.imap(partial_func, batches):
                words_most_similar.update(result)
                pbar.update()
person ZaxR    schedule 30.07.2021