• ML-sklearn参数随机优化:GridSearchCV、RandomizedSearchCV、hyperopt


    目录

    1 GridSearchCV:网格式暴力搜索

    2.RandomizedSearchCV:采样式搜索

    3.hyperopt:贝叶斯优化

    总结


    全都在:sklearn.model_selection里面https://scikit-learn.org/stable/modules/classes.html#hyper-parameter-optimizers

    1 GridSearchCV:网格式暴力搜索

    sklearn模块的GridSearchCV模块,可以在指定范围内自动搜索具有不同超参数的不同模型组合。很暴力,数据量大的时候计算量极大,这是不适合用。

    包:from sklearn.model_selection import GridSearchCV,API:GridSearchCV

    参数:GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score=True)

    estimator :即我们的模型

    param_grid:即我们要调参的参数列表。 比如我们用SVC分类模型的话,那么param_grid可以定义为{"C":[0.1, 1, 10], "gamma": [0.1, 0.2, 0.3]},这样我们就会有9种超参数的组合来进行网格搜索,选择一个拟合分数最好的超平面系数。

    scoring :准确度评价标准,默认None,这时需要使用score函数。需要其函数名形如:scorer(estimator, X, y);如果是None,则使用estimator的误差估计函数。

    n_jobs:并行运行的作业数。默认1。-1表示使用所有处理器。

    iid:默认True,为True时,默认为各个样本误差估计为所有样本之和,而非各个加权的平均。

    refit :默认为True,程序将会以交叉验证训练集得到的最佳参数

    cv: S折交叉验证的折数,即将训练集分成多少份来进行交叉验证。默认是3,。如果样本较多的话,可以适度增大cv的值。

    pre_dispatch:指定总共分发的并行任务数。当n_jobs大于1时,数据将在每个运行点进行复制,这可能导致OOM。

    例:

    from sklearn.model_selection import GridSearchCV
    from sklearn import datasets, svm
    from sklearn.svm import SVC
    from sklearn.datasets import make_moons, make_circles, make_classification
    from sklearn.preprocessing import StandardScaler
    
    
    seed = 1
    X, y = make_circles(noise=0.2, factor=0.5, random_state=seed)
    
    X = StandardScaler().fit_transform(X)
    
    grid = GridSearchCV(SVC(), param_grid={"C": [0.1, 1, 10], "gamma": [1, 0.1, 0.01]}, cv=4)
    grid.fit(X, y)
    
    # print('网格搜索-度量记录:', grid.cv_results_)  # 包含每次训练的相关信息的DataFrame
    print('网格搜索-最佳度量值:', grid.best_score_)  # 获取最佳度量值。Not available if refit=False.
    print('网格搜索-最佳参数:', grid.best_params_)  # 获取最佳度量值时的代定参数的值。是一个字典。Not available if refit=False.
    print('网格搜索-最佳模型:', grid.best_estimator_)  # 获取最佳度量时的分类器模型,Not available if refit=False.
    print('网格搜索-交叉验证分割数 :', grid.n_splits_)
    # print('网格搜索-在整个数据集交叉验证最佳模型时间:', grid.refit_time_)  # only if refit is not False
    
    #
    网格搜索-最佳度量值: 0.91
    网格搜索-最佳参数: {'C': 10, 'gamma': 0.1}
    网格搜索-最佳模型: SVC(C=10, cache_size=200, class_weight=None, coef0=0.0,
      decision_function_shape='ovr', degree=3, gamma=0.1, kernel='rbf',
      max_iter=-1, probability=False, random_state=None, shrinking=True,
      tol=0.001, verbose=False)
    网格搜索-交叉验证分割数 : 4

    2.RandomizedSearchCV:采样式搜索

    sklearn模块的RandomizedSearchCV模块实现了参数的随机搜索,对于每个参数, 可以指定在可能值上的分布或离散选择的列表

    当你的调节参数是连续的,比如回归问题的正则化参数,有必要指定一个连续分布而不是可能值的列表,这样RandomizeSearchCV就可以执行更好的grid search。

    RandomizedSearchCV的使用方法其实是和GridSearchCV一致的,但它以随机在参数空间中采样的方式代替了GridSearchCV对于参数的网格搜索,在对于有连续变量的参数时,RandomizedSearchCV会将其当作一个分布进行采样这是网格搜索做不到的,它的搜索能力取决于设定的n_iter参数(数值越大,获得的参数精度越大,但是搜索时间越长)。

    位于:sklearn.model_selection.RandomizedSearchCV    API:RandomizedSearchCV

    cv_results_:给出不同参数情况下的评价结果的记录

    best_params_:描述了已取得最佳结果的参数的组合

    best_score_:成员提供优化过程期间观察到的最好的评分

    from sklearn.model_selection import RandomizedSearchCV
    from sklearn import datasets, svm
    import numpy as np
    from sklearn.svm import SVC
    from sklearn.datasets import make_moons, make_circles, make_classification
    from sklearn.preprocessing import StandardScaler
    
    seed = 1
    X, y = make_circles(noise=0.2, factor=0.5, random_state=seed)
    
    X = StandardScaler().fit_transform(X)
    
    param_dist = {'C': np.linspace(0.1, 10, 10),
                  'gamma': np.linspace(1, 0.01, 10)
                  }
    
    grid = RandomizedSearchCV(SVC(), param_distributions=param_dist, cv=4)
    grid.fit(X, y)
    
    # refit:是否开启交叉验证估计参数,默认True
    # print('随机搜索-度量记录:', grid.cv_results_)  # 包含每次训练的相关信息的DataFrame
    print('随机搜索-最佳度量值:', grid.best_score_)  # 获取最佳度量值。Not available if refit=False.
    print('随机搜索-最佳参数:', grid.best_params_)  # 获取最佳度量值时的代定参数的值。是一个字典。Not available if refit=False.
    print('随机搜索-最佳模型:', grid.best_estimator_)  # 获取最佳度量时的分类器模型,Not available if refit=False.
    print('随机搜索-交叉验证分割数 :', grid.n_splits_)
    # print('随机搜索-aaaa:', grid.refit_time_)  # only if refit is not False
    
    #
    随机搜索-最佳度量值: 0.91
    随机搜索-最佳参数: {'gamma': 0.22999999999999998, 'C': 2.3000000000000003}
    随机搜索-最佳模型: SVC(C=2.3000000000000003, cache_size=200, class_weight=None, coef0=0.0,
      decision_function_shape='ovr', degree=3, gamma=0.22999999999999998,
      kernel='rbf', max_iter=-1, probability=False, random_state=None,
      shrinking=True, tol=0.001, verbose=False)
    随机搜索-交叉验证分割数 : 4
    

    参考:https://blog.csdn.net/juezhanangle/article/details/80051256

    https://blog.csdn.net/luanpeng825485697/article/details/79831703

     


    3.hyperopt:贝叶斯优化

    Github:https://github.com/hyperopt/hyperopt

    Document:https://hyperopt.github.io/hyperopt/

    安装:sudo pip install hyperopt、sudo pip install calibration、还需要安装pymongo

    介绍:

    3.1.构造目标函数

    假设你有一个定义在某个范围内的函数,并且想把它最小化。也就是说,你想找到产生最低输出值的输入值。下面的简单例子找到x的值用于最小化线性函数y(x) = x,可以这样实现:

    from hyperopt import fmin, tpe, hp
    best = fmin(
        fn=lambda x: x,
        space=hp.uniform('x', 0, 1),
        algo=tpe.suggest,
        max_evals=100)
    print best

    函数fmin接受一个函数来最小化,记为fn,在这里用一个匿名函数lambda x: x来创建函数。该函数可以是任何有效的值返回函数,例如回归中的平均绝对误差。

    下一个参数指定搜索空间,在本例中,它是0到1之间的连续数字范围,由hp.uniform('x', 0, 1)指定。hp.uniform是一个内置的hyperopt函数,它有三个参数:名称x,范围的下限和上限01

    algo参数指定搜索算法,本例中tpe表示 tree of Parzen estimators。该主题超出了本文的范围,但有数学背景的读者可以细读这篇文章。algo参数也可以设置为hyperopt.random,但是这里我们没有涉及,因为它是众所周知的搜索策略

    最后,指定fmin函数将执行的最大评估次数max_evals。这个fmin函数将返回一个python字典

    结果:上述函数的一个输出示例是{'x': 0.000269455723739237}

    二次方程:

    best = fmin(
        fn=lambda x: (x-1)**2,
        space=hp.uniform('x', -2, 2),
        algo=tpe.suggest,
        max_evals=100)
    print best
    
    #{'x': 0.997369045274755}

    最大化:把最大化函数加负号变成最小化,得出来的坐标就是原函数最大化坐标。

    3.2搜索空间

    hyperopt模块包含一些方便的函数来指定输入参数的范围。我们已经见过hp.uniform。最初,这些是随机搜索空间,但随着hyperopt更多的学习(因为它从目标函数获得更多反馈),通过它认为提供给它最有意义的反馈,会调整并采样初始搜索空间的不同部分。

    以下内容将在本文中使用:

    1. hp.choice(label, options) 其中options应是 python 列表或元组。
    2. hp.normal(label, mu, sigma) 其中musigma分别是均值和标准差。
    3. hp.uniform(label, low, high) 其中lowhigh是范围的下限和上限。

    其他也是可用的,hp.lognormalhp.quniform。

    import hyperopt.pyll.stochastic
    
    space = {
        'x': hp.uniform('x', 0, 1),
        'y': hp.normal('y', 0, 1),
        'name': hp.choice('name', ['alice', 'bob']),
    }
    
    print hyperopt.pyll.stochastic.sample(space)
    
    #随机的采样出一个结果
    #{'y': -1.4012610048810574, 'x': 0.7258615424906184, 'name': 'alice'}
    

    3.3 捕获信息 

    如果能看到hyperopt黑匣子内发生了什么是极好的。Trials对象使我们能够做到这一点。我们只需要导入一些东西。

    STATUS_OKTrialsTrials对象允许我们在每个时间步存储信息。然后我们可以将它们打印出来,并在给定的时间步查看给定参数的函数评估值。

    from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
    
    fspace = {
        'x': hp.uniform('x', -5, 5)
    }
    
    def f(params):
        x = params['x']
        val = x**2
        return {'loss': val, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(fn=f, space=fspace, algo=tpe.suggest, max_evals=50, trials=trials)
    
    print('best:', best)
    print('trials:')
    for trial in trials.trials[:2]:#打印前2个信息
        print trial
    
    #
    best: {'x': 0.014420181637303776}
    trials:
    {'refresh_time': None, 'book_time': None, 'misc': {'tid': 0, 'idxs': {'x': [0]}, 'cmd': ('domain_attachment', 'FMinIter_Domain'), 'vals': {'x': [1.9646918559786162]}, 'workdir': None}, 'state': 2, 'tid': 0, 'exp_key': None, 'version': 0, 'result': {'status': 'ok', 'loss': 3.8600140889486996}, 'owner': None, 'spec': None}
    {'refresh_time': None, 'book_time': None, 'misc': {'tid': 1, 'idxs': {'x': [1]}, 'cmd': ('domain_attachment', 'FMinIter_Domain'), 'vals': {'x': [-3.9393509404526728]}, 'workdir': None}, 'state': 2, 'tid': 1, 'exp_key': None, 'version': 0, 'result': {'status': 'ok', 'loss': 15.518485832045357}, 'owner': None, 'spec': None}

    Trials对象将数据存储为BSON对象,其工作方式与JSON对象相同。BSON来自pymongo模块。我们不会在这里讨论细节,这是对于需要使用MongoDB进行分布式计算的hyperopt的高级选项,因此需要导入pymongo。回到上面的输出。tid是时间 id,即时间步,其值从0到max_evals-1。它随着迭代次数递增。'x'是键'vals'的值,其中存储的是每次迭代参数的值。'loss'是键'result'的值,其给出了该次迭代目标函数的值。

    3.4可视化

    这里讨论两种类型的可视化:x时间与y值,x值与y损失。

    时间与值:

    f, ax = plt.subplots(1)
    xs = [t['tid'] for t in trials.trials]
    ys = [t['misc']['vals']['x'] for t in trials.trials]
    ax.set_xlim(xs[0]-10, xs[-1]+10)
    ax.scatter(xs, ys, s=20, linewidth=0.01, alpha=0.75)
    ax.set_title('$x$ $vs$ $t$ ', fontsize=18)
    ax.set_xlabel('$t$', fontsize=16)
    ax.set_ylabel('$x$', fontsize=16)

     值与损失:

    f, ax = plt.subplots(1)
    xs = [t['misc']['vals']['x'] for t in trials.trials]
    ys = [t['result']['loss'] for t in trials.trials]
    ax.scatter(xs, ys, s=20, linewidth=0.01, alpha=0.75)
    ax.set_title('$val$ $vs$ $x$ ', fontsize=18)
    ax.set_xlabel('$x$', fontsize=16)
    ax.set_ylabel('$val$', fontsize=16)

    3.5Iris 数据集

    将介绍4个使用hyperopt在经典数据集 Iris 上调参的完整示例。 K 近邻(KNN),支持向量机(SVM),决策树和随机森林。由于我们试图最大化交叉验证的准确率,而hyperopt只知道如何最小化函数,所以必须对准确率取负

    1)hyperopt来找到 K近邻(KNN)机器学习模型的最佳参数

    插曲:(**params可以把字典对象当作参数传入)

    1和2等价
    1:
    pr = {'n_neighbors': 15, 'weights': 'distance'}
    clf = neighbors.KNeighborsClassifier(**pr)
    2:
    clf = neighbors.KNeighborsClassifier(n_neighbors=15, weights='distance')
    from sklearn import datasets
    iris = datasets.load_iris()
    X = iris.data
    y = iris.target
    
    def hyperopt_train_test(params):
        clf = KNeighborsClassifier(**params)
        return cross_val_score(clf, X, y).mean()#返回的是交叉验证的均值,越大越好
    
    space4knn = {
        'n_neighbors': hp.choice('n_neighbors', range(1,50))#k的个数
    }
    
    def f(params):
        acc = hyperopt_train_test(params)#计算训练结果准确性,返回-acc最小化
        return {'loss': -acc, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(f, space4knn, algo=tpe.suggest, max_evals=100, trials=trials)
    print 'best:'
    print best

    可以打印显示:

    f, ax = plt.subplots(1)#, figsize=(10,10))
    xs = [t['misc']['vals']['n'] for t in trials.trials]
    #加-,转回准确率
    ys = [-t['result']['loss'] for t in trials.trials]
    ax.scatter(xs, ys, s=20, linewidth=0.01, alpha=0.5)
    ax.set_title('Iris Dataset - KNN', fontsize=18)
    ax.set_xlabel('n_neighbors', fontsize=12)
    ax.set_ylabel('cross validation accuracy', fontsize=12)

    迭代中判断,可以对params参数字典进行判断,在优化目标函数中依据判断进行动态调整计算。如这个,根据标准化和缩放关键字判断,对X进行处理:

    # now with scaling as an option
    from sklearn import datasets
    iris = datasets.load_iris()
    X = iris.data
    y = iris.target
    
    def hyperopt_train_test(params):
        X_ = X[:]
    
        if 'normalize' in params:
            if params['normalize'] == 1:
                X_ = normalize(X_)
                del params['normalize']
    
        if 'scale' in params:
            if params['scale'] == 1:
                X_ = scale(X_)
                del params['scale']
    
        clf = KNeighborsClassifier(**params)
        return cross_val_score(clf, X_, y).mean()
    
    space4knn = {
        'n_neighbors': hp.choice('n_neighbors', range(1,50)),
        'scale': hp.choice('scale', [0, 1]),
        'normalize': hp.choice('normalize', [0, 1])
    }
    
    def f(params):
        acc = hyperopt_train_test(params)
        return {'loss': -acc, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(f, space4knn, algo=tpe.suggest, max_evals=100, trials=trials)
    print 'best:'
    print best

    2)支持向量机(SVM)

    iris = datasets.load_iris()
    X = iris.data
    y = iris.target
    
    def hyperopt_train_test(params):
        X_ = X[:]
    
        if 'normalize' in params:
            if params['normalize'] == 1:
                X_ = normalize(X_)
                del params['normalize']
    
        if 'scale' in params:
            if params['scale'] == 1:
                X_ = scale(X_)
                del params['scale']
    
        clf = SVC(**params)
        return cross_val_score(clf, X_, y).mean()
    
    space4svm = {
        'C': hp.uniform('C', 0, 20),
        'kernel': hp.choice('kernel', ['linear', 'sigmoid', 'poly', 'rbf']),
        'gamma': hp.uniform('gamma', 0, 20),
        'scale': hp.choice('scale', [0, 1]),
        'normalize': hp.choice('normalize', [0, 1])
    }
    
    def f(params):
        acc = hyperopt_train_test(params)
        return {'loss': -acc, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(f, space4svm, algo=tpe.suggest, max_evals=100, trials=trials)
    print 'best:'
    print best
    
    parameters = ['C', 'kernel', 'gamma', 'scale', 'normalize']
    cols = len(parameters)
    f, axes = plt.subplots(nrows=1, ncols=cols, figsize=(20,5))
    cmap = plt.cm.jet
    for i, val in enumerate(parameters):
        xs = np.array([t['misc']['vals'][val] for t in trials.trials]).ravel()
        ys = [-t['result']['loss'] for t in trials.trials]
        xs, ys = zip(*sorted(zip(xs, ys)))
        axes[i].scatter(xs, ys, s=20, linewidth=0.01, alpha=0.25, c=cmap(float(i)/len(parameters)))
        axes[i].set_title(val)
        axes[i].set_ylim([0.9, 1.0])

    显示 ['C', 'kernel', 'gamma', 'scale', 'normalize']   VS 准确率  的关系图:

    3)决策树

    iris = datasets.load_iris()
    X_original = iris.data
    y_original = iris.target
    
    def hyperopt_train_test(params):
        X_ = X[:]
        if 'normalize' in params:
            if params['normalize'] == 1:
                X_ = normalize(X_)
                del params['normalize']
    
        if 'scale' in params:
            if params['scale'] == 1:
                X_ = scale(X_)
                del params['scale']
        clf = DecisionTreeClassifier(**params)
        return cross_val_score(clf, X, y).mean()
    
    space4dt = {
        'max_depth': hp.choice('max_depth', range(1,20)),
        'max_features': hp.choice('max_features', range(1,5)),
        'criterion': hp.choice('criterion', ["gini", "entropy"]),
        'scale': hp.choice('scale', [0, 1]),
        'normalize': hp.choice('normalize', [0, 1])
    }
    
    def f(params):
    acc = hyperopt_train_test(params)
    return {'loss': -acc, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(f, space4dt, algo=tpe.suggest, max_evals=300, trials=trials)
    print 'best:'
    print best

    其准确率为97.3%。

    {'max_features': 1, 'normalize': 0, 'scale': 0, 'criterion': 0, 'max_depth': 17}

    4)随机森林

    iris = datasets.load_iris()
    X_original = iris.data
    y_original = iris.target
    
    def hyperopt_train_test(params):
        X_ = X[:]
        if 'normalize' in params:
            if params['normalize'] == 1:
                X_ = normalize(X_)
                del params['normalize']
    
        if 'scale' in params:
            if params['scale'] == 1:
                X_ = scale(X_)
                del params['scale']
        clf = RandomForestClassifier(**params)
        return cross_val_score(clf, X, y).mean()
    
    space4rf = {
        'max_depth': hp.choice('max_depth', range(1,20)),
        'max_features': hp.choice('max_features', range(1,5)),
        'n_estimators': hp.choice('n_estimators', range(1,20)),
        'criterion': hp.choice('criterion', ["gini", "entropy"]),
        'scale': hp.choice('scale', [0, 1]),
        'normalize': hp.choice('normalize', [0, 1])
    }
    
    best = 0
    def f(params):
        global best
        acc = hyperopt_train_test(params)
        if acc > best:
        best = acc
        print 'new best:', best, params
        return {'loss': -acc, 'status': STATUS_OK}
    
    trials = Trials()
    best = fmin(f, space4rf, algo=tpe.suggest, max_evals=300, trials=trials)
    print 'best:'
    print best

    总结

    我们已经介绍了简单的例子,如最小化确定的线性函数,以及复杂的例子,如调整随机森林参数。hyperopt的官方文档在这里。另一篇有关 hyperopt 不错的博客位于 FastML 站点(译注:已无效)。hyperopt作者的SciPy会议论文是Hyperopt: A Python Library for Optimizing the Hyperparameters of Machine Learning Algorithms,伴随一起的视频教程。关于工程来龙去脉的更多技术处理细节可以参见Making a Science of Model Search

    参考:https://www.jianshu.com/p/35eed1567463

  • 相关阅读:
    (转)Quick Tip: Provisioning Web Parts to a Page(添加web part到page上,)
    解决sharepoint 2010浏览器在线浏览Word出错(非原创)
    转:部署带webpart的网页(Deploy a Page using a Feature)
    单点登录到sharepoint
    Feature Base On WebApp
    Create a New Document Using Office Web Apps
    学校合并与数组合并
    DNN拟合曲线
    使用tf.keras.layers.Layer自定义神经网络的层
    numpy
  • 原文地址:https://www.cnblogs.com/onenoteone/p/12441725.html
Copyright © 2020-2023  润新知