Когда вы делаете две строки ...
phrases.add_vocab(sentences)
phrases = Phrases(sentences)
... эта вторая строка отбрасывает любой существующий экземпляр внутри переменной phrases
и заменяет его новым экземпляром (Phrases(sentences)
). Там нет шансов для аддитивной корректировки в единственном экземпляре.
Во-вторых, две последовательные строки .save()
-then-instant-re- .load()
не могут спасти использование памяти. В лучшем случае .load()
будет ненужным, только точно воспроизводя то, что было просто .save()
d, но тратя много времени и временной памяти, загружая вторую копию, а затем отбрасывая дубликат, который уже был в phrases
, для назначить phrases
новому клону.
Хотя это проблемы, в более общем плане, проблема в том, что то, что вам нужно сделать, не должно быть таким сложным.
Класс Phrases
примет в качестве корпуса sentences
итеративный объект, каждый элемент которого представляет собой список строк-токенов. Вам не нужно беспокоиться о размерах куска и многократном вызове add_vocab()
- вы можете просто предоставить один объект, который сам предлагает каждый элемент по очереди, и Phrases
будет делать правильные вещи. Вы do должны беспокоиться о разбивке необработанных строк на конкретные слова, которые вы хотите рассмотреть («токенизация»).
(Для большого корпуса вы все равно можете столкнуться с проблемами памяти, связанными с количеством уникальных слов, которые Phrases
пытается сосчитать. Но не имеет значения, насколько произвольно велико число элементы - потому что он будет смотреть только по одному за раз. Только накопление уникальных слов будет занимать оперативную память.)
Для хорошего представления о том, как итеративный объект может работать в таких ситуациях, хороший пост в блоге:
Поток данных в Python: генераторы, итераторы, итерируемые
Если ваш файл corpus.txt
уже настроен на одно предложение разумного размера на строку и все слова уже разделены простыми пробелами, то итеративный класс может быть таким простым:
class FileByLineIterable(object):
def __init__(self, filename):
self.filename = filename
def __iter__(self):
with open(self.filename, 'r', encoding='utf8') as src:
for line in src.readlines():
yield line.split()
Тогда ваш код может быть таким же простым, как ...
sentences = FileByLineIterable('./final/corpus.txt')
phrases = Phrases(sentences, max_vocab_size=max_vocab_size)
... потому что класс Phrases
получает то, что он хочет - корпус, который предлагает посредством итерации только один элемент списка слов за раз.
Примечание:
вы можете включить ведение журнала на уровне INFO для отслеживания прогресса и отслеживания любых признаков того, что что-то идет не так
есть немного более продвинутый построчный итератор, который также ограничивает текст одной строки не более чем 10 000 токенов (чтобы соответствовать внутреннему пределу реализации gensim
Word2Vec
) и открывает файлы из мест, отличных от локальных путей к файлам, доступно по gensim.models.word2vec.LineSentence
См:
https://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.LineSentence
(Несмотря на то, что он упакован в пакет word2vec
, его можно использовать в другом месте.)