【Python机器学习及实践】进阶篇:模型实用技巧(模型检验与超参数搜索)

 Python机器学习及实践——进阶篇:模型实用技巧

(模型检验与超参数搜索)


1.模型检验

在真正实践机器学习任务的时候,我们并不可能直到正确答案。这就要求我们充分利用现有数据,并且通常的做法依然是对现有数据进行采样分割:一部分用于模型参数训练,叫做训练集(Training set);另一部分数据集合用于调优模型配置和特征选择,并且对未知的测试性能做出评估,叫做开发集(Development set)或者验证集(Validation set)。

1.1留一验证

留一验证(Leave-one-out cross validation)就是从任务提供的数据中,随机采样一定比例作为训练集,剩下的"留做"验证。通常,这个比例为7:3,即70%作为训练集,30%作为验证集。但是,这一方法的模型性能不稳定,原因在于对验证集合随机采样的不确定性。

1.2交叉验证

交叉验证(K-fold cross-validation)可理解为多次留一验证的过程。需要强调的是,每次检验所使用的验证集之间是互斥的,并且要保证每一条可用数据都被模型验证过。以5折交叉验证(5-fold cross-validation)为例,全部可用数据被随机分割为平均数量的5组,每次迭代都选取其中的1组数据作为验证集,其他4组作为训练集。

交叉验证的好处在于,可以保证所有数据都有被训练和验证的机会,也尽最大可能让优化的模型性能表现得更加可信。

2.超参数搜索

前面提到的模型参数,一般统称为模型的超参数(Hyperparameters),如K近邻算法中的K值,SVM中的核函数等。多数情况先,超参数的选择是无限的。因此在有限的时间内,除了可以验证预设几种超参数组合以外,也可以通过启发式的搜索方式对超参数组合进行调优(网格搜索),同时由于超参数的验证过程之间彼此独立,因此为并行计算提供了可能(并行搜索)

2.1网格搜索

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

使用单线程对文本分类的朴素贝叶斯模型的超参数组合执行网格搜素

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File  : GridSearch.py
@Author: Xinzhe.Pang
@Date  : 2019/7/24 23:48
@Desc  : 
"""
import numpy as np
# 从sklearn.datasets中导入20类新闻文本抓取器
from sklearn.datasets import fetch_20newsgroups
# 分割数据集
from sklearn.model_selection import train_test_split
# 导入支持向量机分类模型
from sklearn.svm import SVC
# 导入TfidfVectorizer文本抽取器
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入Pipeline
from sklearn.pipeline import Pipeline
# 从sklearn.grid_search中导入网格搜索模块GridSearchCV
from sklearn.model_selection import GridSearchCV

# 使用新闻抓取器从互联网上下载所有数据
news = fetch_20newsgroups(subset='all')

# 对前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)
# 使用Pipline 简化系统搭建流程 将文本抽取与分类器模型串联起来
clf = Pipeline([('vect', TfidfVectorizer(stop_words='english', analyzer='word')), ('svc', SVC())])

# 超参数svc_gamma有4个 svc_C有3个 超参数组合一共有12种  使用np.logspace函数来选取超参数
parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)}
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3)

gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

print(gs.score(X_test, y_test))

在交叉验证获取最佳的超参数过程中,如果设定refit=True,那么程序将会以交叉训练集得到的最佳超参数,重新对所有可用的训练集和开发集进行,作为最终用于性能评估的最佳模型的参数。

2.2并行搜索

由于各个新模型在执行交叉验证的过程中间是相互独立的,所以可以充分利用多核处理器(Multicore processor)甚至是分布式计算资源来从事并行搜索(Parallel Grid Search),这样能够成倍地节省运算时间。

使用多个线程对文本分类的朴素贝叶斯模型的超参数组合执行并行化的网格搜索

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File  : ParallelGridSearch.py
@Author: Xinzhe.Pang
@Date  : 2019/7/25 0:39
@Desc  : 
"""
import numpy as np
# 从sklearn.datasets中导入20类新闻文本抓取器
from sklearn.datasets import fetch_20newsgroups
# 分割数据集
from sklearn.model_selection import train_test_split
# 导入支持向量机分类模型
from sklearn.svm import SVC
# 导入TfidfVectorizer文本抽取器
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入Pipeline
from sklearn.pipeline import Pipeline
# 从sklearn.grid_search中导入网格搜索模块GridSearchCV
from sklearn.model_selection import GridSearchCV

# 使用新闻抓取器从互联网上下载所有数据
news = fetch_20newsgroups(subset='all')

# 选取前3000条数据
X_train, X_test, y_train, y_test = train_test_split(news.data[:3000], news.target[:3000], test_size=0.25,
                                                    random_state=33)

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

# 超参数svc_gamma有4个 svc_C有3个 超参数组合一共有12种  使用np.logspace函数来选取超参数
parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)}
# 初始化配置并行网格搜索 n_jobs=-1代表使用该计算机的全部CPU
gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3, n_jobs=-1)

gs.fit(X_train, y_train)
gs.best_params_, gs.best_score_

print(gs.score(X_test, y_test))

报错:ImportError: [joblib] Attempting to do parallel computing without protecting your import on a system that does not support forking. To use parallel-computing in a script, you must protect your main loop using "if __name__ == '__main__'". Please see the joblib documentation on Parallel for more information

解决方法:

# 超参数svc_gamma有4个 svc_C有3个 超参数组合一共有12种  使用np.logspace函数来选取超参数
if __name__ == '__main__':
    parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)}
    # 初始化配置并行网格搜索 n_jobs=-1代表使用该计算机的全部CPU
    gs = GridSearchCV(clf, parameters, verbose=2, refit=True, cv=3, n_jobs=-1)
    gs.fit(X_train, y_train)
    gs.best_params_, gs.best_score_
    print(gs.score(X_test, y_test))

使用多线程并行搜索技术对朴素贝叶斯模型在文本分类任务中的超参数组合进行调优,可以有效地利用过核心计算机资源,节省了最佳超参数组合的搜索时间。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章