feat(ml): training hygiene — system-tagged images are absent from other concepts training
Step 2 of milestone #128. _hygiene_excluded_ids (training_data.py) is the one shared predicate: images carrying any system tag are dropped from every OTHER concepts head training — not positives (a rough wip tagged as a character drags the head toward generic-sketch) and not rejection or sampled negatives (a wip OF character X is not evidence against X). A system tags own head trains on them unfiltered; that is what makes auto-flagging banners work. Selection is split out of train_head as the sklearn-free head_training_ids so CI (no sklearn) can pin the behavior. CCIP: reference prototypes skip hygiene-tagged images — a faceless wip figure region must never become an identity reference — and the ref cache signature now counts hygiene applications, since tagging an image wip changes the reference set without touching character/region counts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
@@ -62,6 +62,18 @@ def _single_character_images():
|
||||
)
|
||||
|
||||
|
||||
def _hygiene_tagged_images():
|
||||
"""Subquery of image ids carrying any SYSTEM tag (wip / banner / editor
|
||||
screenshot). Training hygiene (#128): such images never contribute
|
||||
reference prototypes — a faceless wip's figure region would otherwise
|
||||
become an identity reference for the character it's tagged with."""
|
||||
return (
|
||||
select(image_tag.c.image_record_id)
|
||||
.join(Tag, Tag.id == image_tag.c.tag_id)
|
||||
.where(Tag.is_system.is_(True))
|
||||
)
|
||||
|
||||
|
||||
async def _ref_signature(session: AsyncSession) -> tuple:
|
||||
n_tags = (
|
||||
await session.execute(
|
||||
@@ -79,7 +91,17 @@ async def _ref_signature(session: AsyncSession) -> tuple:
|
||||
)
|
||||
)
|
||||
).one()
|
||||
return (n_tags, n_regs, max_id)
|
||||
# Hygiene applications must invalidate too: tagging an image `wip` changes
|
||||
# the reference set without touching character-tag or region counts.
|
||||
n_hygiene = (
|
||||
await session.execute(
|
||||
select(func.count())
|
||||
.select_from(image_tag)
|
||||
.join(Tag, Tag.id == image_tag.c.tag_id)
|
||||
.where(Tag.is_system.is_(True))
|
||||
)
|
||||
).scalar_one()
|
||||
return (n_tags, n_regs, max_id, n_hygiene)
|
||||
|
||||
|
||||
async def character_references(session: AsyncSession) -> dict[int, list]:
|
||||
@@ -102,6 +124,9 @@ async def character_references(session: AsyncSession) -> dict[int, list]:
|
||||
.where(ImageRegion.kind.in_(_FIGURE_KINDS))
|
||||
.where(ImageRegion.ccip_embedding.is_not(None))
|
||||
.where(ImageRegion.image_record_id.in_(_single_character_images()))
|
||||
.where(
|
||||
ImageRegion.image_record_id.not_in(_hygiene_tagged_images())
|
||||
)
|
||||
)
|
||||
).all()
|
||||
refs: dict[int, list] = {}
|
||||
|
||||
Reference in New Issue
Block a user