Python机器学习及实践——进阶篇6(超参数搜索)

Posted Lenskit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python机器学习及实践——进阶篇6(超参数搜索)相关的知识,希望对你有一定的参考价值。

前面所提到的模型配置,我们一般统称为模型的超参数,如K近邻算法中的K值 支持向量机中不同的和函数等。多数情况下,超参数的选择是无限的。因此在有限的时间内,除了可以验证人工预设几种超参数组合以外,也可以通过启发式的搜索方法对超参数组合进行调优。我们称这种启发式的超参数搜索方法为网格搜索。同时由于超参数的的验证过程之间彼此独立,因此为并行计算提供了可能。

网格搜索:
由于超参数的空间是无尽的,因此超参数的组合配置只能是“更优”解,没有最优解。通常情况下,我们依靠网格搜索对多种超参数组合的空间进行暴力搜索。每一套超参数组合被代入到学习函数中作新的模型,并且为了比较新模型之间的性能,每个模型都会采用交叉验证的方法在多组相同的训练和开发数据集下进行评估。请看下述代码:

# 从sklearn.datasets中导入20类新闻文本抓取器。
from sklearn.datasets import fetch_20newsgroups
# 导入numpy,并且重命名为np。
import numpy as np

# 使用新闻抓取器从互联网上下载所有数据,并且存储在变量news中。
news = fetch_20newsgroups(subset='all')

# 从sklearn.cross_validation导入train_test_split用来分割数据。
from sklearn.model_selection import train_test_split

# 对前3000条新闻文本进行数据分割,25%文本用于未来测试。
X_train, X_test, y_train, y_test = train_test_split(news.data[:3000], news.target[:3000], test_size=0.25, random_state=33)

# 导入支持向量机(分类)模型。
from sklearn.svm import SVC
# 导入TfidfVectorizer文本抽取器。
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入Pipeline。
from sklearn.pipeline import Pipeline

#使用Pipeline 简化系统搭建流程,将文本抽取与分类器模型串联起来。
clf = Pipeline([('vect', TfidfVectorizer(stop_words='english', analyzer='word')), ('svc', SVC())])

# 这里需要试验的2个超参数的的个数分别是4、3, svc__gamma的参数共有10^-2, 10^-1... 。这样我们一共有12种的超参数组合,12个不同参数下的模型。
parameters = 'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)

# 从sklearn.grid_search中导入网格搜索模块GridSearchCV。
from sklearn.model_selection import GridSearchCV

# 将12组参数组合以及初始化的Pipline包括3折交叉验证的要求全部告知GridSearchCV。请大家务必注意refit=True这样一个设定 。
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3)


# 执行单线程网格搜索。
%time _= gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

# 输出最佳模型在测试集上的准确性。
print (gs.score(X_test, y_test))
Fitting 3 folds for each of 12 candidates, totalling 36 fits
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.3s
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.2s
[CV] svc__C=0.1, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=0.01, total=   4.3s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.1s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.4s
[CV] svc__C=0.1, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=0.1, total=   4.4s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.2s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=0.1, svc__gamma=1.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.2s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.3s
[CV] svc__C=0.1, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=0.1, svc__gamma=10.0, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.01 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.2s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.3s
[CV] svc__C=1.0, svc__gamma=0.1 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=0.1, total=   4.3s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.3s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=1.0, svc__gamma=1.0 ......................................
[CV] ....................... svc__C=1.0, svc__gamma=1.0, total=   4.6s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=1.0, svc__gamma=10.0 .....................................
[CV] ...................... svc__C=1.0, svc__gamma=10.0, total=   4.5s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.2s
[CV] svc__C=10.0, svc__gamma=0.01 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=0.01, total=   4.3s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.2s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.4s
[CV] svc__C=10.0, svc__gamma=0.1 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=0.1, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=1.0 .....................................
[CV] ...................... svc__C=10.0, svc__gamma=1.0, total=   4.4s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.3s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.3s
[CV] svc__C=10.0, svc__gamma=10.0 ....................................
[CV] ..................... svc__C=10.0, svc__gamma=10.0, total=   4.4s
[Parallel(n_jobs=1)]: Done  36 out of  36 | elapsed:  2.6min finished
Wall time: 2min 43s
0.8226666666666667

上述代码的输出说明:使用单线程的网格搜索技术对朴素贝叶斯模型在文本分类任务中的超参数组合进行调优,共有12组超参数X3折交叉验证=36项独立运行的计算任务。该任务一共进行了3分23秒,寻找到的最佳超参数组合在测试集上所能达成的最高分类准确性为82.27%。

并行搜索:
尽管采用网格搜索结合交叉验证的方法,来寻找更好超参数组合的过程非常耗时;然而一旦获取比较好的超参数组合,则可以保持一段时间使用。因此这是值得推荐并且相对一劳永逸的性能提升方法。更可喜的是,由于各个新模型在执行交叉验证的过程中间是互相独立的,所以我们可以使用多核处理器甚至是分布式的计算资源来从事并行搜索,这样能够成倍地节省运算时间。我们对之前代码中的超参数搜索略作修改,看看会有怎样的效率提升。

# 从sklearn.datasets中导入20类新闻文本抓取器。
from sklearn.datasets import fetch_20newsgroups
# 导入numpy,并且重命名为np。
import numpy as np

# 使用新闻抓取器从互联网上下载所有数据,并且存储在变量news中。
news = fetch_20newsgroups(subset='all')

# 从sklearn.cross_validation导入train_test_split用来分割数据。
#from sklearn.cross_validation import train_test_split
from sklearn.model_selection import train_test_split

# 对前3000条新闻文本进行数据分割,25%文本用于未来测试。
X_train, X_test, y_train, y_test = train_test_split(news.data[:3000], news.target[:3000], test_size=0.25, random_state=33)

# 导入支持向量机(分类)模型。
from sklearn.svm import SVC

# 导入TfidfVectorizer文本抽取器。
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入Pipeline。
from sklearn.pipeline import Pipeline

#使用Pipeline 简化系统搭建流程,将文本抽取与分类器模型串联起来。
clf = Pipeline([('vect', TfidfVectorizer(stop_words='english', analyzer='word')), ('svc', SVC())])

# 这里需要试验的2个超参数的的个数分别是4、3, svc__gamma的参数共有10^-2, 10^-1... 。这样我们一共有12种的超参数组合,12个不同参数下的模型。
parameters = 'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)

# 从sklearn.grid_search中导入网格搜索模块GridSearchCV。
#from sklearn.grid_search import GridSearchCV
from sklearn.model_selection import GridSearchCV

# 初始化配置并行网格搜索,n_jobs=-1代表使用该计算机全部的CPU。
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3, n_jobs=-1)

# 执行多线程并行网格搜索。
%time _= gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

# 输出最佳模型在测试集上的准确性。
print (gs.score(X_test, y_test))
Fitting 3 folds for each of 12 candidates, totalling 36 fits
Wall time: 30.4 s
0.8226666666666667

同样是网格搜索,使用多线程并行搜索技术对朴素贝叶斯模型在文本分类任务中的超参数组合进行调优,执行同样的36项计算任务一共只花了30.4秒,寻找到的最佳超参数组合在测试集上所能达成的最高分类准确性依然为82.27%。我们发现在没有影响验证准确性的前提下,通过并行搜索基础有效地利用了6核心(cpu)的计算资源,几乎6倍地提升了运算速度,节省了最佳超参数组合的搜索时间。

以上是关于Python机器学习及实践——进阶篇6(超参数搜索)的主要内容,如果未能解决你的问题,请参考以下文章

Python机器学习及实践——进阶篇1(特征提升之特征抽取)

Python机器学习及实践——进阶篇1(特征提升之特征抽取)

Python机器学习及实践——进阶篇4(模型正则化之L1正则&L2正则)

Python机器学习及实践——进阶篇4(模型正则化之L1正则&L2正则)

Python机器学习及实践——进阶篇3(模型正则化之欠拟合与过拟合)

Python机器学习及实践——进阶篇3(模型正则化之欠拟合与过拟合)