Skip to content
Back to skills

Separate Pos Neg Dice Tracking

ASecurity

Track dice score separately for positive (mask-present) and negative (empty-mask) images to avoid division distortion

  • 61 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 12, 2026
datapythongo

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add wenmin-wu/ds-skills --skill separate-pos-neg-dice-tracking --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Separate Pos Neg Dice Tracking?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Separate Pos Neg Dice Tracking
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wenmin-wu-separate-pos-neg-dice-tracking/badge)](https://www.skillsdirectory.com/skills/wenmin-wu-separate-pos-neg-dice-tracking)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cv-separate-pos-neg-dice-tracking
description: Track dice score separately for positive (mask-present) and negative (empty-mask) images to avoid division distortion
---

## Overview

Standard dice metric breaks on empty masks: `2|A∩B|/(|A|+|B|) = 0/0`. Most datasets hack around this by adding a small epsilon, which distorts scores for negative images. A cleaner approach: track dice separately for positive and negative cases. For negative images, dice is simply 1 if the prediction is also empty, else 0. This gives interpretable per-category scores and reveals whether the model is failing on positives or leaking false positives on negatives.

## Quick Start

```python
import torch

def dice_metric_split(probability, truth, threshold=0.5):
    """Return (all_dice, dice_neg, dice_pos) — dice split by mask presence."""
    with torch.no_grad():
        p = (probability > threshold).float().view(len(truth), -1)
        t = (truth > 0.5).float().view(len(truth), -1)
        t_sum = t.sum(-1)
        p_sum = p.sum(-1)

        neg_idx = torch.nonzero(t_sum == 0).squeeze(-1)
        pos_idx = torch.nonzero(t_sum >= 1).squeeze(-1)

        # Negative: 1 if prediction is also empty, else 0
        dice_neg = (p_sum == 0).float()
        # Positive: standard dice
        dice_pos = 2 * (p * t).sum(-1) / ((p + t).sum(-1) + 1e-7)

        dice_neg = dice_neg[neg_idx]
        dice_pos = dice_pos[pos_idx]
    return torch.cat([dice_pos, dice_neg]), dice_neg, dice_pos
```

## Workflow

1. Binarize probability map with threshold
2. Split batch by ground-truth mask sum: zero → negative, positive → positive
3. For negatives, dice = 1 iff prediction sum is also zero (perfect empty prediction)
4. For positives, compute standard dice
5. Report both aggregates separately in logs — watch them diverge to diagnose failure modes

## Key Decisions

- **Negative definition**: Ground-truth sum == 0 (no mask pixels). Different from "negative predictions".
- **Per-image vs per-batch**: Compute per-image to avoid one large positive mask dominating the score.
- **Actionable signal**: If `dice_neg` drops, model is hallucinating masks on healthy images — add a classification gate. If `dice_pos` drops, improve segmentation directly.
- **vs. epsilon smoothing**: Epsilon hides the failure mode by giving fake dice=1 to empty pairs. Split tracking exposes it.

## References

- [UNet with ResNet34 encoder (Pytorch)](https://www.kaggle.com/code/rishabhiitbhu/unet-with-resnet34-encoder-pytorch)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.