神經(jīng)網(wǎng)絡(luò)中的分位數(shù)回歸和分位數(shù)損失
在使用機器學(xué)習(xí)構(gòu)建預(yù)測模型時,我們不只是想知道“預(yù)測值(點預(yù)測)”,而是想知道“預(yù)測值落在某個范圍內(nèi)的可能性有多大(區(qū)間預(yù)測)”。例如當(dāng)需要進行需求預(yù)測時,如果只儲備最可能的需求預(yù)測量,那么缺貨的概率非常的大。但是如果庫存處于預(yù)測的第95個百分位數(shù)(需求有95%的可能性小于或等于該值),那么缺貨數(shù)量會減少到大約20分之1。
獲得這些百分位數(shù)值的機器學(xué)習(xí)方法有:
- scikit-learn:GradientBoostingRegressor(loss='quantile, alpha=alpha)
- LightGBM: LGBMRegressor(objective='quantile', alpha=alpha)
- XGBoost: XGBoostRegressor(objective='reg:quantileerror', quantile_alpha=alpha) (version 2.0~)
這種”預(yù)測值落在某個范圍內(nèi)的可能性有多大(區(qū)間預(yù)測)”的方法都被稱作分位數(shù)回歸,上面的這些機器學(xué)習(xí)的方法是用了一種叫做Quantile Loss的損失。
Quantile loss是用于評估分位數(shù)回歸模型性能的一種損失函數(shù)。在分位數(shù)回歸中,我們不僅關(guān)注預(yù)測的中心趨勢(如均值),還關(guān)注在分布的不同分位數(shù)處的預(yù)測準(zhǔn)確性。Quantile loss允許我們根據(jù)所關(guān)注的分位數(shù)來量化預(yù)測的不確定性。
假設(shè)我們有一個預(yù)測問題,其中我們要預(yù)測一個連續(xù)型變量的分布,并且我們關(guān)注不同的分位數(shù),例如中位數(shù)、0.25分位數(shù)、0.75分位數(shù)等。對于第q分位數(shù),Quantile Loss定義為:
這里:
- yy 是真實值。
- yy 是模型的預(yù)測值。
- qq 是目標(biāo)分位數(shù),取值范圍為0,10,1。
這個損失函數(shù)的核心思想是,當(dāng)模型的預(yù)測值超過真實值時,損失是預(yù)測值與真實值的差值乘以q。當(dāng)預(yù)測值低于真實值時,損失是預(yù)測值與真實值的差值乘以1?q。這確保了對于不同的分位數(shù),我們有不同的懲罰。如果我們更關(guān)心較小分位數(shù)(例如,中位數(shù)),我們會設(shè)定較小的q,反之亦然。
用Pytorch實現(xiàn)分位數(shù)損失
下面是一個使用Pytorch將分位數(shù)損失定義為自定義損失函數(shù)的示例。
import torch
def quantile_loss(y_true, y_pred, quantile):
errors = y_true - y_pred
loss = torch.mean(torch.max((quantile - 1) * errors, quantile * errors))
return loss
對于訓(xùn)練來說,跟正常的訓(xùn)練方法一樣:
for epoch in range(num_epochs):
for batch_x, batch_y in dataloader:
optimizer.zero_grad()
outputs = model(batch_x)
loss = quantile_loss(outputs, batch_y, quantile)
loss.backward()
optimizer.step()
讓我們看看這個自定義的損失函數(shù)是否如預(yù)期的那樣工作。
Pytorch分位數(shù)損失測試
首先,我們嘗試為x生成均勻隨機分布(-5~5),為y生成與x指數(shù)成比例的正態(tài)隨機分布,看看是否可以從x預(yù)測y的分位數(shù)點。
# Generate dummy data
num_samples = 10000
shape = (num_samples, 1)
torch.manual_seed(0)
# x is uniform random from -5 to 5
# y is random normal distribution * exp(scaled x)
x_tensor = torch.rand(shape) * 10 - 5
x_scaled = x_tensor / 5
y_tensor = torch.randn(shape) * torch.exp(x_scaled)
# Convert values to NumPy array (for graphs)
x = x_tensor.numpy()
y = y_tensor.numpy()
網(wǎng)絡(luò)結(jié)構(gòu)很簡單,兩個中間層64個節(jié)點+每層relu。在沒有任何正則化或提前停止的情況下使用100次epoch。待預(yù)測的四分位數(shù)(百分位數(shù))在列中為[0.500,0.700,0.950,0.990,0.995],在行中為批大小[1,4,16,64,256],總共有25個預(yù)測。在10,000個訓(xùn)練數(shù)據(jù)實例(藍色)中,低于預(yù)測輸出值(紅色)的實例的比率在圖中被標(biāo)記為“實際”值。
低于指定百分位數(shù)值的樣本百分比通常接近指定值,并且輸出分位數(shù)預(yù)測的是非常直接的。
再考慮一個稍微復(fù)雜的例子,其中y=clip(x, - 2,2) + randn。其中clip(x, - 2,2)是剪輯函數(shù)(將值限制在指定范圍內(nèi))。當(dāng)數(shù)字超出給定范圍時,該函數(shù)將其限制到最近的邊界(如果將范圍設(shè)置為-2到2,并輸入-5的輸入值,該函數(shù)將返回-2;如果輸入10,它將返回2),而randn是遵循正態(tài)分布的隨機數(shù)。網(wǎng)絡(luò)結(jié)構(gòu)和其他設(shè)置與前一種情況相同。
與前一種情況一樣,低于指定百分位數(shù)值的樣本百分比通常接近指定值。分位數(shù)預(yù)測的理想形狀總是左上角圖中紅線的形狀。它應(yīng)該隨著指定的百分位數(shù)的增加而平行向上移動。當(dāng)移動到圖的右下方時,預(yù)測的紅線呈現(xiàn)出更線性的形狀,這不是一個理想的結(jié)果。
讓我們用一個更復(fù)雜的形狀,我們的目標(biāo)是y=2sin(x) + randn。其他設(shè)置與前一種情況相同。
可以看到低于指定百分位數(shù)值的樣本百分比通常接近指定值。當(dāng)向5x5圖的右下方移動時,分位數(shù)預(yù)測的形狀偏離了正弦形狀。在圖的右下方,預(yù)測值的紅線變得更加線性。
如何選擇Q
我們看到,如果設(shè)置過高的quantile,會得到扁平化的值,那么如何判斷使用Quantile Loss得到的結(jié)果是否“扁平”,如何“避免扁平呢”?
檢測“扁平化”的方法之一是一起計算第50、68和95個百分位值,并檢查這些值之間的關(guān)系,即使要獲得的最終值是99.5百分位值。如果樣本分布服從正態(tài)分布,以μ為均值,σ為標(biāo)準(zhǔn)差
在μ±σ區(qū)間內(nèi)的概率約為68;在μ±2σ區(qū)間內(nèi)的概率約為95;在μ±3σ區(qū)間內(nèi)的概率約為99.7
如果第68百分位-第50百分位、第95百分位-第50百分位和99.5百分位-第50百分位值的比值明顯偏離1:2:3,我們可以確定偏離的百分位值已經(jīng)“變平”。
避免扁平化”的第一種方法是減少批量大小,如上面的實驗所示。較小的批量大小避免了這個問題,并且不太可能產(chǎn)生平坦的預(yù)測。但是減少批大小也有缺點,比如收斂不穩(wěn)定和增加訓(xùn)練時間,所以它只是有時一個容易采用的選擇。
第二種方法是在同一批次中收集相似的樣本,而不是隨機生成批次。這避免了“在批內(nèi)低于和高于預(yù)測值的樣本比例與指定的百分位數(shù)值之間的平衡”。
最后"扁平化"是無法避免的,我們只能進行緩解,下列符號用于下列方程。
- P0:第50個百分位值
- P1:第68個百分位值
- P2:第95百分位值
- P3: 99.5百分位值
使用上述變量,可以使用以下流程圖獲得適當(dāng)?shù)?9.5%百分位數(shù)值。
總結(jié)
分位數(shù)回歸是一種強大的統(tǒng)計工具,對于那些關(guān)注數(shù)據(jù)分布中不同區(qū)域的問題,以及需要更加靈活建模的情況,都是一種有價值的方法。
本文將介紹了在神經(jīng)網(wǎng)絡(luò)種自定義損失實現(xiàn)分位數(shù)回歸,并且介紹了如何檢測和緩解預(yù)測結(jié)果的"扁平化"問題。Quantile loss在一些應(yīng)用中很有用,特別是在金融領(lǐng)域的風(fēng)險管理問題中,因為它提供了一個在不同分位數(shù)下評估模型性能的方法。