我想以文本格式找到大型语料库中的二元语言。由于语料库无法立即加载到内存中,并且其行很大,因此我按块加载,每个块1 kb
def read_in_chunks(filename, chunk_size=1024):
"""Lazy function (generator) to read a file piece by piece.
Default chunk size: 1k."""
while True:
data = filename.read(chunk_size)
if not data:
break
yield data
然后,我想逐个遍历语料库并找到二元组,并使用gensim Phrases()和Phraser()函数,但是在训练过程中,我的模型不断失去状态。因此,我尝试在读取的每兆字节后保存并重新加载模型,然后释放内存,但是它仍然会丢失状态。我的代码在这里:
with open("./final/corpus.txt", "r", encoding='utf8') as r:
max_vocab_size=20000000
phrases = Phrases(max_vocab_size=max_vocab_size)
i=1
j=1024
sentences = ""
for piece in read_in_chunks(r):
if i<=j:
sentences = sentences + piece
else:
phrases.add_vocab(sentences)
phrases = Phrases(sentences)
phrases = phrases.save('./final/phrases.txt')
phrases = Phraser.load('./final/phrases.txt')
sentences = ""
j+=1024
i+=1
print("Done")
有什么建议吗? 谢谢。
答案 0 :(得分:1)
当你做两行时...
phrases.add_vocab(sentences)
phrases = Phrases(sentences)
...第二行删除了phrases
变量内的所有现有实例,并用全新的实例(Phrases(sentences)
代替了它。没有机会对单个实例进行附加调整。
其次,.save()
-then-immediate-re-.load()
的连续两行无法节省网络内存使用量。最好情况下,.load()
是不必要的,仅精确地复制刚刚.save()
d的内容,但是浪费大量时间和临时内存来加载第二个副本,然后丢弃已经在其中的副本phrases
将phrases
分配给新克隆。
虽然这些都是问题,但更普遍的是,问题在于您要做的事情不必这么复杂。
Phrases
类将接受一个可迭代的对象作为其sentences
的主体,其中每个项目都是一个字符串令牌列表。您不必担心块大小,也不必多次调用add_vocab()
–您可以提供一个对象,该对象本身依次提供每个项目,而Phrases
将做正确的事情。您要做必须担心将原始行分解为您要考虑的特定单词(“令牌化”)。
(对于大型语料库,您可能仍然会遇到与Phrases
试图计算的唯一单词数有关的内存问题。但是,无论大小如何,都没有关系项的数量是–因为一次只能查看一个。只有个唯一单词的累积会消耗运行内存。)
要很好地介绍可迭代对象在这种情况下的工作方式,好的博客文章是:
Data streaming in Python: generators, iterators, iterables
如果您的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
包中,但可以在其他地方使用。)