Repository navigation
Conversation
First PR towards keypoint detection support: the data args and dataset args that read a keypoint dataset off disk, plus tests. No model, no transforms, no train_task wiring. The keypoint set (count, names, sigmas, flip permutation, skeleton) is either read from the dataset or declared by the user, with no per-dataset presets baked in. Fields that neither source provides stay None so that the consumer decides, rather than this layer inventing a default. The on-disk format details were settled by inspecting real annotation files rather than from assumption; dev_tools/check_keypoint_detection_data_args.py records that inspection and is re-runnable. Notably, real num_dims == 2 YOLO pose labels use no unlabeled-keypoint sentinel at all, so the reader treats every keypoint of such a dataset as labeled instead of guessing one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60b5688f43
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
The script was a throwaway used once to settle the on-disk format questions before writing the readers. Committing it left ~270 lines that nothing runs, pointing at two external URLs that will rot, and pinned an Ultralytics download URL into the repo for no ongoing benefit. The findings it produced are what mattered, and those live where they are load-bearing: in the reader and data args docstrings. The verification run itself is recorded in the pull request. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Apply the new AGENTS.md documentation style to the keypoint detection files: bullet points over prose, shorter sentences, no filler. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
_iter_yolo_label_lines now yields (line number, line). The wrapper only existed so the three older callers could keep their signature; they unpack the number away instead. The number is in reach if those readers ever want file:line error messages too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep this PR to the data args only. The dataset args, the dataset, the YOLO pose label reader and the keypoint dataset item move to a follow-up PR stacked on this one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drop the Attributes blocks. No other DataArgs class has one, and they documented an arbitrary subset of the fields. What is left is an attribute docstring on the five fields whose type does not already say what they hold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
/review |
gabrielfruet
left a comment
There was a problem hiding this comment.
Small stuff, I will not block because of this but I highly recommend addressing
| keypoint_helpers.validate_flip_idx(flip_idx, 3) | ||
|
|
||
|
|
||
| def test_validate_kpt_names__invalid() -> None: |
There was a problem hiding this comment.
We only have the invalid variant here.
I think tests can also be used as documentation to understand the code. So I think it's worth it to add
| from lightly_train.types import PathLike | ||
|
|
||
|
|
||
| class YOLOKeypointDetectionDataArgs(TaskDataArgs): |
There was a problem hiding this comment.
Why not separate files? we have coco_object_detection_dataset and yolo_object_detection_dataset
| return kpt_shape | ||
|
|
||
|
|
||
| def validate_flip_idx(flip_idx: list[int] | None, num_keypoints: int) -> None: |
There was a problem hiding this comment.
Although internal, I think it's worth it to add a better documentation on the functions here. At least was pretty hard to me to understand flip idx and sigmas.
First PR towards keypoint detection support (see
NOTES_keypoint_detection_ecpose.md). It covers only the data args — the user-facing config classes and the keypoint set resolution. Reading labels off disk is the follow-up PR, stacked on this one.What's in it
_data/keypoint_helpers.pyKeypointSetArgs+ the pure resolvers that combine a dataset's keypoint set with a user-declared one_data/keypoint_detection_dataset.pyCOCO/YOLOKeypointDetectionDataArgs, mirroringinstance_segmentation_dataset.pyDesign decisions worth a look
No per-dataset presets. No COCO-17 or CrowdPose-14 preset, no baked sigma table, no baked flip pairs. The keypoint set comes from the dataset (COCO
categories[], YOLOkpt_shape/flip_idx/kpt_names) or from the user'skeypointsargument. Where a format carries nothing — COCO has no sigmas and no flip pairs, YOLO has no sigmas and no skeleton — the field staysNoneand whichever consumer needs it decides. Nothing is invented here.Values given twice must agree. Neither the dataset nor the user takes precedence; a conflict is an error naming both values. Silent precedence in either direction would be impossible to debug.
One shared keypoint set. If several included COCO categories declare
keypointsthey must declare the same ones, and the same for YOLO's per-classkpt_names. A category that is excluded viaignore_classesmay differ freely.Keypoint set resolved at construction. A bad keypoint config fails when the args are built, not much later when labels are read. COCO
categories[].skeletonis one-indexed and is converted to zero-indexed on read;flip_idxmust be a permutation and its own inverse, since flipping twice has to be the identity.Filtering fields ship here, enforced in the follow-up.
min_keypoints,include_crowdand theskip_if_*flags are part of the data args schema and feed the mmap hashes, but the code that acts on them lives in the dataset args. Shipping the schema whole avoids changing it in the next PR.min_keypointsdefaults to 0. The reader reproduces the file faithfully and drops nothing. Filtering zero-keypoint instances is standard in pose training, but that's a training-policy call for the model PR.include_crowd=Falseis the one default that does drop data, so it's an explicit field.Deliberately not wired up
No
KeypointDetectionTrainTaskConfig, nokeypoint_detectioninTrainTaskConfig.task, notrain_keypoint_detection(), no__init__.pyexport, no docs. Thattaskfield is a closedLiteral; adding a member would advertise a task thatTASK_TRAIN_MODEL_CLASSEScannot serve, so it would validate and then crash at model construction.The
formatdiscriminator ships on both classes from day one, andTestKeypointDetectionDataConfigexercises the discriminated union plus the YAML path in the test file — that's where a field missing from the data args would be dropped silently byload_data_yaml_if_path. Those few lines move intotrain_task.pyunchanged once a model lands.YOLOOrientedObjectDetectionDataArgsis the cautionary example of a data args class that shipped withoutformatand so can't join a union.Commit type
refactorrather thanfeat: perCONTRIBUTING.md,featmeans a user-facing feature and bumps the minor version, and nothing here is reachable by users.featbelongs to the PR that shipstrain_keypoint_detection. Happy to change it if you'd rather this cut a release.Verification
🤖 Generated with Claude Code