blinklinmult.train.losses¶
Masked binary losses for partially-annotated blink supervision.
Every loss here takes a validity mask alongside its target and reduces over the
valid positions only. That is not an optimisation — it is what makes joint
training across the six corpora correct. A sample drawn from CEW carries an
all-False blink_presence mask and a placeholder target; reducing over it
with an unmasked BCEWithLogitsLoss would train the blink head to predict the
placeholder on every still image in the corpus, which is the single most likely
way to get a plausible-looking run that has quietly learned the wrong thing.
Reduction. The mean is taken over valid positions, so a batch’s loss does not depend on how many of its samples happened to come from a corpus that annotates the target. A batch with no valid position for a target contributes exactly zero to that head — with the gradient path preserved, so DDP does not deadlock waiting for a rank that skipped a parameter.
Logits, not probabilities. All losses consume raw logits and apply their own
sigmoid where needed. Applying a sigmoid in the model and a log here would
lose the numerically-stable fused implementation for no benefit.
Attributes¶
Guards division when a batch has no valid position for a target. |
|
Focusing parameter from the focal-loss paper. |
|
Positive-class weight from the focal-loss paper. |
Exceptions¶
Raised when a loss is misconfigured or given inconsistent shapes. |
Classes¶
A masked binary loss as a configurable module. |
Functions¶
|
Binary cross-entropy over valid positions. |
|
Focal loss over valid positions. |
|
Soft Dice loss over valid positions. |
|
Sum of |
|
Construct a loss by config name. |
|
Penalise frame-to-frame jumps in the predicted eye-state signal. |
|
Penalise predicted closures far outside a plausible blink duration. |
Module Contents¶
- blinklinmult.train.losses.EPSILON = 1e-08¶
Guards division when a batch has no valid position for a target.
- blinklinmult.train.losses.DEFAULT_FOCAL_GAMMA = 2.0¶
Focusing parameter from the focal-loss paper.
- blinklinmult.train.losses.DEFAULT_FOCAL_ALPHA = 0.25¶
Positive-class weight from the focal-loss paper.
Blink frames are the minority class in a continuously-sampled recording — a blink occupies a few frames per several seconds — so a class-balancing term is the default rather than an option.
- exception blinklinmult.train.losses.LossError¶
Bases:
ValueErrorRaised when a loss is misconfigured or given inconsistent shapes.
Initialize self. See help(type(self)) for accurate signature.
- blinklinmult.train.losses.masked_bce(logits: torch.Tensor, target: torch.Tensor, mask: torch.Tensor) torch.Tensor¶
Binary cross-entropy over valid positions.
- Parameters:
logits (torch.Tensor) – Raw predictions, any shape.
target (torch.Tensor) – Binary targets, same shape.
mask (torch.Tensor) –
Truewhere the target is real supervision.
- Returns:
Scalar loss.
- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree.
- blinklinmult.train.losses.masked_focal(logits: torch.Tensor, target: torch.Tensor, mask: torch.Tensor, gamma: float = DEFAULT_FOCAL_GAMMA, alpha: float = DEFAULT_FOCAL_ALPHA) torch.Tensor¶
Focal loss over valid positions.
Down-weights positions the model already classifies confidently, which matters for blink presence: sampled continuously, the overwhelming majority of frames are easy negatives, and their aggregate gradient drowns out the few frames where the eye is actually closing.
- Parameters:
logits (torch.Tensor) – Raw predictions.
target (torch.Tensor) – Binary targets.
mask (torch.Tensor) –
Truewhere the target is real supervision.gamma (float) – Focusing parameter;
0reduces this to weighted BCE.alpha (float) – Positive-class weight in
[0, 1].
- Returns:
Scalar loss.
- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree or a parameter is out of range.
- blinklinmult.train.losses.masked_dice(logits: torch.Tensor, target: torch.Tensor, mask: torch.Tensor) torch.Tensor¶
Soft Dice loss over valid positions.
Dice optimises overlap rather than per-position accuracy, so it is far less sensitive to the positive/negative imbalance of a blink sequence than cross-entropy is. Used as the second term of
masked_dice_bce().- Parameters:
logits (torch.Tensor) – Raw predictions.
target (torch.Tensor) – Binary targets.
mask (torch.Tensor) –
Truewhere the target is real supervision.
- Returns:
Scalar loss in
[0, 1].- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree.
- blinklinmult.train.losses.masked_dice_bce(logits: torch.Tensor, target: torch.Tensor, mask: torch.Tensor, dice_weight: float = 0.5) torch.Tensor¶
Sum of
masked_bce()and a weightedmasked_dice().- Parameters:
logits (torch.Tensor) – Raw predictions.
target (torch.Tensor) – Binary targets.
mask (torch.Tensor) –
Truewhere the target is real supervision.dice_weight (float) – Weight of the Dice term.
- Returns:
Scalar loss.
- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree or the weight is negative.
- class blinklinmult.train.losses.MaskedLoss(name: str, **kwargs)¶
Bases:
torch.nn.ModuleA masked binary loss as a configurable module.
- Parameters:
name (str) – One of
"bce","focal","dice_bce".**kwargs – Loss-specific arguments, forwarded to the underlying function.
- Raises:
LossError – If the name is unknown or an argument is not accepted.
- forward(logits: torch.Tensor, target: torch.Tensor, mask: torch.Tensor) torch.Tensor¶
Compute the loss.
- Parameters:
logits (torch.Tensor) – Raw predictions.
target (torch.Tensor) – Binary targets.
mask (torch.Tensor) –
Truewhere the target is real supervision.
- Returns:
Scalar loss.
- Return type:
torch.Tensor
- blinklinmult.train.losses.build_loss(name: str, **kwargs) MaskedLoss¶
Construct a loss by config name.
- Parameters:
name (str) – Loss name.
**kwargs – Loss-specific arguments.
- Returns:
The loss module.
- Return type:
- Raises:
LossError – If the name is unknown.
- blinklinmult.train.losses.temporal_smoothness(logits: torch.Tensor, mask: torch.Tensor, margin: float = 0.0) torch.Tensor¶
Penalise frame-to-frame jumps in the predicted eye-state signal.
A blink is continuous motion – the lid closes over several frames and reopens over several more – so the signal that describes it should not chatter. Independent per-frame predictions have no reason to be smooth, and a jagged signal is what makes interval extraction brittle: every spurious crossing of the operating point becomes a spurious event boundary.
Needs no annotation, so it applies to every corpus including those that label only blink presence, or nothing at all.
- Parameters:
logits (torch.Tensor) –
(B, T)raw predictions.mask (torch.Tensor) –
(B, T)Truewhere the frame is valid.margin (float) – Jumps at or below this are free, so a genuine closure is not penalised for being fast.
0.0penalises every jump.
- Returns:
Scalar; zero when fewer than two valid adjacent frames exist, which is the still-image case.
- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree or the input is not
(B, T).
- blinklinmult.train.losses.duration_prior(logits: torch.Tensor, mask: torch.Tensor, threshold: float = 0.5, min_frames: float = 3.0, max_frames: float = 12.0) torch.Tensor¶
Penalise predicted closures far outside a plausible blink duration.
A human blink lasts roughly 100-400 ms, which at 30 fps is about 3-12 frames. A model firing on one isolated frame, or holding a closure for seconds, is producing something that is not a blink whatever the frame-wise loss says.
Applied as a soft count of above-threshold frames per window rather than by extracting intervals, so it stays differentiable. That makes it a prior on how much of a window is closed, not a hard constraint on any one event – the honest reading, since a window may legitimately contain two blinks.
Needs no annotation.
- Parameters:
logits (torch.Tensor) –
(B, T)raw predictions.mask (torch.Tensor) –
(B, T)validity.threshold (float) – Probability above which a frame counts as closed.
min_frames (float) – Below this, a window’s closure is implausibly short.
max_frames (float) – Above this, implausibly long.
- Returns:
Scalar; zero when the window holds no valid frame, and zero for any window whose soft count already lies in range.
- Return type:
torch.Tensor
- Raises:
LossError – If the shapes disagree or the bounds are inverted.