
SQL注入攻擊深度解析與防護策略
在本文中,我們將討論貝葉斯優化作為一種具有記憶并從每次參數調整中學習的超參數優化方法。然后,我們將從頭開始構建一個貝葉斯優化器,而不使用任何特定的庫。
傳統的超參數優化方法,如網格搜索(grid search)
和隨機搜索(random search)
,需要多次計算給定模型的成本函數,以找到超參數的最優組合。由于許多現代機器學習架構包含大量超參數(例如深度神經網絡),計算成本函數變得計算昂貴,降低了傳統方法(如網格搜索)的吸引力。在這種情況下,貝葉斯優化已成為常見的超參數優化方法之一,因為它能夠在迭代次數明顯較少的情況下找到優化的解決方案,相較于傳統方法如網格搜索和隨機搜索,這得益于從每次迭代中學習。
貝葉斯優化在概念上可能看起來復雜,但一旦實現,它會變得更簡單。在這一部分中,我將提供貝葉斯優化工作原理的概念性概述,然后我們將實施它以更好地理解。
貝葉斯優化利用貝葉斯技術
對目標函數
設置先驗
,然后添加一些新信息以得到后驗函數
。
先驗
表示在新信息可用之前我們所知道的內容,后驗
表示在給定新信息后我們對目標函數的了解。
更具體地說,收集搜索空間
的樣本(在這個上下文中是一組超參數),然后為給定樣本計算目標函數(即訓練和評估模型)。由于目標函數不容易獲得,使用“替代函數”
作為目標函數的貝葉斯近似
。
然后,使用前一個樣本的信息更新替代函數,從先驗到后驗。
后驗表示在那個時間點上我們對目標函數的最佳了解,并用于指導“獲取函數”
。獲取函數
(例如期望改進)優化搜索空間內位置的條件概率,以獲取更有可能優化原始成本函數的新樣本。
繼續使用期望改進的例子,獲取函數計算超參數網格中每個點的期望改進,并返回具有最大值的點。然后,新收集的樣本將通過成本函數運行,后驗將被更新,這個過程重復,直到達到目標函數的可接受的優化點、產生足夠好的結果,或者資源耗盡。
本節將專注于貝葉斯優化的逐步實現,共有七個步驟。首先,我將列出這些步驟,然后提供詳細的解釋,以及實現代碼塊。
讓我們深入研究!
我們首先導入一些必要的庫,如下所示:
numpy
用于數值計算,是數據科學中常見的庫之一scipy.stats
是一個用于統計函數的庫load_iris
是 scikit-learn
中加載鳶尾花數據集的函數GaussianProcessRegressor
是 scikit-learn
中實現高斯過程回歸模型的類Matern
是 scikit-learn
中實現 Matern
核函數的類,用于高斯過程import numpy as np
import scipy.stats as sps
from sklearn.datasets import load_iris
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern
導入了這些庫之后,讓我們繼續定義目標函數。
目標函數接受一組超參數 C
和 gamma
作為輸入,并返回在鳶尾花數據集上使用 RBF
核的支持向量分類器的負準確性。其中,C
是正則化參數,gamma
是 RBF
、poly
和 sigmoid
核的核系數。核系數的詳細信息對我們的流程并不關鍵,可以在這里找到。然后,我們使用 load_iris
加載鳶尾花數據集,并將數據分為訓練集和測試集。數據準備好后,訓練支持向量分類器,并返回在測試集上的負準確性。
def objective(params):
C, gamma = params
X, y = load_iris(return_X_y=True)
np.random.seed(0)
indices = np.random.permutation(len(X))
X_train = X[indices[:100]]
y_train = y[indices[:100]]
X_test = X[indices[100:]]
y_test = y[indices[100:]]
from sklearn.svm import SVC
clf = SVC(C=C, gamma=gamma)
clf.fit(X_train, y_train)
return -clf.score(X_test, y_test)
在這一步,我們定義超參數搜索空間的邊界。我們創建一個形狀為 (2, 2
) 的 NumPy
數組 bounds
,其中每行對應一個超參數,每列對應該超參數的下界和上界。在我們的例子中,第一個超參數是 C
,第二個是 gamma
,兩者都用于訓練支持向量分類器。
設置邊界的目的是限制超參數搜索空間,避免測試不太可能是最優的值,并將優化焦點放在超參數空間的最有希望的區域。我們對這個練習隨機定義了邊界,但在超參數范圍已知的任務中,這變得很重要。
bounds = np.array([[1e-3, 1e3], [1e-5, 1e-1]])
這一步定義了我們之前討論過的獲取函數,并確定在搜索空間中要評估的下一個點。在這個具體的例子中,獲取函數是期望改進(Expected Improvement, EI)
函數。它測量目標函數在當前最佳觀測值的基礎上的期望改進,考慮到當前替代模型(高斯過程)。獲取函數的定義如下:
gp.predict()
在點 x
處預測均值和標準差。f_best
)。f_best
的改進為 improvement = f_best — mu
。sigma
為正,則計算標準得分 Z = improvement/sigma
;如果 sigma
為 0
,則將 Z
設置為 0
。sps.norm.cdf
)和概率密度函數(sps.norm.pdf
)計算在點 x
處的期望改進(ei
)。def acquisition(x):
mu, sigma = gp.predict(x.reshape(1, -1), return_std=True)
f_best = np.min(y_samples)
improvement = f_best - mu
with np.errstate(divide='warn'):
Z = improvement / sigma if sigma > 0 else 0
ei = improvement * sps.norm.cdf(Z) + sigma * sps.norm.pdf(Z)
ei[sigma == 0.0] == 0.0
return ei
在開始貝葉斯優化循環之前,我們需要使用一些初始樣本初始化高斯過程替代模型。如前所述,替代函數用于有效地逼近未知的目標函數以進行優化。高斯過程是一個概率模型,定義了對函數的先驗。隨著獲取新數據,它允許使用貝葉斯推理來更新模型。具體而言,x_samples
是從由 bounds
數組定義的搜索空間中隨機抽樣的初始點。y_samples
是這些初始點對應的目標函數評估。這些樣本用于訓練高斯過程,并改進其替代建模。
我們終于來到了貝葉斯優化循環。在這一步中,貝葉斯優化循環將運行指定次數(n_iter
)。在每次迭代中,使用現有樣本(即 x_samples
和 y_samples
)更新高斯過程模型,使用 gp.fit()
方法。然后,通過在參數空間生成的大量隨機點(即 x_random_points
)優化獲取函數,選擇下一個由目標函數評估的樣本。在這些點上評估獲取函數,并選擇獲取函數值最大的點作為下一個樣本(即 x_next
)。在此點記錄獲取函數值作為 best_acq_value
。最后,在選擇的點上評估目標函數,并通過更新 x_samples
和 y_samples
將結果值添加到現有樣本中。這個過程重復進行指定次數的迭代(即 n_iter
),并打印每次迭代的結果。
# 運行 n_iter 次的貝葉斯優化循環
n_iter = 10
for i in range(n_iter):
# 使用現有樣本更新高斯過程
gp.fit(x_samples, y_samples)
# 通過優化獲取函數找到下一個樣本
x_next = None
best_acq_value = -np.inf
# 從參數空間中抽樣大量隨機點
n_random_points = 10000
x_random_points = np.random.uniform(bounds[:, 0], bounds[:, 1], size=(n_random_points, bounds.shape[0]))
# 在每個點上評估獲取函數并找到最大值
acq_values = np.array([acquisition(x) for x in x_random_points])
max_acq_index = np.argmax(acq_values)
max_acq_value = acq_values[max_acq_index]
if max_acq_value > best_acq_value:
best_acq_value = max_acq_value
x_next = x_random_points[max_acq_index]
print(f"Iteration {i+1}: next sample is {x_next}, acquisition value is {best_acq_value}")
# 在下一個樣本上評估目標函數并將其添加到現有樣本中
y_next = objective(x_next)
x_samples = np.vstack((x_samples, x_next))
y_samples = np.append(y_samples, y_next)
最后,我們打印在貝葉斯優化循環中找到的最佳參數和最佳準確性。最佳參數是與目標函數最小值相對應的參數,這就是為什么使用 np.argmin
來找到 y_samples
最小值的索引。
# Print final results
best_index = np.argmin(y_samples)
best_x = x_samples[best_index]
best_y = y_samples[best_index]
print(f"Best parameters: C={best_x[0]}, gamma={best_x[1]}")
print(f"Best accuracy: {best_y}")
以下是運行此過程的最終結果:
在本文中,我們介紹了機器學習流水線中的超參數優化,并深入探討了超參數優化的世界,詳細討論了貝葉斯優化以及為什么它可能是一種相對于基本優化器(如網格搜索和隨機搜索)更有效的微調策略。然后,我們逐步從頭開始構建了一個用于分類的貝葉斯優化器,以更好地理解這個過程。
文章轉自微信公眾號@算法進階