feat: PALETTE, composed from swappable partitioning blocks - #74
Open
Hendrik-code wants to merge 1 commit into
Open
Hendrik-code wants to merge 1 commit into
Hendrik-code wants to merge 1 commit into
Conversation
`RandomPaletteGPU` hard-codes one composition -- 1-D K-means, then Voronoi, then a per-region affine remap. `PaletteSynthesisGPU` takes that apart: the initial partitioner builds a region map from the raw intensities, each refinement subdivides the map it is handed, and the remap stays fixed, because that is the part the augmentation is named after. At its defaults it is `RandomPaletteGPU`; the point is the compositions that are not -- EM/GMM instead of K-means, several refinements in a row, or no spatial subdivision at all. `RandomPaletteGPU` is left exactly as it is. It is the composition every shipped config names, and rewriting it in terms of these blocks would put a refactor in the way of reading what the published experiments ran. Rebased onto the registry stack (#67-#71), which changed how this hooks in: * the class registers itself rather than being appended by an `if` ladder, so the ladder edit this used to carry is gone. It gets its own `AugId` rather than sharing `PALETTE`, because two entries on one concept would silently overwrite each other's cell in the coverage matrix; * `build_palette_from_cfg` is gone with the ladder that called it. The registry builds a transform by calling its constructor with the config block, so the constructor takes the nested blocks directly -- as dicts from a config, or as instances from a test. `factory.py` keeps the part the registry cannot do: signature validation cannot look inside a block whose shape depends on its own `type` field; * every parameter is named, and there are defaults throughout, because the registry rejects `**kwargs` and requires a GPU entry to be constructible; * `random.choice` for the blur sigmas becomes `shared_choice`, the fix from `smauglab/transforms/rng.py`: `torch.manual_seed` does not reach Python's `random`, and DDP ranks would each pick their own sigma. The overlay's entry point is `remap_labels`, not `apply`: `nn.Module.apply` already means "run this over every submodule", and shadowing it broke `.apply(fn)` on any pipeline containing one. Tests cover what is actually new -- that a config picks the blocks, that a nonsensical pick fails at construction with the fix in the message, and that every block hands the remap the contiguous region ids it indexes with, which the EM blocks do not produce on their own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #45, ported onto the registry stack (#67 → #71). #45 is left as it is until this one is reviewed.
What this adds
RandomPaletteGPUhard-codes one composition — 1-D K-means, then Voronoi, then a per-region affine remap.PaletteSynthesisGPUtakes that apart:initial_partitionerkmeans1d,em_gmmrefinement_partitioners(a list, applied in order)voronoi,em_gmm,identityoverlayblend_strengthknobThe remap itself stays fixed — it is the part the augmentation is named after. At its defaults the class is
RandomPaletteGPU; the point is the compositions that are not, such as EM/GMM instead of K-means, or several refinements in a row.RandomPaletteGPUis left exactly as it is. It is the composition every shipped config names, and rewriting it in terms of these blocks would put a refactor in the way of reading what the published experiments ran.Why this is a port and not a rebase
#45 branched before the
auglab→smauglabrename and edited theifladder ingpu/transforms.py, which #70 deleted. The rebase touched every hook-up point:AugId(palette_composed) rather than sharingPALETTE— two entries on one concept silently overwrite each other's cell inmatrix();build_palette_from_cfgis gone with the ladder that called it.build.pybuilds a transform by calling its constructor with the config block, so the constructor now takes the nested blocks directly — dicts from a config, instances from a test.factory.pykeeps the part the registry cannot do: signature-derived validation cannot look inside a block whose shape depends on its owntypefield;**kwargs(test_no_registered_class_hides_parameters_behind_kwargs) and requires a GPU entry to be constructible with none (test_constructible_with_declared_defaults);random.choicefor the blur sigmas becomesshared_choice— the fix fromtransforms/rng.py, sincetorch.manual_seeddoes not reach Python'srandomand DDP ranks would each pick their own sigma.Two bugs from #45 fixed along the way:
remap_labels, notapply.nn.Module.applyalready means "run this over every submodule", so.apply(fn)was broken on any pipeline containing one — mypy caught it.parent * mult + assignids, which are sparse; the remap indexes length-Rtensors with them._densify_region_idsmakes them contiguous, and a test pins it for every block.Migration
PaletteSynthesisTransformstays inDEAD_KEYS: the class only ever existed on thepalette-refactorbranch, so a config carrying that key never ran it, and turning it on during migration would start running an augmentation the config never ran. The dropped-key note now namesPaletteSynthesisGPUand says what to rename. This also keepslegacy_effective_kwargs.jsonhonest as captured evidence that the registry builds what the ladders built.Tests
unit_tests/test_palette_blocks.pycovers what is new — that a config picks the blocks, that a nonsensical pick fails at construction with the fix in the message (voronoiin the initial slot, an unknown type, a block without atype), that region ids stay contiguous, and that every composition runs end to end.PaletteSynthesisGPUalso joins the introspective discovery intest_transforms_gpu.py.234 passed, 3 skippedlocally, plusruff check,ruff format --checkandmypy smauglabclean. README matrix andall_augmentations.jsonregenerated.🤖 Generated with Claude Code