Ответ 1
В последних версиях gensim вы можете загрузить подмножество, начиная с фронта файла, используя необязательный параметр limit
до load_word2vec_format()
. (Похоже, что векторы GoogleNews находятся примерно в порядке наименее частых порядков, поэтому первый N обычно является подмножеством N-размера, который вы хотите. Поэтому используйте limit=500000
, чтобы получить самые частые векторы 500 000 слов - все еще довольно большой словарный запас - сохранение 5/6-й части памяти/времени загрузки.)
Так что это может немного помочь. Но если вы повторно загружаете для каждого веб-запроса, вам все равно придется болеть от загрузки скорости с привязкой к IO и избыточной избыточной памяти для хранения каждой повторной загрузки.
Есть несколько трюков, которые вы можете использовать в комбинации, чтобы помочь.
Обратите внимание, что после загрузки таких векторов в исходном формате word2vec.c-origin, вы можете повторно сохранить их, используя gensim native save()
. Если вы сохраните их несжатыми, а массив поддержки достаточно велик (и набор GoogleNews определенно достаточно велик), массив поддержки будет сбрасываться в отдельный файл в формате двоичного файла. Этот файл позже может быть отображен на карту с диска, используя опцию gensim native [load(filename, mmap='r')][1]
.
Изначально это заставит загрузку казаться мгновенной - вместо того, чтобы читать весь массив с диска, ОС просто отобразит области виртуальных адресов на данные диска, так что через некоторое время, когда код обратится к этим ячейкам памяти, необходимые диапазоны будет считываться с диска. Пока все хорошо!
Однако, если вы выполняете типичные операции, такие как most_similar()
, вы все равно столкнетесь с большими задержками, чуть позже. Это потому, что эта операция требует как первоначального сканирования и расчета по всем векторам (при первом вызове, для создания векторов с нормализованной длиной единицы для каждого слова), а затем другого сканирования и вычисления по всем нормированным векторам (по каждый вызов, чтобы найти N-наиболее похожие векторы). Те, у кого есть полный доступ к проверке, будут отображать всю информацию в целом по массиву - снова стоимость пары минут IO.
То, что вы хотите, состоит в том, чтобы избежать излишнего выполнения этой нормализации единицы и заплатить стоимость ввода-вывода только один раз. Это требует сохранения векторов в памяти для повторного использования всеми последующими веб-запросами (или даже несколькими параллельными веб-запросами). К счастью, отображение памяти также может помочь здесь, хотя и с несколькими дополнительными этапами подготовки.
Сначала загрузите векторы word2vec.c в формате load_word2vec_format()
. Затем используйте model.init_sims(replace=True)
, чтобы принудительно выполнить нормализацию единицы, разрушительно на месте (сглаживание ненормированных векторов).
Затем сохраните модель в новом префиксе файла: model.save('GoogleNews-vectors-gensim-normed.bin``. (Обратите внимание, что на самом деле это создает несколько файлов на диске, которые необходимо хранить вместе для модель, подлежащая повторной загрузке.)
Теперь мы сделаем небольшую программу Python, которая служит для загрузки и переноса данных в памяти, и принудительно включите весь массив в память. Мы также хотим, чтобы эта программа зависала до тех пор, пока ее не закончили (сохраняя отображение живым), и будьте осторожны, чтобы не переучитывать уже нормированные векторы. Это требует еще одного трюка, потому что загруженные KeyedVectors на самом деле не знают, что векторы нормированы. (Обычно сохраняются только исходные векторы, а нормированные версии пересчитываются по мере необходимости.)
Примерно должно работать следующее:
from gensim.models import KeyedVectors
from threading import Semaphore
model = KeyedVectors.load('GoogleNews-vectors-gensim-normed.bin', mmap='r')
model.syn0norm = model.syn0 # prevent recalc of normed vectors
model.most_similar('stuff') # any word will do: just to page all in
Semaphore(0).acquire() # just hang until process killed
Это займет некоторое время, но нужно только один раз, до/вне любых веб-запросов. Пока процесс жив, векторы остаются в памяти. Кроме того, если/пока не будет другого давления в виртуальной памяти, векторы должны оставаться загруженными в память. Это важно для следующего.
Наконец, в вашем коде обработки веб-запроса вы можете просто сделать следующее:
model = KeyedVectors.load('GoogleNews-vectors-gensim-normed.bin', mmap='r')
model.syn0norm = model.syn0 # prevent recalc of normed vectors
# … plus whatever else you wanted to do with the model
Несколько процессов могут совместно использовать файлы с отображением только для чтения. (То есть, как только ОС узнает, что файл X находится в ОЗУ в определенной позиции, каждый другой процесс, который также хочет преобразовать версию X только для чтения, будет направлен на повторное использование этих данных в этой позиции.).
Таким образом, этот web-reqeust load()
и любые последующие обращения могут повторно использовать данные, которые предыдущий процесс уже внес в адресное пространство и активную память. Операции, требующие вычисления подобия по каждому вектору, по-прежнему занимают время для доступа к нескольким ГБ ОЗУ и выполняют вычисления/сортировку, но больше не потребуют дополнительного дискового ввода-вывода и избыточной повторной нормализации.
Если система сталкивается с другим давлением в памяти, диапазоны массива могут выпасть из памяти до тех пор, пока следующая прочитанная страница не вернет их обратно. И если машине не хватает ОЗУ для полной загрузки векторов, тогда для каждого сканирования потребуется смешивание пейджинга и выхода, а производительность будет разочаровывающим, неважно, что. (В таком случае: получите больше ОЗУ или работайте с меньшим набором векторов.)
Но если у вас достаточно ОЗУ, это приводит к тому, что исходный/естественный код загрузки и использования непосредственно "работает" довольно быстро, без дополнительного интерфейса веб-сервиса, поскольку машина разделяет файлы, отображаемые функции памяти как служебный интерфейс.