为啥训练我的朴素贝叶斯分类器会占用这么多内存?
Posted
技术标签:
【中文标题】为啥训练我的朴素贝叶斯分类器会占用这么多内存?【英文标题】:Why does training my Naive Bayes Classifier take so much memory?为什么训练我的朴素贝叶斯分类器会占用这么多内存? 【发布时间】:2020-05-31 16:10:33 【问题描述】:最近,我一直在做一个需要对 Twitter 数据进行情绪分析的项目。我正在使用 Textblob 库中的朴素贝叶斯分类器,并尝试使用 160 万条推文对其进行训练(如果有人想知道,可以在这里找到:https://www.kaggle.com/kazanova/sentiment140)。直接传入 160 万条推文会导致内存错误,因此我决定将其分块,以便一次只训练 1000 条推文。这取得了小小的成功,因为在我的计算机冻结之前,我只能在我的本地计算机上获得大约 10,000 条推文,因为我使用了太多的内存。然后我在 Google colab 上试用了它,这样我就可以在云中运行我的代码。使用 TPU 和 GPU,在会话崩溃并且我不得不重新启动运行时之前,我获得的最大推文也是 28,000 条。这是我的代码:
with open("shuffledlist.pickle", 'rb') as f: #Loading in my list of 1.6 million tweets
full_data = pickle.load(f)
training_data = (tweet for tweet in full_data[:1500000])
try:
with open("sentimentclassifier.pickle", "rb") as file: #makes a new classifier if one doesnt exist
classifier = pickle.load(file)
print("Got existing classifier")
except EOFError:
classifier = NaiveBayesClassifier(full_data[:1000])
print("Made new classifier")
del full_data
feeding_size = 1000
left_splice = 0
right_splice = feeding_size + left_splice
count = 0
new_start_time = time.time()
past_times = 0
while right_splice < 1500000:
loop_time = time.time()
data = itertools.islice(training_data,left_splice,right_splice)
try:
classifier.update(data)
except Exception:
print("Houston we got a problem")
with open("sentimentclassifier.pickle", "wb") as sentiment:
pickle.dump(classifier, sentiment, protocol = -1)
sys.exit("Yo it ended at and ".format(left_splice, right_splice))
past_times += time.time() - loop_time
count += 1
string = "Left: Right: . Took seconds. Total Time Elapsed: . Average Time for each: . Count: ."\
.format(left_splice, right_splice, time.time()-loop_time, time.time() - new_start_time, past_times/count, count)
sys.stdout.write('\r' + string)
left_splice += feeding_size
right_splice += feeding_size
with open("sentimentclassifier.pickle", "wb") as sentiment:
pickle.dump(classifier, sentiment, protocol = -1)
print("Done dumping cycle !".format(count))
print("Done! Right: , Left: !".format(left_splice, right_splice))
with open("sentimentclassifier.pickle", "wb") as sentiment:
pickle.dump(classifier, sentiment, protocol = -1)
print("Training took seconds!".format(time.time()-new_start_time))
一些注意事项:
由于我的主要问题是我的情绪分类器.pickle 文件有多大,我尝试使用 gzip,但是打开和关闭文件的时间太长了,这尤其糟糕,因为我需要打开文件每循环一次,因为我不想在程序崩溃时丢失任何进度。
我从使用列表切换到使用生成器,这确实显着提高了速度。
在 google colab 中,我尝试一次通过 10,000 个,这是最后的努力,不出所料,它没有达到最佳效果。
我不确定 nltk 的朴素贝叶斯分类器是否更有效,但我真的希望这是最后的手段,因为重新格式化我的推文列表可能需要几个小时。但如果它真的更有效,我会很乐意重做我的代码,如果这意味着我可以让它工作。
谢谢您,任何建议将不胜感激!
【问题讨论】:
【参考方案1】:我会尝试在单独的训练文件中将训练数据拆分为可管理的块。与其打开一个包含 150 万条推文的文件,不如将该文件拆分为每个文件几千条推文。循环训练一个文件,关闭该文件,然后训练下一个文件。这样一来,您就不会一次将太多内容加载到 ram 中。它必须以您的方式将全部 150 万条推文保存在内存中。这会让你的 RAM 陷入困境。
要明确:
这个:
with open("shuffledlist.pickle", 'rb') as f: #Loading in my list of 160 万推文 full_data = pickle.load(f)
>training_data = (tweet for tweet in full_data[:1500000])
正在将整个文件加载到 RAM 中。因此,在这条线之后进行分块并不会减少您正在使用的 ram 数量,尽管它会减少您正在使用的 GPU 核心数量,因为您每次迭代只提供 GPU x 数量。如果您首先加载较小的文件,您将从一开始就减少使用的 RAM 量。
【讨论】:
似乎阻碍我的 RAM 的主要因素是分类器本身,因为在大约 28,000 条推文之后,它变成了 3 GB。但我会尝试这个想法,因为它不会受到伤害。我会在我在家的时候尝试一下并更新你。 分类器在您的硬盘上。无需将整个文件加载到 ram 中,只是为了在每次运行时更新它。试着简单地把它放在这里......想象你有一个文本文件作为脚本运行的算法列表。比如,老式的机器学习。您创建规则以派生新算法,然后您想要更新算法文本文件。 Open("algorithms","a") as algorithms: 不会加载整个文本文件。它只是要打开它,然后当您写入它时,您只需添加其中的内容。 5 gigs 或 5kb,没关系。 这里是你想要做的事情的链接:medium.com/@mrgarg.rajat/… 哦,所以我以为我的分类器占用了内存,但它实际上是我的数据集?对数据集本身进行分块应该可以解决问题吗?我对此只有一个问题。那么为什么我的程序在前 1000 条推文中并不慢,但在 10,000 条之后它会冻结我的计算机? 如果左切片保持为零,则它加载到 gpu 中的数据集随着每次迭代而增加。也许我只是需要更多的咖啡......我不知道......但我没有看到左切片发生任何变化,而右切片随着每次运行而变得越来越高。您可以通过在每次运行时按提要大小增加左切片来解决此问题,但最终,将训练数据分块并以较小的批次运行对您的 RAM 和处理器更友好。以上是关于为啥训练我的朴素贝叶斯分类器会占用这么多内存?的主要内容,如果未能解决你的问题,请参考以下文章