LESSON 10.410.510.6 贝叶斯优化的基本流程BayesOpt vs HyperOpt vs Optuna batch基于BayesOpt实现高斯过程gp优化
超參數優化 - 貝葉斯優化方法
import numpy as np import pandas as pd import sklearn import matplotlib as mlp import matplotlib.pyplot as plt import seaborn as sns import time import re, pip, conda目錄
一 貝葉斯優化基礎方法
? 1 貝葉斯優化的基本流程
? 2 貝葉斯優化用于HPO
二 貝葉斯優化的實現
? 1 基于Bayes_opt實現GP優化
? 2 基于HyperOpt實現TPE優化
? 3 基于Optuna實現多種貝葉斯優化
一 貝葉斯優化基礎方法
在之前的課程中我們講解了網格搜索、隨機網格搜索與Halving網格搜索,無論具體每種網格搜索的思想如何變化,網格優化都是在一個大參數空間中、盡量對所有點進行驗證后再返回最優損失函數值的方法,這一類方法在計算量與計算時間上有著不可避免的缺陷,因此才會有隨機、Halving等試圖縮短訓練時間、讓整體網格搜索更加適合于大型數據和大型空間的手段。然而,盡管sklearn在提高網格搜索效率方面做出了種種優化,但上述方法仍然無法在效率和精度上做到雙贏,若希望更快速的進行參數搜索、并且搜索出一組泛化能力盡可能強的參數,目前的常見做法還是選用一些帶有先驗過程(提前做一些假設)的調參工具,即一些基于貝葉斯過程調參工具。
貝葉斯優化方法是當前超參數優化領域的SOTA手段(State of the Art),可以被認為是當前最為先進的優化框架,它可以被應用于AutoML的各大領域,不止限于超參數搜索HPO的領域,更是可以被用于神經網絡架構搜索NAS以及元學習等先進的領域。現代幾乎所有在效率和效果上取得優異成果的超參數優化方法都是基于貝葉斯優化的基本理念而形成的,因此貝葉斯優化是整個AutoML中學習的重點。
然而,雖然貝葉斯優化非常強大,但整體的學習難度卻非常高。在學習貝葉斯優化之前,學習者不僅需要充分理解機器學習的主要概念和算法、熟悉典型的超參數優化流程,還需要對部分超出微積分、概率論和線性代數的數學知識有所掌握。特別的是,貝葉斯優化算法本身,與貝葉斯優化用于HPO的過程還有區別。在我們課程有限的時間內,我將重點帶大家來看貝葉斯優化用于HPO的核心過程。
1 貝葉斯優化的基本流程
首先,我們不理會HPO的問題,先來看待下面的例子。假設現在我們知道一個函數𝑓(𝑥)的表達式以及其自變量𝑥的定義域,現在,我們希望求解出𝑥的取值范圍上𝑓(𝑥)的最小值,你打算如何求解這個最小值呢?面對這個問題,無論是從單純的數學理論角度,還是從機器學習的角度,我們都已經見過好幾個通俗的思路:
- 1 我們可以對𝑓(𝑥)求導、令其一階導數為0來求解其最小值
函數𝑓(𝑥)f(x)可微,且微分方程可以直接被求解
- 2 我們可以通過梯度下降等優化方法迭代出𝑓(𝑥)的最小值
函數𝑓(𝑥)f(x)可微,且函數本身為凸函數
- 3 我們將全域的𝑥帶入𝑓(𝑥)計算出所有可能的結果,再找出最小值
函數𝑓(𝑥)f(x)相對不復雜、自變量維度相對低、計算量可以承受
當我們知道函數𝑓(𝑥)的表達式時,以上方法常常能夠有效,但每個方法都有自己的前提條件。假設現在函數𝑓(𝑥)是一個平滑均勻的函數,但它異常復雜、且不可微,我們無法使用上述三種方法中的任意一種方法求解,但我們還是想求解其最小值,可以怎么辦呢?由于函數異常復雜,帶入任意𝑥計算的所需的時間很長,所以我們不太可能將全域𝑥都帶入進行計算,但我們還是可以從中隨機抽樣部分觀測點來觀察整個函數可能存在的趨勢。于是我們選擇在𝑥的定義域上隨機選擇了4個點,并將4個點帶入𝑓(𝑥)進行計算,得到了如下結果:
?好了,現在有了這4個觀測值,你能告訴我𝑓(𝑥)的最小值在哪里嗎?你認為最小值點可能在哪里呢?大部分人會傾向于認為,最小值點可能非常接近于已觀測出4個𝑓(𝑥)值中最小的那個值,但也有許多人不這么認為。當我們有了4個觀測值,并且知道我們的函數時相對均勻、平滑的函數,那我們可能對函數的整體分布有如下猜測:
當我們對函數整體分布有一個猜測時,這個分布上一定會存在該函數的最小值。同時,不同的人可能對函數的整體分布有不同的猜測,不同猜測下對應的最小值也是不同的。
現在,假設我們邀請了數萬個人對該問題做出猜測,每個人所猜測的曲線如下圖所示。不難發現,在觀測點的附近,每個人猜測的函數值差距不大,但是在遠離遠側點的地方,每個人猜測的函數值就高度不一致了。這也是當然的,因為觀測點之間函數的分布如何完全是未知的,并且該分布離觀測點越遠時,我們越不確定真正的函數值在哪里,因此人們猜測的函數值的范圍非常巨大。
[0,1] - 100個小區間[0,0.01] n1 [0.01,0.02] n2 [0.02,0.03] n3 ... [0.99,1] n100現在,我們將所有猜測求均值,并將任意均值周圍的潛在函數值所在的區域用色塊表示,可以得到一條所有人猜測的平均曲線。不難發現,色塊所覆蓋的范圍其實就是大家猜測的函數值的上界和下界,而任意𝑥所對應的上下界差異越大,表示人們對函數上該位置的猜測值的越不確定。因此上下界差異可以衡量人們對該觀測點的置信度(自信度),色塊范圍越大,置信度越低。
在觀測點周圍,置信度總是很高的,遠離觀測點的地方,置信度總是很低,所以如果我們能夠在置信度很低的地方補充一個實際的觀測點,我們就可以很快將眾人的猜測統一起來。以下圖為例,當我們在置信度很低的區間內取一個實際觀測值時,圍繞該區間的“猜測”會立刻變得集中,該區間內的置信度會大幅升高。
當整個函數上的置信度都非常高時,我們可以說我們得出了一條與真實的𝑓(𝑥)曲線高度相似的曲線𝑓?,次數我們就可以將𝑓?的最小值當作真實𝑓(𝑥)的最小值來看待。自然,如果估計越準確,𝑓?越接近𝑓(𝑥),則𝑓?的最小值也會越接近于𝑓(𝑥)的真實最小值。那如何才能夠讓𝑓?更接近𝑓(𝑥)呢?根據我們剛才提升置信度的過程,很明顯——觀測點越多,我們估計出的曲線會越接近真實的𝑓(𝑥)。然而,由于計算量有限,我們每次進行觀測時都要非常謹慎地選擇觀測點。那現在,如何選擇觀測點才能夠最大程度地幫助我們估計出𝑓(𝑥)的最小值呢?
有非常多的方法,其中最簡單的手段是使用最小值出現的頻數進行判斷。由于不同的人對函數的整體分布有不同的猜測,不同猜測下對應的最小值也是不同的,根據每個人猜測的函數結果,我們在𝑋軸上將定義域區間均勻劃分為100個小區間,如果有某個猜測的最小值落在其中一個區間中,我們就對該區間進行計數(這個過程跟對離散型變量繪制直方圖的過程完全一致)。當有數萬個人進行猜測之后,我們同時也繪制了基于𝑋軸上不同區間的頻數圖,頻數越高,說明猜測最小值在該區間內的人越多,反之則說明該猜測最小值在該區間內的人越少。該頻數一定程度上反饋出最小值出現的概率,頻數越高的區間,函數真正的最小值出現的概率越高。
當我們將𝑋軸上的區間劃分得足夠細后,繪制出的頻數圖可以變成概率密度曲線,曲線的最大值所對應的點是𝑓(𝑥)的最小值的概率最高,因此很明顯,我們應該將曲線最大值所對應的點確認為下一個觀測點。根據圖像,我們知道最小值最有可能在的區間就在x=0.7左右的位置。當我們不取新的觀測點時,現在𝑓(𝑥)上可以獲得的可靠的最小值就是x=0.6時的點,但我們如果在x=0.7處取新的觀測值,我們就很有可能找到比當前x=0.6的點還要小的𝑓𝑚𝑖𝑛。因此,我們可以就此決定,在x=0.7處進行觀測。
當我們在x=0.7處取出觀測值之后,我們就有了5個已知的觀測點。現在,我們再讓數萬人根據5個已知的觀測點對整體函數分布進行猜測,猜測完畢之后再計算當前最小值頻數最高的區間,然后再取新的觀測點對𝑓(𝑥)進行計算。當允許的計算次數被用完之后(比如,500次),整個估計也就停止了。
你發現了嗎?在這個過程當中,我們其實在不斷地優化我們對目標函數𝑓(𝑥)的估計,雖然沒有對𝑓(𝑥)進行全部定義域上的計算,也沒有找到最終確定一定是𝑓(𝑥)分布的曲線,但是隨著我們觀測的點越來越多,我們對函數的估計是越來越準確的,因此也有越來越大的可能性可以估計出𝑓(𝑥)真正的最小值。這個優化的過程,就是貝葉斯優化。
2 貝葉斯優化用于HPO
在貝葉斯優化的數學過程當中,我們主要執行以下幾個步驟:
-
1 定義需要估計的𝑓(𝑥)以及𝑥的定義域
-
2 取出有限的n個𝑥上的值,求解出這些𝑥對應的𝑓(𝑥)(求解觀測值)
-
3 根據有限的觀測值,對函數進行估計(該假設被稱為貝葉斯優化中的先驗知識),得出該估計𝑓?上的目標值(最大值或最小值)
-
4 定義某種規則,以確定下一個需要計算的觀測點
并持續在2-4步驟中進行循環,直到假設分布上的目標值達到我們的標準,或者所有計算資源被用完為止(例如,最多觀測m次(最多觀測m個點),或最多允許運行t分鐘)。
以上流程又被稱為序貫模型優化(SMBO),是最為經典的貝葉斯優化方法。在實際的運算過程當中,尤其是超參數優化的過程當中,有以下具體細節需要注意:
-
當貝葉斯優化不被用于HPO時,一般𝑓(𝑥)可以是完全的黑盒函數(black box function,也譯作黑箱函數,即只知道𝑥與𝑓(𝑥)的對應關系,卻絲毫不知道函數內部規律、同時也不能寫出具體表達式的一類函數),因此貝葉斯優化也被認為是可以作用于黑盒函數估計的一類經典方法。但在HPO過程當中,需要定義的𝑓(𝑥)一般是交叉驗證的結果/損失函數的結果,而我們往往非常清楚損失函數的表達式,只是我們不了解損失函數內部的具體規律,因此HPO中的𝑓(𝑥)不能算是嚴格意義上的黑盒函數。
-
在HPO中,自變量𝑥就是超參數空間。在上述二維圖像表示中,𝑥為一維的,但在實際進行優化時,超參數空間往往是高維且極度復雜的空間。
-
最初的觀測值數量n、以及最終可以取到的最大觀測數量m都是貝葉斯優化的超參數,最大觀測數量m也決定了整個貝葉斯優化的迭代次數。
-
在第3步中,根據有限的觀測值、對函數分布進行估計的工具被稱為概率代理模型(Probability Surrogate model),畢竟在數學計算中我們并不能真的邀請數萬人對我們的觀測點進行連線。這些概率代理模型自帶某些假設,他們可以根據廖廖數個觀測點估計出目標函數的分布𝑓?(包括𝑓?上每個點的取值以及該點對應的置信度)。在實際使用時,概率代理模型往往是一些強大的算法,最常見的比如高斯過程、高斯混合模型等等。傳統數學推導中往往使用高斯過程,但現在最普及的優化庫中基本都默認使用基于高斯混合模型的TPE過程。(高斯過程估計均值方差來得到𝑓?上每個點的取值以及該點對應的置信度)
-
在第4步中用來確定下一個觀測點的規則被稱為采集函數(Aquisition Function),采集函數衡量觀測點對擬合𝑓?所產生的影響,并選取影響最大的點執行下一步觀測,因此我們往往關注采集函數值最大的點。最常見的采集函數主要是概率增量PI(Probability of improvement,比如我們計算的頻數)、期望增量(Expectation Improvement)、置信度上界(Upper Confidence Bound)、信息熵(Entropy)等等。上方gif圖像當中展示了PI、UCB以及EI。其中大部分優化庫中默認使用期望增量。
在HPO中使用貝葉斯優化時,我們常常會看見下面的圖像,這張圖像表現了貝葉斯優化的全部基本元素,我們的目標就是在采集函數指導下,讓𝑓?盡量接近𝑓(𝑥)。
真正的f(x)(虛線)上取兩個觀測值,利用概率代理模型來推測出估計的f*(實線)和置信度。根據概率代理模型所輸出的結果(f*)計算出采集函數,采集函數最大值所對應的x點就是下一個觀測點。
現在我們已經了解貝葉斯優化的基本流程。與許多算法一樣,基礎流程足以支撐我們使用已經搭建好的優化庫進行超參數優化了,即便我們沒有對優化原理的每個細節都了如指掌,我們也可以通過實驗反饋出的結果來直接判斷是否應該調整我們的代碼。接下來,我們會先學習如何應用貝葉斯優化的各類庫實現不同的貝葉斯優化算法。
二 貝葉斯優化的實現
貝葉斯優化是當今黑盒函數估計領域最為先進和經典的方法,在同一套序貫模型下使用不同的代理模型以及采集函數、還可以發展出更多更先進的貝葉斯優化改進版算法,因此,貝葉斯優化的其算法本身就多如繁星,實現各種不同種類的貝葉斯優化的庫也是琳瑯滿目,幾乎任意一個專業用于超參數優化的工具庫都會包含貝葉斯優化的內容。我們可以在以下頁面找到大量可以實現貝葉斯優化方法的HPO庫:AutoML | Overview of HPO Packages?,其中大部分庫都是由獨立團隊開發和維護,因此不同的庫之間之間的優劣、性格、功能都有很大的差異。在課程中,我們將介紹如下三個可以實現貝葉斯優化的庫:bayesian-optimization,hyperopt,optuna。
注意,以上三個庫都不支持基于Python環境的并行或加速,大多數優化算法庫只能夠支持基于數據庫(如MangoDB,mySQL)的并行或加速,但以上庫都可以被部署在分布式計算平臺。
三個庫極其輔助包的安裝方法分別如下,使用pip或conda安裝時注意關閉梯子。
- Bayes_opt
- Hyperopt
- Optuna
- Skopt(作為Optuna輔助包安裝,也可單獨使用)
接下來我們會分別使用三個庫來實現貝葉斯優化。在課程中,我們依然使用集成算法中的房價數據作為驗證數據,并且呈現出我們之前在不同優化方法上得出的結果作為對比。同時,我們將使用與集成算法中完全一致的隨機數種子、以及隨機森林算法作為被優化的評估器。
- 導入庫,確認使用數據
Bayes_opt版本:1.2.0
print(optuna.__version__) #2.10.0print(hyperopt.__version__) #0.2.7data = pd.read_csv(r"D:\Pythonwork\2021ML\PART 2 Ensembles\datasets\House Price\train_encode.csv",index_col=0)X = data.iloc[:,:-1] y = data.iloc[:,-1] X.head() X.shape #(1460, 80)- 確認該數據集上的歷史成果
1 基于Bayes_opt實現GP優化
bayes-optimization是最早開源的貝葉斯優化庫之一,也是為數不多至今依然保留著高斯過程優化的優化庫。由于開源較早、代碼簡單,bayes-opt常常出現在論文、競賽kernels或網絡學習材料當中,因此理解Bayes_opt的代碼是極其重要的課題。不過,bayes-opt對參數空間的處理方式較為原始,也缺乏相應的提效/監控功能,對算力的要求較高,因此它往往不是我們進行優化時的第一首選庫。通常來說,當且僅當我們必須要實現基于高斯過程的貝葉斯優化,且算法的參數空間中帶有大量連續型參數時,我們才會優先考慮Bayes_opt庫。我們可以在github上找到bayes-optmization的官方文檔(https://github.com/fmfn/BayesianOptimization)?,想要進一步了解其基本功能與原理的小伙伴可以進行閱讀。
from bayes_opt import BayesianOptimization- 1 定義目標函數
目標函數的值即𝑓(𝑥)的值。貝葉斯優化會計算𝑓(𝑥)在不同𝑥上的觀測值,因此𝑓(𝑥)的計算方式需要被明確。在HPO過程中,我們希望能夠篩選出令模型泛化能力最大的參數組合,因此𝑓(𝑥)應該是損失函數的交叉驗證值或者某種評估指標的交叉驗證值。需要注意的是,bayes_opt庫存在三個影響目標函數定義的規則:
1 目標函數的輸入必須是具體的超參數,而不能是整個超參數空間,更不能是數據、算法等超參數以外的元素,因此在定義目標函數時,我們需要讓超參數作為目標函數的輸入。
2 超參數的輸入值只能是浮點數,不支持整數與字符串。因此當算法的實際參數需要輸入字符串時,該參數不能使用bayes_opt進行調整,當算法的實際參數需要輸入整數時,則需要在目標函數中規定參數的類型。
3 bayes_opt只支持尋找𝑓(𝑥)的最大值,不支持尋找最小值。因此當我們定義的目標函數是某種損失時,目標函數的輸出需要取負(即,如果使用RMSE,則應該讓目標函數輸出負RMSE,這樣最大化負RMSE后,才是最小化真正的RMSE。)當我們定義的目標函數是準確率,或者auc等指標,則可以讓目標函數的輸出保持原樣。
- 2 定義參數空間
在任意超參數優化器中,優化器會將參數空格中的超參數組合作為備選組合,一組一組輸入到算法中進行訓練。在貝葉斯優化中,超參數組合會被輸入我們定義好的目標函數𝑓(𝑥)中。
在bayes_opt中,我們使用字典方式來定義參數空間,其中參數的名稱為鍵,參數的取值范圍為值。且任意參數的取值范圍為雙向閉區間,以下方的空間為例,在n_estimators的取值中,80與100都可以被取到。
以下參數空間與我們在隨機森林中獲得最高分的隨機搜索的范圍高度相似。
param_grid_simple = {'n_estimators': (80,100), 'max_depth':(10,25), "max_features": (10,20), "min_impurity_decrease":(0,1)}需要注意的是,bayes_opt只支持填寫參數空間的上界與下界,不支持填寫步長等參數,且bayes_opt會將所有參數都當作連續型超參進行處理,因此bayes_opt會直接取出閉區間中任意浮點數作為備選參數。例如,取92.28作為n_estimators的值。
這也是為什么在目標函數中,我們需要對整數型超參的取值都套上int函數。假設優化器取出92.28作為n_estimators的值,實際傳入隨機森林算法的會是int(92.28) = 92,如此我們可以保證算法運行過程中不會因參數類型不符而報錯。也因為bayes_opt的這個性質,輸入bayes_opt的參數空間天生會比其他貝葉斯優化庫更大/更密,因此需要的迭代次數也更多。
- 3 定義優化目標函數的具體流程
在有了目標函數與參數空間之后,我們就可以按bayes_opt的規則進行優化了。在任意貝葉斯優化算法的實踐過程中,一定都有涉及到隨機性的過程——例如,隨機抽取點作為觀測點,隨機抽樣部分觀測點進行采集函數的計算等等。在大部分優化庫當中,這種隨機性是無法控制的,即便允許我們填寫隨機數種子,優化算法也不能固定下來。因此我們可以嘗試填寫隨機數種子,但需要記住優化算法每次運行時一定都會不一樣。
雖然,優化算法無法被復現,但是優化算法得出的最佳超參數的結果卻是可以被復現的。只要優化完畢之后,可以從優化算法的實例化對象中取出最佳參數組合以及最佳分數,該最佳參數組合被輸入到交叉驗證中后,是一定可以復現其最佳分數的。如果沒能復現最佳分數,則是交叉驗證過程的隨機數種子設置存在問題,或者優化算法的迭代流程存在問題。(GridSearchCV--自己幫我們分割數據集、自己幫我們進行交叉驗證,自己求解出結果,通常會獲取最佳參數自己(分割數據集、進行交叉驗證,求解出結果)再驗證一次,所以搜索最優和重建最優是不同的。然而對于bayes優化而言沒有GridSearchCV搜索最優和重建最優是相同的)
def param_bayes_opt(init_points,n_iter):#定義優化器,先實例化優化器opt = BayesianOptimization(bayesopt_objective #需要優化的目標函數,param_grid_simple #備選參數空間,random_state=1412 #隨機數種子,雖然無法控制住)#使用優化器,記住bayes_opt只支持最大化opt.maximize(init_points = init_points #抽取多少個初始觀測值, n_iter=n_iter #一共觀測/迭代多少次)#優化完成,取出最佳參數與最佳分數params_best = opt.max["params"]score_best = opt.max["target"]#打印最佳參數與最佳分數print("\n","\n","best params: ", params_best,"\n","\n","best cvscore: ", score_best)#返回最佳參數與最佳分數return params_best, score_best- 4 定義驗證函數(非必須)
優化后的結果是可以復現的,即我們可以對優化算法給出的最優參數進行再驗證,其中驗證函數與目標函數高度相似,輸入參數或超參數空間、輸出最終的損失函數結果。在使用sklearn中自帶的優化算法時,由于優化算法自己會執行分割數據、交叉驗證的步驟,因此優化算法得出的最優分數往往與我們自身驗證的分數不同(因為交叉驗證時的數據分割不同)。然而在貝葉斯優化過程中,目標函數中的交叉驗證即數據分割都是我們自己規定的,因此原則上來說,只要在目標函數中設置了隨機數種子,貝葉斯優化給出的最佳分數一定與我們驗證后的分數相同,所以當你對優化過程的代碼比較熟悉時,可以不用進行二次驗證。
def bayes_opt_validation(params_best):reg = RFR(n_estimators = int(params_best["n_estimators"]) ,max_depth = int(params_best["max_depth"]),max_features = int(params_best["max_features"]),min_impurity_decrease = params_best["min_impurity_decrease"],random_state=1412,verbose=False,n_jobs=-1)cv = KFold(n_splits=5,shuffle=True,random_state=1412)validation_loss = cross_validate(reg,X,y,scoring="neg_root_mean_squared_error",cv=cv,verbose=False,n_jobs=-1)return np.mean(validation_loss["test_score"])- 5 執行實際優化流程
- 原理上有優越性
可以看到,基于高斯過程的貝葉斯優化在2.11分鐘內鎖定了最佳分數28346.673,這是之前使用隨機搜索時獲得的最佳分數,很可能也是我們當前超參數空間上可以獲得的最佳分數。貝葉斯優化作為從原理上高于網格優化的HPO方法,能夠以更短的時間獲得與隨機網格搜索相同的結果,可見其原理上的優越性。
- 優化過程無法復現,但優化結果可以復現
但同時要注意,由于貝葉斯優化每次都是隨機的,因此我們并不能在多次運行代碼時復現出28346.673這個結果,事實上如果我們重復運行,也只有很小的概率可以再次找到這個最低值(這一點對于隨機搜索來說也是類似的,如果不規定隨機數種子,我們也無法復現最低值)。因此我們在執行貝葉斯優化時,往往會多運行幾次觀察模型找出的結果。同時,驗證分數與目標函數最后輸出的分數一模一樣,可見最終輸出的超參數組合的效力是可以復現的。
- 效率不足
不難發現,bayes_opt的速度雖然快,效率卻不高。實際上在迭代到170次時,貝葉斯優化就已經找到了最小損失,但由于沒有提前停止機制,模型還持續地迭代了130次才停下,如果bayes_opt支持提前停止機制,貝葉斯優化所需的實際迭代時間可能會更少。同時,由于Bayes_opt只能夠在參數空間提取浮點數,bayes_opt在隨機森林上的搜索效率是較低的,即便在10次不同的迭代中分別取到了[88.89, 88.23, 88.16, 88.59……]等值,在取整之后也只能夠獲得一個備選值88,但bayes_opt無法辨別這種區別,因此可能取出了眾多無效的觀測點。如果使用其他貝葉斯優化器,貝葉斯優化的效率將會更高。
- 支持靈活修改
雖然在我們的代碼中沒有體現,但bayes_opt是支持靈活修改采集函數與高斯過程中的種種參數的,具體可以參考這里:BayesianOptimization/advanced-tour.ipynb at master · fmfn/BayesianOptimization · GitHub
總結
以上是生活随笔為你收集整理的LESSON 10.410.510.6 贝叶斯优化的基本流程BayesOpt vs HyperOpt vs Optuna batch基于BayesOpt实现高斯过程gp优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LESSON 9.5 随机森林在巨量数据
- 下一篇: LESSON 11.4 原理进阶:Ada