我目前正在尝试使用Python和Scikit-learn构建一些文本分类工具。
我的文字不是英文的,因此,不受通常的干分解或其他基于英语的维度减少的处理。
因此,TfIdf矩阵变得非常大(150,000x150,000)它可以使用常规PC进行处理,但对它们运行网格搜索会太多,所以我获得了Amazon Web Service的帮助来运行网格搜索。 (我的参数设置也很大)
这是我的代码:
# coding: utf-8
import os, json, codecs, nltk
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer,TfidfTransformer
from sklearn.grid_search import GridSearchCV
from time import time
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
print("Importing dataset...")
with open('y_data.json','r') as fp:
y = json.load(fp)
with open('dataset.json','r') as fp:
dataset = json.load(fp)
print("Importing stop words...")
with codecs.open('stopword.txt','r','utf-8') as fp:
stopword = []
for w in fp:
stopword.append(w.strip())
light_st = set(stopword)
with codecs.open('st_data.txt','r','cp874') as fp:
for w in fp:
stopword.append(w.strip())
heavy_st = set(stopword)
def pre_process_1(text):
return text.replace("|"," ")
def tokenize_1(text):
return text.split()
pipeline = Pipeline([('vec', CountVectorizer(encoding='cp874', preprocessor=pre_process_1, tokenizer=tokenize_1, stop_words=heavy_st, token_pattern=None)),('tfidf', TfidfTransformer()), ('clf', MultinomialNB())])
parameters = {
'vec__max_df': (0.5, 0.625, 0.75, 0.875, 1.0),
'vec__max_features': (None, 5000, 10000, 20000),
'vec__min_df': (1, 5, 10, 20, 50),
'tfidf__use_idf': (True, False),
'tfidf__sublinear_tf': (True, False),
'vec__binary': (True, False),
'tfidf__norm': ('l1', 'l2'),
'clf__alpha': (1, 0.1, 0.01, 0.001, 0.0001, 0.00001)
}
if __name__ == "__main__":
grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=2)
t0 = time()
grid_search.fit(dataset, y)
print("done in {0}s".format(time() - t0))
print("Best score: {0}".format(grid_search.best_score_))
print("Best parameters set:")
best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(list(parameters.keys())):
print("\t{0}: {1}".format(param_name, best_parameters[param_name]))
以下是我的软件环境的详细信息:
Python3.4.2
scikit-learn 0.15.2(随Pip一起安装)
Ubuntu Server14.04 LTS,64位(使用HVM)
尝试使用ec2 r3.8xlarge实例
首先,我使用一个更小的实例(r3.2xlarge; 8个核心)运行我的模型,但从计算中发现它需要相当长的时间(2天)。所以,我决定扩大我的机器并使用最大的实例(我使用r3,因为我的脚本非常耗费内存);然而,它并没有像我想象的那样快速地处理。
当我试图监控CPU负载时(观察-n 5正常运行时间)......我发现即使我让它运行一段时间,平均CPU负载也不会超过9。 (据我所知,32个核心机器在完全利用其所有核心时,应该大约为32个。)
我尝试过更改
n_job
具有相同结果的各种数字(8,32,128)的参数。 (但是我认为脚本会尝试按照指示运行多个作业,因为当我终止进程时,我会看到类似......" Process ForkPoolWorker-30:"并且他们的回溯超过了屏幕)
使用ps x -C python3.4命令进一步检查产生的只有8个python进程正在运行。我推断这可能是python或操作系统的一些限制(我使用t2.micro实例构建我的AMI,它没有很多内核)所以,我决定重做我从头开始重建环境的工作,包括使用c3.4xlarge编译Python,并将操作系统更改为Amazon Linux(我认为是Fedora的一个分支),以便更好地兼容硬件。
但是,我的脚本仍然没有超过8个核心。 最后,使用Scikit-learn网站上的演示文本分类代码:http://scikit-learn.org/stable/auto_examples/grid_search_text_feature_extraction.html (它使用SGDClassifier而不是MultinomialNB)它可以与所有32个核心完美运行!
那么......也许,与网格搜索算法和朴素贝叶斯分类器有关?
我正在考虑提交一个错误,但首先想知道这是Naive Bayes的预期行为,还是我的代码出错?
我无法找到一种方法来测试内存带宽是否直接成为罪魁祸首。但我尝试以各种方式计算并行代码和CPU使用情况,以找出确实存在瓶颈的地方。
使用我的真实数据作为输入(150,000个文本文档;每个包含大约130个单词)
参数空间约为400
多线程由Joblib(Scikit-learn使用的相同模块)完成。我得到了:
使用8个线程:在841.017783164978 s中完成并使用24.636999999999993%的CPU。
使用16个线程:在842.9525656700134 s中完成并使用24.700749999999985%的CPU。
使用全部32个线程:在857.024197101593 s中完成并使用24.242250000000013%的CPU。
结果清楚地表明,随着处理能力的增加,矢量化过程无法扩展。
像以前一样使用大约400的参数空间,我得到了:
使用8个线程:在2102.0565922260284 s中完成并使用25.486000000000054%的CPU。
使用16个线程:在1385.6887295246124 s中完成并使用49.83674999999993%的CPU。
使用全部32个线程:在1319.416403055191中完成并使用89.90074999999997%的CPU。
从8个线程到16个线程的转换显示出巨大的改进。但是,随着线程数增加到32,完成总时间只会略微缩短,而CPU使用率会大幅增加。这一点我不太明白。
使用8个线程:在3385.3253166675568 s中完成并使用25.68999999999995%的CPU。
使用16个线程:在2066.499200105667 s中完成并使用49.359249999999996%的CPU。
使用全部32个线程:在2018.8800330162048 s中完成并使用54.55375000000004%的CPU。
我从我自己的并行代码和GridsearchCV的代码之间存在一些差异,但这可能是因为我在代码中完成的简化(我不是像在Gridsearch中那样进行交叉验证或完整参数迭代)
从我的测试中,我得出结论。 (如果我错了,请纠正我)
我认为我现在最好的选择是进行集群计算。 :)
答案 0 :(得分:4)
看起来你的工作都受内存限制。
Naive Bayes是一个非常简单的模型,其训练算法由单个(稀疏)矩阵乘法和几个和组成。类似地,tf-idf计算起来非常简单:它对输入求和,计算几个日志,并存储结果。
事实上,NB是所以简单,这个程序的瓶颈几乎肯定在CountVectorizer
,它会多次转换内存中的数据结构,直到它的所有术语计数都被填入进入正确的矩阵格式。如果你并行地做很多事情,你可能会遇到内存带宽瓶颈。
(这是所有受过教育的猜测,但它是基于我参与scikit-learn开发。我是MultinomialNB
的作者之一,也是许多遭遇黑客攻击的人之一在CountVectorizer
加快速度。)