基于Gensim训练FastText模型的内存优化及逐句训练可行性问询
关于Gensim FastText大语料训练的疑问解答
我希望使用Python的gensim库训练FastText模型。首先需将每个句子分词为单词列表,再将这些列表存入最终的嵌套列表中,代码如下:
word_punctuation_tokenizer = nltk.WordPunctTokenizer() word_tokenized_corpus = [] for line in open('sentences.txt'): new = line.strip() new = word_punctuation_tokenizer.tokenize(new) if len(new) != 0: word_tokenized_corpus.append(new)随后按如下方式构建模型:
embedding_size = 60 window_size = 40 min_word = 5 down_sampling = 1e-2 ft_model = FastText(word_tokenized_corpus, size=embedding_size, window=window_size, min_count=min_word, sample=down_sampling, sg=1, iter=100)但word_tokenized_corpus中的句子数量极大,程序无法处理。我能否逐句传入分词后的句子训练模型,示例代码如下:
for line in open('sentences.txt'): new = line.strip() new = word_punctuation_tokenizer.tokenize(new) if len(new) != 0: ft_model = FastText(new, size=embedding_size, window=window_size, min_count=min_word, sample=down_sampling, sg=1, iter=100)这种方式会对最终结果产生差异吗?是否可不构建大列表、不占用过多内存来训练模型?
Hey there, let's break down your problem clearly:
首先,你的逐句训练方式完全不可行
每次循环你都重新初始化了一个全新的FastText模型,只用当前这一个句子去训练——这意味着之前所有语料的训练信息都会被彻底丢弃。最后你得到的模型只会学习到最后一个句子的内容,完全达不到训练整个语料的目的,和你想要的效果天差地别。
不过,内存友好的训练方式是存在的
Gensim本身就支持惰性迭代(也就是不用一次性加载所有数据到内存),下面给你两种高效的解决方案:
方案1:用生成器函数逐行返回分词结果
生成器是一种“用多少取多少”的迭代器,只会在训练需要的时候才处理当前行,不会把所有数据都存在内存里。你可以写一个简单的生成器函数:
from nltk import WordPunctTokenizer from gensim.models import FastText def tokenized_corpus_generator(file_path): tokenizer = WordPunctTokenizer() # 用with语句确保文件正确关闭 with open(file_path, 'r', encoding='utf-8') as f: for line in f: cleaned_line = line.strip() # 跳过空行 if not cleaned_line: continue tokens = tokenizer.tokenize(cleaned_line) if len(tokens) > 0: yield tokens # 初始化训练参数 embedding_size = 60 window_size = 40 min_word = 5 down_sampling = 1e-2 # 直接传入生成器训练模型 ft_model = FastText( tokenized_corpus_generator('sentences.txt'), size=embedding_size, window=window_size, min_count=min_word, sample=down_sampling, sg=1, iter=100 )
方案2:结合LineSentence(适合需要持久化分词结果的场景)
如果你需要把分词后的结果保存下来复用,也可以先把分词后的句子写入临时文件,再用Gensim的LineSentence类读取——它同样是惰性加载,不会占用大量内存:
# 第一步:先把分词后的内容写入临时文件 tokenizer = WordPunctTokenizer() with open('tokenized_sentences.txt', 'w', encoding='utf-8') as out_file: with open('sentences.txt', 'r', encoding='utf-8') as in_file: for line in in_file: cleaned_line = line.strip() if not cleaned_line: continue tokens = tokenizer.tokenize(cleaned_line) if len(tokens) > 0: out_file.write(' '.join(tokens) + '\n') # 第二步:用LineSentence读取并训练 from gensim.models.word2vec import LineSentence from gensim.models import FastText ft_model = FastText( LineSentence('tokenized_sentences.txt'), size=embedding_size, window=window_size, min_count=min_word, sample=down_sampling, sg=1, iter=100 )
额外说明
- 这两种方案的训练效果和把所有数据加载到大列表里完全一致(只要固定随机种子,结果几乎无差异),因为Gensim的模型训练本来就是迭代处理语料的。
- 生成器方案更省空间,不需要额外保存分词后的文件,适合一次性训练的场景;
LineSentence方案适合需要重复使用分词后语料的情况。
内容的提问来源于stack exchange,提问作者user14251114
相关产品推荐
相关产品推荐

