比起網格搜尋,這個方法更好嗎?
當我發現我的模型過度擬合時,我常常會想:「是時候進行正則化了。」但我該如何決定使用哪種正則化方法(L1、L2)以及選擇哪些參數呢?通常,我會透過網格搜尋來進行超參數優化,以選擇最佳設置。然而,如果自變量的尺度不同或影響程度不一樣,會發生什麼事呢?我可以為每個變量設計一個具有不同正則化係數的超參數網格嗎?這種優化在高維空間中可行嗎?還有沒有其他設計正則化的方法呢?讓我們用一個假設的例子來探討這些問題。
我的虛構例子是一個二元分類的使用案例,包含三個解釋變量。這三個變量都是類別型,並且各有七種不同的類別。我的可重現的使用案例在這個筆記本中。生成數據集的函數如下:
import numpy as np
import pandas as pd
def get_classification_dataset():
n_samples = 200
cats = ["a", "b", "c", "d", "e", "f"]
X = pd.DataFrame(data={
"col1": np.random.choice(cats, size=n_samples),
"col2": np.random.choice(cats, size=n_samples),
"col3": np.random.choice(cats, size=n_samples),
})
X_preprocessed = pd.get_dummies(X)
theta = np.random.multivariate_normal(np.zeros(len(cats) * X.shape[1]),
np.diag(np.array([1e-1] * len(cats) + [1] * len(cats) + [1e1] * len(cats))),
)
y = pd.Series(data=np.random.binomial(1, expit(np.dot(X_preprocessed.to_numpy(), theta))),
index=X_preprocessed.index,)
return X_preprocessed, y
為了展示拉普拉斯近似貝葉斯優化方法的好處,我故意選擇了三個不同的theta協方差矩陣值。如果這些值相似,興趣就會減少。
除了使用一個簡單的基準模型來預測訓練數據集的平均觀察值(用於比較目的)之外,我還設計了一個稍微複雜的模型。我決定對三個自變量進行獨熱編碼,並在這個基本預處理的基礎上應用邏輯回歸模型。對於正則化,我選擇了L2設計,並計劃使用兩種技術來尋找最佳正則化係數:網格搜尋和拉普拉斯近似貝葉斯優化。最後,我使用兩個指標(隨意選擇的)來評估模型在測試數據集上的表現:對數損失和AUC ROC。
在展示結果之前,讓我們先仔細看看貝葉斯模型以及我們如何優化它。
在貝葉斯框架中,參數不再是固定的常數,而是隨機變量。我們不再是通過最大化似然來估計這些未知參數,而是根據觀察到的數據來優化隨機參數的後驗分佈。這要求我們選擇先驗的設計和參數,通常是有些隨意的。然而,也可以將先驗的參數視為隨機變量——就像在《全面啟動》中,不確定性層層堆疊……
在這項研究中,我選擇了以下模型:
我邏輯上選擇了一個伯努利模型作為Y_i | θ,對應於θ | Σ的L2正則化的正態中心先驗,最後對於Σ_i^-1,我選擇了一個伽馬模型。我選擇建模精度矩陣,而不是文獻中傳統的協方差矩陣,就像在scikit-learn的貝葉斯線性回歸用戶指南中所述。
除了這個書面模型,我假設Y_i和Y_j在條件(θ)下是獨立的,Y_i和Σ也是如此。
似然性
根據模型,似然性可以這樣寫:
為了優化,我們需要評估幾乎所有的項目,除了P(Y=y)。分子中的項目可以使用所選模型進行評估。然而,分母中的剩餘項目無法評估。這就是拉普拉斯近似發揮作用的地方。
拉普拉斯近似
為了評估分母的第一項,我們可以利用拉普拉斯近似。我們通過以下方式近似θ | Y, Σ的分佈:
其中θ*是θ | Y, Σ的密度分佈的模式。
儘管我們不知道密度函數,但我們可以通過以下分解來評估Hessian部分:
我們只需要知道分子的前兩項來評估Hessian,而我們正好知道。
對於那些有興趣進一步了解的人,我建議參考Christopher M. Bishop的《模式識別與機器學習》第4.4部分「拉普拉斯近似」。這對我理解這個近似非常有幫助。
拉普拉斯近似的似然性
最後,為了優化的拉普拉斯近似似然性是:
一旦我們近似了θ | Y, Σ的密度函數,如果近似在各處都準確,我們就可以在任何θ下評估似然性。為了簡化,因為近似僅在接近模式時準確,我們在θ*下評估近似似然性。
以下是一個函數,用於評估給定(標量)σ²=1/p的損失(除了給定的觀察值X和y,以及設計值α和β)。
import numpy as np
from scipy.stats import gamma
from module.bayesian_model import BayesianLogisticRegression
def loss(p, X, y, alpha, beta):
# 計算給定值的損失:
# - 1/sigma²(這裡稱為p,代表精度)
# - X:特徵矩陣
# - y:觀察向量
# - alpha:先驗伽馬分佈的alpha參數
# - beta:先驗伽馬分佈的beta參數
n_feat = X.shape[1]
m_vec = np.array([0] * n_feat)
p_vec = np.array(p * n_feat)
# 計算theta*
res = minimize(BayesianLogisticRegression()._loss, np.array([0] * n_feat), args=(X, y, m_vec, p_vec), method="BFGS", jac=BayesianLogisticRegression()._jac,)
theta_star = res.x
# 計算拉普拉斯近似的Hessian
H = BayesianLogisticRegression()._hess(theta_star, X, y, m_vec, p_vec)
# 損失
loss = 0
# 前兩項:對數損失和正則化項
loss += baysian_model._loss(theta_star, X, y, m_vec, p_vec)
# 第三項:sigma的先驗分佈,這裡寫為p
out -= gamma.logpdf(p, a=alpha, scale=1/beta)
# 第四項:拉普拉斯近似的最後一項
out += 0.5 * np.linalg.slogdet(H)[1] - 0.5 * n_feat * np.log(2 * np.pi)
return out
在我的使用案例中,我選擇通過Adam優化器來優化它,該代碼來自這個repo。
def adam(fun, x0, jac, args=(), learning_rate=0.001, beta1=0.9, beta2=0.999, eps=1e-8, startiter=0, maxiter=1000, callback=None, **kwargs):
"""``scipy.optimize.minimize``相容的ADAM實現 - [http://arxiv.org/pdf/1412.6980.pdf]。
改編自``autograd/misc/optimizers.py``。"""
x = x0
m = np.zeros_like(x)
v = np.zeros_like(x)
for i in range(startiter, startiter + maxiter):
g = jac(x, *args)
if callback and callback(x):
break
m = (1 - beta1) * g + beta1 * m # 第一個動量估計
v = (1 - beta2) * (g**2) + beta2 * v # 第二個動量估計
mhat = m / (1 - beta1**(i + 1)) # 偏差修正
vhat = v / (1 - beta2**(i + 1))
x = x - learning_rate * mhat / (np.sqrt(vhat) + eps)
i += 1
return OptimizeResult(x=x, fun=fun(x, *args), jac=g, nit=i, nfev=i, success=True)
對於這次優化,我們需要前一個損失的導數。我們無法得到解析形式,所以我決定使用數值近似來計算導數。
一旦模型在訓練數據集上訓練完成,就需要在評估數據集上進行預測,以評估其性能並比較不同的模型。然而,無法直接計算新點的實際分佈,因為計算是不可行的。
可以用以下方式近似結果:
考慮到:
我對精度隨機變量選擇了一個無信息的先驗。天真的模型表現不佳,對數損失為0.60,AUC ROC為0.50。第二個模型表現更好,對數損失為0.44,AUC ROC為0.83,這兩者都是在使用網格搜尋和貝葉斯優化時超優化的。這表明,包含依賴變量的邏輯回歸模型優於天真的模型。然而,使用貝葉斯優化並沒有比網格搜尋更有優勢,所以我會繼續使用網格搜尋。謝謝你的閱讀。
……但等等,我在想。為什麼我的參數用相同的係數進行正則化?我的先驗不應該依賴於潛在的依賴變量嗎?也許第一個依賴變量的參數可以取更高的值,而第二個依賴變量的參數,由於影響較小,應該更接近於零。我們來探索這些新維度。
到目前為止,我們考慮了兩種技術,網格搜尋和貝葉斯優化。我們可以在更高的維度中使用這些相同的技術。
考慮新的維度可能會大幅增加我的網格的節點數量。因此,在高維度中,貝葉斯優化是有意義的,以獲得最佳的正則化係數。在考慮的使用案例中,我假設有三個正則化參數,每個自變量一個。在編碼單個變量後,我假設生成的新變量都共享相同的正則化參數。因此,總的正則化參數為三個,即使邏輯回歸的輸入列數超過三個。
我更新了之前的損失函數,代碼如下:
import numpy as np
from scipy.stats import gamma
from module.bayesian_model import BayesianLogisticRegression
def loss(p, X, y, alpha, beta, X_columns, col_to_p_id):
# 計算給定值的損失:
# - 1/sigma²向量(這裡稱為p,代表精度)
# - X:特徵矩陣
# - y:觀察向量
# - alpha:先驗伽馬分佈的alpha參數
# - beta:先驗伽馬分佈的beta參數
# - X_columns:X列的名稱列表
# - col_to_p_id:將列名稱映射到p索引的字典
# 因為許多列名稱可以共享相同的p值
n_feat = X.shape[1]
m_vec = np.array([0] * n_feat)
p_list = []
for col in X_columns:
p_list.append(p[col_to_p_id[col]])
p_vec = np.array(p_list)
# 計算theta*
res = minimize(BayesianLogisticRegression()._loss, np.array([0] * n_feat), args=(X, y, m_vec, p_vec), method="BFGS", jac=BayesianLogisticRegression()._jac,)
theta_star = res.x
# 計算拉普拉斯近似的Hessian
H = BayesianLogisticRegression()._hess(theta_star, X, y, m_vec, p_vec)
# 損失
loss = 0
# 前兩項:對數損失和正則化項
loss += baysian_model._loss(theta_star, X, y, m_vec, p_vec)
# 第三項:1/sigma²的先驗分佈,這裡寫為p
# 現在有一個總和,因為p現在是一個向量
out -= np.sum(gamma.logpdf(p, a=alpha, scale=1/beta))
# 第四項:拉普拉斯近似的最後一項
out += 0.5 * np.linalg.slogdet(H)[1] - 0.5 * n_feat * np.log(2 * np.pi)
return out
通過這種方法,在測試數據集上評估的指標如下:0.39和0.88,這比最初通過網格搜尋和貝葉斯方法優化的模型要好,該模型對所有自變量僅使用一個先驗。
這個使用案例可以通過這個筆記本重現。
我創建了一個例子來說明這個技術的有用性。然而,我還沒有找到合適的真實數據集來充分展示它的潛力。雖然我曾經在一個實際數據集上工作,但我無法從應用這個技術中獲得任何顯著的好處。如果你遇到一個,請告訴我——我會很高興看到這個正則化方法的真實應用。
總結來說,使用貝葉斯優化(如有需要,使用拉普拉斯近似)來確定最佳正則化參數可能是傳統超參數調整方法的一個良好替代方案。通過利用概率模型,貝葉斯優化不僅降低了計算成本,還提高了找到最佳正則化值的可能性,特別是在高維度中。
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!