Skip to content

feat(data): add degenerate sample detection and governance (#217) - #307

Open
HDM-xymm wants to merge 5 commits into
inclusionAI:mainfrom
HDM-xymm:feat/issue-217-degenerate-sample-governance
Open

feat(data): add degenerate sample detection and governance (#217)#307
HDM-xymm wants to merge 5 commits into
inclusionAI:mainfrom
HDM-xymm:feat/issue-217-degenerate-sample-governance

Conversation

@HDM-xymm

@HDM-xymm HDM-xymm commented Jul 28, 2026

Copy link
Copy Markdown

What does this PR do?

Add degenerate sample detection utilities in areno.api.data that identify empty, whitespace-only, special-token-only, no-trainable-token, and identical DPO preference branch samples. The detection is integrated into the SFT, DPO, and policy rollout paths with configurable SKIP/ERROR policy.

Key changes:

  • Add DegenerateReason, DegeneratePolicy, DegenerateFilterConfig, SampleQualityReport dataclasses and 6 check_* detection functions
  • Integrate detection into Trainer.load_prompt_batches, SFT, DPO, and PolicyOnly paths
  • Add --degenerate-policy CLI flag and trainer_config field
  • Add PromptBatch counters for skipped_degenerate and degenerate_reasons
  • Add 23 CPU-only unit tests (no GPU/tokenizer dependency)
  • Add user docs and design doc

Usage

Control degenerate sample handling via CLI:

#Default: silently skip degenerate samples with reason counters
areno train --ckpt Qwen/Qwen3.5-0.8B --degenerate-policy skip ...

#Fail fast: raise ValueError on the first degenerate sample
areno train --ckpt Qwen/Qwen3.5-0.8B --degenerate-policy error ...

Detection covers 5 categories across pre- and post-tokenization stages:

Reason Stage Example
empty pre-tokenization "" prompt or response
whitespace_only pre-tokenization " \n\t "
special_tokens_only post-tokenization all tokens are <|...|>
no_trainable_tokens post-tokenization every position is in the prompt prefix
identical_preference_branches pre-tokenization DPO chosen == rejected

Example output

With --degenerate-policy skip (default), degenerate rows are filtered and counted:

batch = trainer.load_prompt_batches(dataset, batch_size=4, max_prompt_tokens=512)
#batch.skipped_degenerate == 2
#batch.degenerate_reasons == {"empty": 1, "whitespace_only": 1}

With --degenerate-policy error, the first degenerate sample raises:

ValueError: degenerate sample detected (pre_tokenization): prompt is an empty string

Related issue

Fixes #217

Type of change

  • ✨ New feature

How was it tested?

pytest tests/test_degenerate_sample_cpu.py -v

23 CPU-only unit tests covering:

check_prompt_text — empty and whitespace-only prompt detection
check_response_text — empty and whitespace-only response detection
check_tokenized_prompt — zero-length and all-special-token detection
check_trainable_tokens — all-prompt-mask (no trainable token) detection
check_preference_pair — identical DPO chosen/rejected branch detection
apply_degenerate_policy — SKIP returns True, ERROR raises ValueError, disabled config passes through
record_degenerate_reason / format_degenerate_reasons — reason counting and formatting
No GPU or tokenizer dependency. Existing tests pass with default skip policy (backward-compatible).

Checklist

  • The PR title summarizes the contribution.
  • Linked the related issue in the description (if any).
  • Existing tests pass (pytest tests/ -k cpu).
  • New behavior is covered by tests.
  • Described the test commands run and any hardware limitations.
  • Public API / CLI changes are additive and backward-compatible (see CONTRIBUTING.md).

##Update
-Update (2026-08-24): Rebased onto latest main to resolve merge conflicts with the MLX backend and multimodal optimizer features. Fixed lint errors (unused variable, import ordering, formatting) and
updated test mocks to include the new degenerate_policy field and degenerate_filter_config() method.

@HDM-xymm
HDM-xymm force-pushed the feat/issue-217-degenerate-sample-governance branch from a6e7a97 to 7f0eb23 Compare July 28, 2026 08:44
xiajin.lcy and others added 4 commits August 21, 2026 15:16
…AI#217)

Add degenerate sample detection utilities in areno.api.data that identify
empty, whitespace-only, special-token-only, no-trainable-token, and
identical DPO preference branch samples. Integrate detection into the
SFT, DPO, and policy rollout paths with configurable SKIP/ERROR policy.

- Add DegenerateReason, DegeneratePolicy, DegenerateFilterConfig,
  SampleQualityReport dataclasses and 6 check_* detection functions
- Integrate into Trainer.load_prompt_batches, SFT, DPO, and PolicyOnly paths
- Add --degenerate-policy CLI flag and trainer_config field
- Add PromptBatch counters for skipped_degenerate and degenerate_reasons
- Add 23 CPU-only unit tests (no GPU/tokenizer dependency)
- Add user docs and design doc for issue inclusionAI#217
- Remove unused check_response_text import from DPO trainer
- Simplify _make_sequence trainable token check to avoid redundant any() call
- Add comment explaining backward-compatible empty response check in SFT
- Fix missing trailing newline in cli/train.py
- Collapse record_degenerate_reason signature to single line
- Rebase onto latest main (4f908e7) with proper conflict resolution
- Fix indentation errors in trainer_config.py from merge
- Add degenerate_policy='skip' to test SimpleNamespace mocks
- Add degenerate_filter_config() to SFT test config mock
- Remove unused skipped_degenerate variable in sft.py
- Fix missing trailing newline in __init__.py
- Preserve main's backend_config/cuda_config/mlx_config API alongside
  degenerate_filter_config
@HDM-xymm
HDM-xymm force-pushed the feat/issue-217-degenerate-sample-governance branch from 60b2693 to ade342d Compare August 24, 2026 03:30
HDM-xymm pushed a commit to HDM-xymm/AReno that referenced this pull request Aug 28, 2026
Merge upstream/main into feat/issue-217-degenerate-sample-governance.

Conflict resolutions (3 files, 8 conflicts):
- areno/api/__init__.py: keep both LoraConfig (upstream) and
  DegenerateFilterConfig/DegeneratePolicy/DegenerateReason (PR)
- areno/api/trainer_config.py: keep both degenerate_policy field (PR)
  and lora/reference_mode fields (upstream)
- areno/cli/train.py: keep both degenerate_policy CLI option (PR)
  and lora/reference_mode CLI options (upstream); restore missing
  optimizer_state_offload getattr defaults
Merge upstream/main into feat/issue-217-degenerate-sample-governance.

Conflict resolutions (3 files, 8 conflicts):
- areno/api/__init__.py: keep both LoraConfig (upstream) and
  DegenerateFilterConfig/DegeneratePolicy/DegenerateReason (PR)
- areno/api/trainer_config.py: keep both degenerate_policy field (PR)
  and lora/reference_mode fields (upstream)
- areno/cli/train.py: keep both degenerate_policy CLI option (PR)
  and lora/reference_mode CLI options (upstream); restore missing
  optimizer_state_offload getattr defaults
@HDM-xymm
HDM-xymm force-pushed the feat/issue-217-degenerate-sample-governance branch from a5b14db to baaad9e Compare August 28, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Handle empty and degenerate training samples consistently

1 participant