PyTorch回归任务中如何获取预测值的概率分布?
回归任务中获取预测值概率分布的PyTorch实现方法
当然有,回归任务里可以通过建模预测值的概率分布来获取类似分类任务的置信度信息,以下是两种在PyTorch中常用的实现方式:
1. 建模高斯分布(最通用的方法)
回归任务中最常见的做法是假设预测值服从高斯分布,让模型同时输出分布的均值μ和标准差σ(或方差)。这样你就能基于这两个参数得到任意预测值的概率密度,也能计算置信区间来衡量模型的置信度。
实现逻辑:
- 模型最后一层输出两个值:μ(预测的中心值)和对数方差
log_var(避免直接输出方差为负,后续通过指数转换得到非负的标准差)。 - 使用**负对数似然(NLL)**作为损失函数,让模型拟合数据的同时学习不确定性。
PyTorch代码示例:
import torch import torch.nn as nn import torch.optim as optim # 定义输出高斯分布参数的回归模型 class GaussianRegressionModel(nn.Module): def __init__(self, input_dim): super().__init__() self.fc = nn.Sequential( nn.Linear(input_dim, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU(), # 输出均值mu和对数方差log_var nn.Linear(32, 2) ) def forward(self, x): output = self.fc(x) mu = output[:, 0] log_var = output[:, 1] # 从对数方差转换为标准差(保证非负) sigma = torch.exp(0.5 * log_var) return mu, sigma # 高斯分布负对数似然损失 def gaussian_nll_loss(mu, sigma, target): loss = 0.5 * torch.log(2 * torch.pi * sigma**2) + (target - mu)**2 / (2 * sigma**2) return loss.mean() # 训练流程示例 input_dim = 5 model = GaussianRegressionModel(input_dim) optimizer = optim.Adam(model.parameters(), lr=1e-3) # 模拟输入和目标数据 x = torch.randn(32, input_dim) y = torch.randn(32) model.train() for epoch in range(100): optimizer.zero_grad() mu, sigma = model(x) loss = gaussian_nll_loss(mu, sigma, y) loss.backward() optimizer.step() # 预测时获取分布参数与置信区间 model.eval() with torch.no_grad(): pred_mu, pred_sigma = model(x) # 计算95%置信区间:均值 ± 1.96*标准差 lower_bound = pred_mu - 1.96 * pred_sigma upper_bound = pred_mu + 1.96 * pred_sigma
2. 分位数回归(非参数化分布估计)
如果不想假设预测值服从高斯分布,或者需要关注特定分位数的置信区间,可以用分位数回归。模型输出多个分位数(比如0.025、0.5、0.975),通过分位数损失(pinball loss)训练,最终得到不同分位数下的预测值,以此构建置信区间或近似概率分布。
实现逻辑:
- 模型最后一层输出对应分位数的预测值数量(比如3个对应低、中、高分位数)。
- 使用pinball loss作为损失函数,针对每个分位数计算损失并求和。
PyTorch代码示例:
class QuantileRegressionModel(nn.Module): def __init__(self, input_dim, quantiles=[0.025, 0.5, 0.975]): super().__init__() self.quantiles = quantiles self.fc = nn.Sequential( nn.Linear(input_dim, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU(), # 输出对应分位数的预测值 nn.Linear(32, len(quantiles)) ) def forward(self, x): return self.fc(x) # 分位数损失(pinball loss) def pinball_loss(preds, target, quantiles): losses = [] for i, q in enumerate(quantiles): error = target - preds[:, i] # 分位数损失核心逻辑:根据误差正负加权 loss = torch.max(q * error, (q - 1) * error) losses.append(loss.mean()) return sum(losses) # 训练流程示例 input_dim = 5 quantiles = [0.025, 0.5, 0.975] model = QuantileRegressionModel(input_dim, quantiles) optimizer = optim.Adam(model.parameters(), lr=1e-3) x = torch.randn(32, input_dim) y = torch.randn(32) model.train() for epoch in range(100): optimizer.zero_grad() preds = model(x) loss = pinball_loss(preds, y, quantiles) loss.backward() optimizer.step() # 预测时获取各分位数的预测值 model.eval() with torch.no_grad(): quantile_preds = model(x) # 0.5分位数对应中位数预测,0.025和0.975对应95%置信区间 median_pred = quantile_preds[:, 1] lower_bound = quantile_preds[:, 0] upper_bound = quantile_preds[:, 2]
内容的提问来源于stack exchange,提问作者Erik Storm
相关产品推荐
相关产品推荐

