<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          模型神器組合,yyds!

          共 11931字,需瀏覽 24分鐘

           ·

          2021-09-15 14:51

          ↑ 關(guān)注 + 星標(biāo) ,每天學(xué)Python新技能

          后臺回復(fù)【大禮包】送你Python自學(xué)大禮包

          最近在kaggle上有一個(gè)調(diào)參神器非常熱門,在top方案中頻頻出現(xiàn),它就是OPTUNA。知道很多小伙伴苦惱于漫長的調(diào)參時(shí)間里,這次結(jié)合一些自己的經(jīng)驗(yàn),給大家?guī)硪粋€(gè)LGBM模型+OPTUNA調(diào)參的使用教程,這對可謂是非常實(shí)用且容易上分的神器組合了,實(shí)際工作中也可使用。

          關(guān)于LightGBM不多說了,之前分享過很多文章,它是在XGBoost基礎(chǔ)上對效率提升的優(yōu)化版本,由微軟發(fā)布的,運(yùn)行效率極高,且準(zhǔn)確度不降。目前是公認(rèn)比較好,且廣泛使用的機(jī)器學(xué)習(xí)模型了,分類回歸均可滿足。
          關(guān)于調(diào)參,也就是模型的超參數(shù)調(diào)優(yōu),可能你會想到GridSearch。確實(shí)最開始我也在用GridSearch,暴力美學(xué)雖然好,但它的缺點(diǎn)很明顯,運(yùn)行太耗時(shí),時(shí)間成本太高。相比之下,基于貝葉斯框架下的調(diào)參工具就舒服多了。這類開源工具也很多,常見的比如HyperOPT。當(dāng)然今天主角不是它,而是另外一個(gè)更香的OPTUNA,輕量級且功能更強(qiáng)大,速度也是快到起飛!
          因?yàn)樾枰?LGBM 配合舉例講解,下面先從 LGBM 的幾個(gè)主要超參數(shù)開始介紹,然后再根據(jù)這些超參設(shè)置 Optuna 進(jìn)行調(diào)參。

          LightGBM參數(shù)概述

          通常,基于樹的模型的超參數(shù)可以分為 4 類:
          1. 影響決策樹結(jié)構(gòu)和學(xué)習(xí)的參數(shù)
          2. 影響訓(xùn)練速度的參數(shù)
          3. 提高精度的參數(shù)
          4. 防止過擬合的參數(shù)
          大多數(shù)時(shí)候,這些類別有很多重疊,提高一個(gè)類別的效率可能會降低另一個(gè)類別的效率。如果完全靠手動調(diào)參,那會比較痛苦。所以前期我們可以利用一些自動化調(diào)參工具給出一個(gè)大致的結(jié)果,而自動調(diào)參工具的核心在于如何給定適合的參數(shù)區(qū)間范圍。 如果能給定合適的參數(shù)網(wǎng)格,Optuna 就可以自動找到這些類別之間最平衡的參數(shù)組合。
          下面對LGBM的4類超參進(jìn)行介紹。

          1、控制樹結(jié)構(gòu)的超參數(shù)

          max_depth 和 num_leaves
          LGBM 中,控制樹結(jié)構(gòu)的最先要調(diào)的參數(shù)是max_depth(樹深度) 和 num_leaves(葉子節(jié)點(diǎn)數(shù))。這兩個(gè)參數(shù)對于樹結(jié)構(gòu)的控制最直接了斷,因?yàn)?LGBMleaf-wise 的,如果不控制樹深度,會非常容易過擬合。max_depth一般設(shè)置可以嘗試設(shè)置為3到8
          這兩個(gè)參數(shù)也存在一定的關(guān)系。由于是二叉樹,num_leaves最大值應(yīng)該是2^(max_depth)。所以,確定了max_depth也就意味著確定了num_leaves的取值范圍。
          min_data_in_leaf
          樹的另一個(gè)重要結(jié)構(gòu)參數(shù)是min_data_in_leaf,它的大小也與是否過擬合有關(guān)。它指定了葉子節(jié)點(diǎn)向下分裂的的最小樣本數(shù),比如設(shè)置100,那么如果節(jié)點(diǎn)樣本數(shù)量不夠100就停止生長。當(dāng)然,min_data_in_leaf的設(shè)定也取決于訓(xùn)練樣本的數(shù)量和num_leaves。對于大數(shù)據(jù)集,一般會設(shè)置千級以上。

          提高準(zhǔn)確性的超參數(shù)

          learning_rate 和 n_estimators
          實(shí)現(xiàn)更高準(zhǔn)確率的常見方法是使用更多棵子樹并降低學(xué)習(xí)率。換句話說,就是要找到LGBMn_estimatorslearning_rate的最佳組合。
          n_estimators控制決策樹的數(shù)量,而learning_rate是梯度下降的步長參數(shù)。經(jīng)驗(yàn)來說,LGBM 比較容易過擬合,learning_rate可以用來控制梯度提升學(xué)習(xí)的速度,一般值可設(shè)在 0.01 和 0.3 之間。一般做法是先用稍多一些的子樹比如1000,并設(shè)一個(gè)較低的learning_rate,然后通過early_stopping找到最優(yōu)迭代次數(shù)。
          max_bin
          除此外,也可以增加max_bin(默認(rèn)值為255)來提高準(zhǔn)確率。因?yàn)樽兞糠窒涞臄?shù)量越多,信息保留越詳細(xì),相反,變量分箱數(shù)量越低,信息越損失,但更容易泛化。這個(gè)和特征工程的分箱是一個(gè)道理,只不過是通過內(nèi)部的hist直方圖算法處理了。如果max_bin過高,同樣也存在過度擬合的風(fēng)險(xiǎn)。

          更多超參數(shù)來控制過擬合

          lambda_l1 和 lambda_l2
          lambda_l1lambda_l2 對應(yīng)著 L1L2 正則化,和 XGBoostreg_lambdareg_alpha 是一樣的,對葉子節(jié)點(diǎn)數(shù)和葉子節(jié)點(diǎn)權(quán)重的懲罰,值越高懲罰越大。這些參數(shù)的最佳值更難調(diào)整,因?yàn)樗鼈兊拇笮∨c過擬合沒有直接關(guān)系,但會有影響。一般的搜索范圍可以在 (0, 100)
          min_gain_to_split
          這個(gè)參數(shù)定義著分裂的最小增益。這個(gè)參數(shù)也看出數(shù)據(jù)的質(zhì)量如何,計(jì)算的增益不高,就無法向下分裂。如果你設(shè)置的深度很深,但又無法向下分裂,LGBM就會提示warning,無法找到可以分裂的了。參數(shù)含義和 XGBoostgamma 是一樣,說明數(shù)據(jù)質(zhì)量已經(jīng)達(dá)到了極限了。比較保守的搜索范圍是 (0, 20),它可以用作大型參數(shù)網(wǎng)格中的額外正則化。
          bagging_fraction 和 feature_fraction
          這兩個(gè)參數(shù)取值范圍都在(0,1)之間。
          feature_fraction指定訓(xùn)練每棵樹時(shí)要采樣的特征百分比,它存在的意義也是為了避免過擬合。因?yàn)橛行┨卣髟鲆婧芨撸赡茉斐擅靠米訕浞至训臅r(shí)候都會用到同一個(gè)特征,這樣每個(gè)子樹就同質(zhì)化了。而如果通過較低概率的特征采樣,可以避免每次都遇到一樣的強(qiáng)特征,從而讓子樹的特征變得差異化,即泛化。
          bagging_fraction指定用于訓(xùn)練每棵樹的訓(xùn)練樣本百分比。要使用這個(gè)參數(shù),還需要設(shè)置 bagging_freq,道理和feature_fraction一樣,也是讓沒棵子樹都變得好而不同

          在 Optuna 中創(chuàng)建搜索網(wǎng)格

          Optuna 中的優(yōu)化過程首先需要一個(gè)目標(biāo)函數(shù),該函數(shù)里面包括:
          • 字典形式的參數(shù)網(wǎng)格
          • 創(chuàng)建一個(gè)模型(可以配合交叉驗(yàn)證kfold)來嘗試超參數(shù)組合集
          • 用于模型訓(xùn)練的數(shù)據(jù)集
          • 使用此模型生成預(yù)測
          • 根據(jù)用戶定義的指標(biāo)對預(yù)測進(jìn)行評分并返回
          下面給出一個(gè)常用的框架,模型是5折的Kfold,這樣可以保證模型的穩(wěn)定性。最后一行返回了需要優(yōu)化的 CV 分?jǐn)?shù)的平均值。目標(biāo)函數(shù)可以自己設(shè)定,比如指標(biāo)logloss最小,auc最大,ks最大,訓(xùn)練集和測試集的auc差距最小等等。
          import optuna  # pip install optuna
          from sklearn.metrics import log_loss
          from sklearn.model_selection import StratifiedKFold

          def objective(trial, X, y):
              # 后面填充
              param_grid = {}
              cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=1121218)

              cv_scores = np.empty(5)
              for idx, (train_idx, test_idx) in enumerate(cv.split(X, y)):
                  X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
                  y_train, y_test = y[train_idx], y[test_idx]

                  model = lgbm.LGBMClassifier(objective="binary", **param_grid)
                  model.fit(
                      X_train,
                      y_train,
                      eval_set=[(X_test, y_test)],
                      eval_metric="binary_logloss",
                      early_stopping_rounds=100,
                  )
                  preds = model.predict_proba(X_test)
                  cv_scores[idx] = preds

              return np.mean(cv_scores)
          下面是參數(shù)的設(shè)置,Optuna比較常見的參數(shù)設(shè)置方式有suggest_categoricalsuggest_intsuggest_float。其中,suggest_intsuggest_float的設(shè)置方式為(參數(shù),最小值,最大值,step=步長)
          def objective(trial, X, y):
              # 字典形式的參數(shù)網(wǎng)格
              param_grid = {
                  "n_estimators": trial.suggest_categorical("n_estimators", [10000]),
                  "learning_rate": trial.suggest_float("learning_rate"0.010.3),
                  "num_leaves": trial.suggest_int("num_leaves"203000, step=20),
                  "max_depth": trial.suggest_int("max_depth"312),
                  "min_data_in_leaf": trial.suggest_int("min_data_in_leaf"20010000, step=100),
                  "max_bin": trial.suggest_int("max_bin"200300),
                  "lambda_l1": trial.suggest_int("lambda_l1"0100, step=5),
                  "lambda_l2": trial.suggest_int("lambda_l2"0100, step=5),
                  "min_gain_to_split": trial.suggest_float("min_gain_to_split"015),
                  "bagging_fraction": trial.suggest_float(
                      "bagging_fraction"0.20.95, step=0.1
                  ),
                  "bagging_freq": trial.suggest_categorical("bagging_freq", [1]),
                  "feature_fraction": trial.suggest_float(
                      "feature_fraction"0.20.95, step=0.1
                  ),
              }

          創(chuàng)建 Optuna 自動調(diào)起來

          下面是完整的目標(biāo)函數(shù)框架,供參考:
          from optuna.integration import LightGBMPruningCallback

          def objective(trial, X, y):
              # 參數(shù)網(wǎng)格
              param_grid = {
                  "n_estimators": trial.suggest_categorical("n_estimators", [10000]),
                  "learning_rate": trial.suggest_float("learning_rate"0.010.3),
                  "num_leaves": trial.suggest_int("num_leaves"203000, step=20),
                  "max_depth": trial.suggest_int("max_depth"312),
                  "min_data_in_leaf": trial.suggest_int("min_data_in_leaf"20010000, step=100),
                  "lambda_l1": trial.suggest_int("lambda_l1"0100, step=5),
                  "lambda_l2": trial.suggest_int("lambda_l2"0100, step=5),
                  "min_gain_to_split": trial.suggest_float("min_gain_to_split"015),
                  "bagging_fraction": trial.suggest_float("bagging_fraction"0.20.95, step=0.1),
                  "bagging_freq": trial.suggest_categorical("bagging_freq", [1]),
                  "feature_fraction": trial.suggest_float("feature_fraction"0.20.95, step=0.1),
                  "random_state"2021,
              }
              # 5折交叉驗(yàn)證
              cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=1121218)

              cv_scores = np.empty(5)
              for idx, (train_idx, test_idx) in enumerate(cv.split(X, y)):
                  X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
                  y_train, y_test = y[train_idx], y[test_idx]
                  
                  # LGBM建模
                  model = lgbm.LGBMClassifier(objective="binary", **param_grid)
                  model.fit(
                      X_train,
                      y_train,
                      eval_set=[(X_test, y_test)],
                      eval_metric="binary_logloss",
                      early_stopping_rounds=100,
                      callbacks=[
                          LightGBMPruningCallback(trial, "binary_logloss")
                      ],
                  )
                  # 模型預(yù)測
                  preds = model.predict_proba(X_test)
                  # 優(yōu)化指標(biāo)logloss最小
                  cv_scores[idx] = log_loss(y_test, preds)

              return np.mean(cv_scores)
          上面這個(gè)網(wǎng)格里,還添加了LightGBMPruningCallback,這個(gè)callback類很方便,它可以在對數(shù)據(jù)進(jìn)行訓(xùn)練之前檢測出不太好的超參數(shù)集,從而顯著減少搜索時(shí)間。
          設(shè)置完目標(biāo)函數(shù),現(xiàn)在讓參數(shù)調(diào)起來!
          study = optuna.create_study(direction="minimize", study_name="LGBM Classifier")
          func = lambda trial: objective(trial, X, y)
          study.optimize(func, n_trials=20)
          direction可以是minimize,也可以是maximize,比如讓auc最大化。然后可以設(shè)置trials來控制嘗試的次數(shù),理論上次數(shù)越多結(jié)果越優(yōu),但也要考慮下運(yùn)行時(shí)間。
          搜索完成后,調(diào)用best_valuebast_params屬性,調(diào)參就出來了。
          print(f"\tBest value (rmse): {study.best_value:.5f}")
          print(f"\tBest params:")

          for key, value in study.best_params.items():
              print(f"\t\t{key}{value}")
              
          -----------------------------------------------------
          Best value (binary_logloss): 0.35738
           Best params:
            device: gpu
            lambda_l1: 7.71800699380605e-05
            lambda_l2: 4.17890272377219e-06
            bagging_fraction: 0.7000000000000001
            feature_fraction: 0.4
            bagging_freq: 5
            max_depth: 5
            num_leaves: 1007
            min_data_in_leaf: 45
            min_split_gain: 15.703519227860273
            learning_rate: 0.010784015325759629
            n_estimators: 10000

          得到這個(gè)參數(shù)組合后,我們就可以拿去跑模型了,看結(jié)果再手動微調(diào),這樣就可以省很多時(shí)間了。

          結(jié)語

          本文給出了一個(gè)通過Optuna調(diào)參LGBM的代碼框架,使用及其方便,參數(shù)區(qū)間范圍需要根據(jù)數(shù)據(jù)情況自行調(diào)整,優(yōu)化目標(biāo)可以自定定義,不限于以上代碼的logloss
          關(guān)于Optuna的強(qiáng)大之處,后面會對比同類的調(diào)參工具介紹,敬請期待

          - END -

          推薦閱讀

          1. 程序員在深圳買千萬豪宅,被領(lǐng)導(dǎo)知道后,被打2星!

          2. 個(gè)個(gè)年薪都五十萬的數(shù)據(jù)分析師,是真的嗎?

          3. 打架打出來的牛逼城市!

          4. 985高校的學(xué)生“夫妻宿舍”令人羨慕,網(wǎng)友:這福利心動了,我要去讀博!

          5. 微軟這個(gè)太強(qiáng)了


          推薦一個(gè)公眾號,幫助程序員自學(xué)與成長


          瀏覽 36
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线中文字幕成人 | 69操逼| 国产在线观看一区 | 在线观看黄色免费视频 | 无码豆花视频在线观看 |