This commit is contained in:
Alex Blank
2025-05-19 13:59:16 +02:00
parent 426f4d6963
commit c6defa2065
196 changed files with 18625 additions and 1 deletions
+118
View File
@@ -0,0 +1,118 @@
import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
class QuantileLoss(nn.Module):
def __init__(self, config):
super().__init__()
self.register_buffer('q', torch.tensor(config.quantiles))
def forward(self, predictions, targets):
diff = predictions - targets.unsqueeze(-1).expand(-1, -1, -1, predictions.shape[-1])
ql = (1 - self.q) * F.relu(diff) + self.q * F.relu(-diff)
losses = ql.view(-1, ql.shape[-1]).mean(0)
return losses
def qrisk(pred, tgt, quantiles):
diff = pred - tgt
ql = (1 - quantiles) * np.clip(diff, 0, float('inf')) + quantiles * np.clip(-diff, 0, float('inf'))
losses = ql.reshape(-1, ql.shape[-1])
normalizer = np.abs(tgt).mean()
risk = 2 * losses / normalizer
return risk.mean(0)
def weighted_bce_loss_fn():
bce = nn.BCEWithLogitsLoss(reduction="none") # Use reduction="none" to get per-element loss
use_class_weights = False
time_weight_factor = 1
def _loss_fn(y_pred, y_true):
loss_list = [] # To accumulate per-sample loss values
for i in range(len(y_pred)):
current_pred = y_pred[i]
current_true = y_true[i]
loss_raw = bce(current_pred, current_true)
if use_class_weights:
# Calculate class weights using torch operations
try:
factor = torch.max(current_true) / torch.mean(current_true) / 2
non_zero_indices = current_true != 0
class_weights = torch.ones_like(current_pred)
class_weights[non_zero_indices] = factor
except Exception:
class_weights = torch.ones_like(current_pred)
else:
class_weights = torch.ones_like(current_pred)
# Calculate time weights using torch operations
try:
# Find indices where the event occurs
event_indices = torch.where(current_true == 1)[0]
if len(event_indices) > 0:
first_event_index = event_indices[0].item()
time_weights = torch.ones_like(current_pred)
# Weight the loss before the first event higher if needed
time_weights[:first_event_index] = time_weight_factor
else:
time_weights = torch.ones_like(current_pred)
except Exception:
time_weights = torch.ones_like(current_pred)
# Apply the weights to the raw loss
loss = loss_raw * class_weights * time_weights
# Optionally, take the mean over the time dimension
loss_list.append(loss.mean())
# Aggregate the loss for the entire batch
return torch.stack(loss_list).mean()
return _loss_fn
def weighted_mse_prob_loss_fn():
mse = nn.MSELoss(reduce=False)
after_event_factor = 1
use_weighted = False
def _loss_fn(y_pred, y_true):
nonlocal mse, after_event_factor
loss_list = list()
for i in range(len(y_pred)):
current_pred = y_pred[i]
current_true = y_true[i]
loss_raw = mse(current_pred, current_true)
# calculate factor to use for weighting, only works with probability values
if use_weighted:
try:
factor = torch.max(current_true) / torch.mean(current_true) / 2
non_zero_indices = current_true != 0
class_weights = np.ones(len(current_true))
class_weights[non_zero_indices] = factor
except:
# if there are no non-zero indices, set all weights to 1
class_weights = np.ones(len(current_true))
else:
# if we don't want to weight the loss, set all weights to 1
class_weights = np.ones(len(current_true))
# calculate time weight, here, after the event, the loss should be higher
try:
last_event_index = np.where(current_true != 0)[-1]
time_weights = np.zeros(len(current_true))
# here, we want to weight the loss after the 'fertility curve' higher, so that we don't get the signal too late
time_weights[last_event_index:] = after_event_factor
except:
# if there are no non-zero indices, set all weights to 1
time_weights = np.ones(len(current_true))
loss = loss_raw * torch.tensor(class_weights) * torch.tensor(time_weights)
loss_list.append(loss.mean())
return torch.stack(loss_list).mean()
return _loss_fn