Improved NDD skills#6376
Conversation
|
| Filename | Overview |
|---|---|
| skills/dali-dynamic-mode/SKILL.md | Migrates .select() → .tensors[], adds Advanced Slicing section and a default-args performance row in the mistakes table. Content is internally consistent. |
| skills/dali-dynamic-mode/evals/evals.json | Updates two assertion strings to reference batch.tensors[i] instead of the deprecated batch.select(i), keeping eval assertions consistent with the updated skill. |
| docs/examples/getting_started/dynamic_mode.ipynb | Three .select() → .tensors[] replacements including the warning prose and visualization loop; changes are mechanical and correct. |
| docs/examples/general/data_loading/coco_reader/dynamic_mode.ipynb | Six .select() → .tensors[] replacements across bbox/label/polygon inspection and plot_sample helper; all correct. |
| docs/examples/image_processing/clahe/dynamic_mode.ipynb | Five .select() → .tensors[] replacements in MRI batch construction and contrast analysis loops; all correct. |
| docs/examples/image_processing/resize/dynamic_mode.ipynb | Single .select() → .tensors[] change in image decoding chain; correct. |
| docs/examples/sequence_processing/video/video_file_list_outputs/dynamic_mode.ipynb | Four .select() → .tensors[] replacements for video/label/frame/timestamp batch access; all correct. |
| docs/examples/sequence_processing/video/video_reader_label/dynamic_mode.ipynb | Single .select() → .tensors[] replacement for video/label sample access; correct. |
| docs/examples/sequence_processing/video/video_reader_simple/dynamic_mode.ipynb | Single .select() → .tensors[] replacement for video sample access; correct. |
| docs/examples/image_processing/decoder/dynamic_mode.ipynb | Single .select() → .tensors[] replacement in image batch visualization loop; correct. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Batch] --> B{Intent}
B -->|Select specific sample| C["batch.tensors[i] → Tensor"]
B -->|Select subset of samples| D["batch.tensors[slice or list] → Batch"]
B -->|Slice within every sample with scalar bounds| E["batch.slice[start:stop] → Batch"]
B -->|Slice within every sample with per-sample bounds| F["batch.slice[batch_start : batch_stop] → Batch"]
C --> G["Deprecated: batch.select(i)"]
style G fill:#ffcccc
Reviews (5): Last reviewed commit: "Explain how skipping arguments avoids py..." | Re-trigger Greptile
14d9bb9 to
d3c5b59
Compare
| imgs = ndd.as_batch([ndd.imread(file) for file in filenames]) | ||
| sliced = imgs.slice[ | ||
| 42 : # value broadcast to all samples | ||
| ndd.batch(imgs.shape).slice[0] / 2 # half of the height of _respective_ samples |
There was a problem hiding this comment.
[Bug] Float division produces float slice bounds here.
Batch.__truediv__ (i.e. /) is wired to fdiv — floating-point division — so ndd.batch(imgs.shape).slice[0] / 2 yields a Batch of floats (e.g. 240.0, 360.0). DALI's TensorSubscript will either reject those float bounds or interpret them as normalised coordinates rather than integer pixel offsets. Replace with // 2 (Batch.__floordiv__ → div, integer-preserving) to match the stated intent of "half of the height".
| ndd.batch(imgs.shape).slice[0] / 2 # half of the height of _respective_ samples | |
| ndd.batch(imgs.shape).slice[0] // 2 # half of the height of _respective_ samples |
There was a problem hiding this comment.
@greptileai It's an antipattern that needs fixing, but the code does work as written and produces correct results.
There was a problem hiding this comment.
Fair enough — if DALI coerces float slice bounds to integers internally and produces the correct result, then it's not a bug. I'll withdraw the "Bug" label.
That said, using / 2 instead of // 2 is still worth a nudge in docs/examples, since example code tends to be copied verbatim and the implicit coercion isn't obvious to readers.
Shall I remember a rule: "Don't flag float-to-int coercion in DALI slice bounds as a bug — it works correctly, though // is preferred style in examples"?
902ffdc to
6ed7386
Compare
| The `.slice[]` API accepts batches of indices, allowing the user to mix and match batches and | ||
| scalar values, e.g.: | ||
| ```python | ||
| imgs = ndd.as_batch([ndd.imread(file) for file in filenames]) |
There was a problem hiding this comment.
[Minor / clarity] Two things worth tightening on this example line:
ndd.imreadalready handles the list-of-paths case by returning aBatchdirectly (per_imread.py— single path → Tensor, list → Batch). The inner list-comp +ndd.as_batchwrap is redundant;imgs = ndd.imread(filenames)is equivalent and reads more like idiomatic ndd.ndd.imreadis not introduced anywhere else in this skill. A reader (or LLM consuming the skill) seeing it here for the first time has to guess what it does. Either add a one-line note where it appears, or use a more familiar primitive that the skill already covers.
| ```python | ||
| imgs = ndd.as_batch([ndd.imread(file) for file in filenames]) | ||
| sliced = imgs.slice[ | ||
| 42 : # value broadcast to all samples |
There was a problem hiding this comment.
[Nit / clarity] The comment # value broadcast to all samples is hard to parse — it doesn't say what value or what it contrasts with. The point of this snippet (per the section heading and prose above) is that .slice[] accepts a mix of scalars and per-sample batches; that contrast only lands if the two comments are parallel. Consider e.g.:
42 : # scalar start (same for all samples)
ndd.batch(imgs.shape).slice[0] // 2 # per-sample stop (half height of each)
| | `batch[i]` | `batch.select(i)` | `Batch` has no `__getitem__` | | ||
| | `batch.select(0)` for per-sample slicing | `batch.slice[0]` | `.select()` picks samples; `.slice` slices within each sample | | ||
| | `batch[i]` | `batch.tensors[i]` | `Batch` has no `__getitem__` | | ||
| | `batch.tensors[0]` for per-sample slicing | `batch.slice[0]` | `.tensors` and `.select()` pick samples; `.slice` slices within each sample | |
There was a problem hiding this comment.
[Minor / consistency] This is now the only place in the file that still mentions .select() as a sample-picking API. The PR consistently migrates everywhere else (line 41-42 table, line 46 prose, line 250 migration row) to .tensors[] only — a reader or LLM trained on the skill will pick up the inconsistency and may emit .select() calls again.
If .select() still exists for backward compat, consider stating that explicitly somewhere (e.g. ".select() is the legacy spelling") rather than slipping it into the explanation here. Otherwise it's simpler to drop it: `.tensors[]` picks samples; `.slice` slices within each sample.
| @@ -221,6 +234,7 @@ for epoch in range(num_epochs): | |||
| | No `batch_size` to random ops | `ndd.random.uniform(batch_size=N, ...)` | No pipeline-level batch size to inherit | | |||
| | `register(reader)` after first `next_epoch` to restore | Register the freshly built reader before the first iteration | Reader state can only be applied before the prefetch thread starts | | |||
| | Restoring into a reader built without `enable_checkpointing=True` after iteration | Pass `enable_checkpointing=True` at construction (or register before first iteration) | Backend doesn't keep snapshots otherwise | | |||
| | Spelling out default argument values | Skip default argument values | Very high Python-side overhead, especially when the argument accepts Tensors/Batches | | |||
There was a problem hiding this comment.
[Minor / actionability] The Why cell asserts "Very high Python-side overhead, especially when the argument accepts Tensors/Batches" without telling the reader why — in most Python libraries, passing a default explicitly is equivalent to omission, so this rule reads as surprising. Without a mechanism, a reader can't tell when the warning generalizes (e.g. is this true for plain scalar defaults too, or only Tensor/Batch-typed ones?).
One extra clause would make this self-justifying, e.g. "unset args are handled efficiently by the backend via sentinels; passing the default explicitly forces Python-side conversion — costly for Tensor/Batch types."
|
@mzient please rebase and then we need to issue |
Add advanced slicing. Use .tensors[] rather than .select() Mention that spelling out default values has a nontrivial cost. Signed-off-by: Michal Zientkiewicz <michalz@nvidia.com>
Signed-off-by: Michal Zientkiewicz <michalz@nvidia.com>
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
6ed7386 to
b1fc295
Compare
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
|
/nvskills-ci |
Category:
Other (e.g. Documentation, Tests, Configuration)
Description:
Improved NDD skills
Additional information:
Affected modules and functionalities:
Key points relevant for the review:
Tests:
Checklist
Documentation
DALI team only
Requirements
REQ IDs: N/A
JIRA TASK: N/A