我目前正在尝试使用Python和Scikit-learn来构build一些文本分类工具。
我的文字不是英文的,因此,不会受到分解或其他基于英语的维度降低的惯常处理。
因此,TfIdfmatrix变得相当大(150,000×150,000)它可以使用普通的PC进行处理,但是对它们进行网格search会太多,所以我通过Amazon Web Service的帮助来运行网格search。 (我的参数设置也很大)
这是我的代码:
在主机上运行我的Intellij IDE,我需要ZeroMQ来与来宾的后端应用进行通信
Linux ARM上的程序寄存器和堆栈的初始状态
什么是常用的库在Linux上编写OpenGL 4.X应用程序?
上下文切换在Linux中需要多长时间?
# 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','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,'vec__binary': (True,'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个左右)。
我试图改变
n_job
参数以不同的数字(8,32,128)与相同的结果。 (但是我认为这个脚本试图按照指示运行尽可能多的工作,因为当我终止这个过程时,我会看到类似于……“Process ForkPoolWorker-30:”和它们的回溯鞭打过屏幕)
使用ps x -C python3.4命令进行进一步检查可以得出只有8个python进程正在运行。 我推断这可能是从Python或操作系统的某种限制(我使用t2.micro实例构build我的AMI,它没有太多的核心)所以,我决定重新从头开始重build我的环境,包括编译Python使用c3.4xlarge,并将操作系统更改为Amazon Linux(我认为Fedora的一个分支),以便与硬件更好地兼容。
但是,我的脚本仍然没有超过8个核心。 最后,使用Scikit-learn网站的演示文本分类代码: http ://scikit-learn.org/stable/auto_examples/grid_search_text_feature_extraction.html(使用SGDClassifier代替MultinomialNB)它可以与所有32个核心完美的运行!
所以…也许,与网格searchalgorithm和朴素贝叶斯分类器有关?
我正在考虑提交一个bug,但是想知道这是否是Naive Bayes的预期行为,或者如果我的代码出错了?
更新
我无法find一种方法来testing内存带宽是否是直接的罪魁祸首。 但是我尝试用各种方式来计算我的并行代码和cpu使用情况,以确定瓶颈的确切位置。
实验1:只进行vector化和转换。
使用我的真实数据作为input(150,000文本文档;每个包含大约130个字)
参数空间大约是400。
multithreading是由Joblib完成的(与Scikit-learn使用的模块相同)。 我有:
使用8个线程:在841.017783164978 s完成,使用24.636999999999993%的cpu。
使用16个线程:在842.9525656700134中完成,使用24.700749999999985%的cpu。
使用全部32个线程:在857.024197101593中完成,使用24.242250000000013%的cpu。
结果清楚地表明,随着处理能力的增加,vector化过程不能成比例。
实验2:这次我只对预vector化数据执行MultinomialNB。
使用约400的参数空间,我得到了:
使用8个线程:完成2102.0565922260284秒,使用25.486000000000054%的cpu。
使用16个线程:在1385.6887295246124s完成,使用49.83674999999993%的cpu。
使用全部32个线程:在1319.416403055191s完成,使用89.90074999999997%的cpu。
从8个线程到16个线程的转换显示了巨大的改进。 但是,随着线程数量增加到32个,总体完成时间只会略微缩短,而cpu使用率则会大幅增加。 这一点我不太明白。
实验3:我将这两个过程结合在一起。
使用8个线程:完成3385.3253166675568秒,使用25.68999999999995%的cpu。
使用16个线程:在2066.499200105667s完成,使用49.359249999999996%的cpu。
使用全部32个线程:在2018.8800330162048 s完成,使用54.55375000000004%的cpu。
从我自己的并行代码和gridsearchcv获得的时间之间有一些差异,但这可能是因为我在代码中完成的简化(我没有进行交叉validation或全参数迭代Gridsearch)
结论
从我的testing中,我得出这样的结论。 (如果我错了,请纠正我)
vector化阶段使用内存更encryption集; 因此最有可能使带宽饱和。 这可以从完成时间和cpu利用率观察到,它遇到了某种瓶颈,并没有规模。 但是,这是一个相对较快的过程。 (因为所有数据都存储在RAM上,所以消除了IO限制,在这段时间内存使用量约为30%)
MultinomialNB使用比vector化器更less的内存; 大部分的计算似乎是在核心处理。 因此,它可以比vector化器(8> 16)更好地缩放,但是之后它也会碰到某种瓶颈,MultinomialNB比vector化器需要更多的时间。
在将两个进程结合在一起时,完成时间performance出与MultinomialNB相同的趋势,因为在我看来,内存带宽可能是向量化阶段的瓶颈,但与MultinomialNB相比这个阶段相对较短。 因此,如果并发任务数量less,则可以同时进行这两个阶段,而不会使带宽饱和,但是当进程数量足够多时,会有足够数量的并发进程执行vector化来饱和带宽; 从而迫使操作系统减less运行过程。 (解释一下我之前发现的运行python的进程只有8-9)
我不是很确定,但我认为SGDClassifier可以使用100%cpu的原因是SGDClassifier比MultinomialNB有更长的核心处理时间。 因此,在每次迭代中,大部分时间都用于内核计算SGDClassifier,而不是进行vector化,并且SGDClassifier需要很长时间来计算的事实减less了许多工人同时进入vector化阶段的机会(如每个vector化任务相对较短但内存密集)
我想现在我最好的select是去集群计算。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。