Skip to content

Commit 0081473

Browse files
Speed up slow unit/gpu/example tests (#1616)
### What does this PR do? Type of change: test infrastructure / test speedups + CI stabilization Make the test suite faster, `tests/unit` hermetic, and the CI lanes stable, without losing coverage. Most changes are mechanical test/infra edits; the buckets below cover the diff broadly. **Unit tests — hermetic (no HF Hub):** toy local datasets/configs + the local tiny tokenizer (with a checked-in chat template) replace Hub assets; `tests/unit/conftest.py` enforces offline mode. Genuinely-HF tests moved to `tests/gpu*` (e.g. the new `tests/gpu/torch/utils/test_dataset_utils.py`). `CONTRIBUTING.md` documents the hermetic-unit-test expectation. **Unit-test speedups (no coverage loss):** speculative (disable CPU torch.compile), calibrator (fewer histogram bins), ONNX conv/dynamo (smaller shapes + representative subset), Ruler/sparse-attention (local tokenizer), data-parallel autoquant (world size 4→2). Shared `tiny_tokenizer` fixture. The distributed test helper now uses a private `spawn` context instead of mutating the global start method (avoids cross-test contamination). **Rarely-used autonas/fastnas tests:** heavy parametrize cases marked `@pytest.mark.manual`, one representative kept per test (fastnas preferred); lighter sibling tests still cover core behavior. The legacy FSDP1 NAS distributed test is also dropped: FastNAS/AutoNAS aren't used with either FSDP1 or FSDP2, and FSDP1 is superseded by the newer FSDP2 API — so we keep a single FSDP2 case as a sanity check and drop FSDP1, leaving the suite leaner. **gpu_megatron:** deduplicate distributed worker pools by world_size within a module (saves a redundant pool spin-up in multi-pool files; module-scoped, no cross-module reuse). **Example tests:** reduce per-test work via args that default to current behavior (tests pass the fast values) — torch_onnx TRT optimization level, diffusers calibration/inference steps, eagle `sample_size`, megatron_bridge iters/calib, llm_sparsity data slice, export safetensors-structure `calib_size`. Also enable the recently added `gpt-oss` example tests in CI. **Per-test timeouts:** `pytest-timeout` with a default per-directory timeout (60s unit / 300s gpu+example) enforced in `tests/conftest.py` (`timeout_func_only` in `pyproject.toml`), so a new test cannot silently exceed the budget — an unmapped test dir crashes collection. A few inherently slow tests carry explicit higher per-test overrides (CUDA-compile, autotune, dflash). **CUDA kernel pre-compilation:** a dedicated `tests/gpu/_extensions` test JIT-builds the conv3d implicit-GEMM kernel up front (collected before the functional tests in the same process) so the one-time build cost no longer lands on — and time out — the first functional test that uses it. Mirrored into the `llm_ptq`/`vlm_ptq` example lanes. **Test relocation & optional-dependency guards:** vLLM sparsity plugin test moved to `tests/gpu_vllm` (drops the in-test `importorskip`); diffusers-dependent unit test guarded with `importorskip("diffusers")` for partial-install lanes; `gpt_oss` example test dir renamed to `gpt-oss` to match the CI matrix. **Diffusers test models:** shared model-path constants in `tests/_test_utils/examples/models.py` consolidated/renamed and point at tiny `hf-internal-testing` test pipes (SDXL/SD3/FLUX) so cachify/quantize/export tests run on toy weights; `local_id`s normalized. **Shared dataset utils:** `examples/llm_sparsity/.../hf_pts.py` now uses `get_dataset_dataloader` (drops the bespoke cnn_dailymail-only `get_calib_dataloader`; supports any registered/HF/JSONL dataset, includes attention_mask); `data_prep.py` gains `--max_samples`. **CI workflows:** container image bumps (pytorch 26.04→26.05, TRT-LLM rc16→rc17) and tightened lane timeouts (unit 30→15 min, gpu lanes trimmed, onnx example lane 45 min). **Imports at top of file:** in-function imports across the test suite are moved to module top per the coding guideline, conservatively — optional deps stay guarded (in-function or behind a module-level `importorskip`) in `tests/unit` since the partial-install lane runs without them, and build/hardware-availability imports (apex, triton, megatron/transformer_engine, tensorrt_llm) plus `_test_utils` lazy guards are left in place. **Kernel warning filters:** the repeated `filterwarnings` blanket-ignore in six `tests/gpu/torch/kernels/**` modules is consolidated into a scoped hook in `tests/gpu/torch/kernels/conftest.py` (kernel tests only — the rest of the suite keeps surfacing warnings). **Eagle example speedups:** `torch.compile` (eagle recipe default) added ~2 min to every eagle training test; it's now disabled in the eagle example tests except one smoke (`test_llama_eagle3[1-False]`), and the downstream resume / AR-validate / export tests point at the compile-free checkpoint. Measured: `test_ar_validate` 139s→17s, offline training 142s→22s, streaming 140s→23s — the compile path is still smoke-tested once. **Example lanes install editable (`-e`):** so example scripts launched as subprocesses resolve `modelopt` to the same source path as the test process and reuse the pre-compiled CUDA-extension cache instead of recompiling (~2 min/test); verified in the TRT-LLM container. **Tiny test tokenizer:** `get_tiny_tokenizer` defaults to left padding (what decoder-LM calibration expects) and ships a terse generation-tagged chat template — replacing a verbose ChatML one that inflated tokenized length on the 128-vocab tokenizer and broke the offline-PTQ example tests' `max-seq-len` filter. **Restored Hub-download coverage:** the live (ungated) HF dataset round-trips exercising `get_dataset_samples`' download branch now live in `tests/gpu/torch/utils/test_dataset_utils.py` (they had been dropped from the hermetic unit file without a counterpart). Individual file changes not explicitly called out above fall under this general test/CI cleanup. ### Testing Unit + the touched gpu_megatron files validated locally; example/GPU lanes validated in CI. ### Before your PR is "*Ready for review*" - Is this change backward compatible?: ✅ (tests + example CLI args default to prior behavior) - If you copied code from any other sources or added a new PIP dependency: N/A - Did you write any new necessary tests?: N/A (optimizes/relocates existing tests) - Did you update Changelog?: N/A - Did you get Claude approval on this PR?: ❌ (pending) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Chores** * Updated container image versions for PyTorch (26.04→26.05), TensorRT-LLM (1.3.0rc16→1.3.0rc17), and ONNX/TensorRT (26.04→26.05). * **Tests** * Enhanced test isolation: unit tests now run hermetically without HuggingFace Hub access. * Optimized test runtime via smaller model/dataset parameters and parallel test caching. * Added CUDA extension availability tests and extended dataset utility coverage. * **Documentation** * Updated testing guidelines in `CONTRIBUTING.md` to emphasize offline test design. * **Chores** * Added pytest timeout configuration and improved CI/CD workflow efficiency with editable installs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ca7eb64 commit 0081473

88 files changed

Lines changed: 907 additions & 723 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/_example_tests_runner.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ jobs:
4747
echo "PATH=${PATH}:/usr/local/tensorrt/targets/x86_64-linux-gnu/bin" >> $GITHUB_ENV
4848
- name: Install dependencies
4949
run: |
50-
# use `python -m pip` instead of `pip` to avoid conflicts with system pip for nemo containers
51-
python -m pip install ".${{ inputs.pip_install_extras }}"
50+
# Uninstall conflicting system-wide installed modelopt in nemo containers
51+
pip uninstall -y nvidia-modelopt || true
52+
53+
# Use `python -m pip` instead of `pip` to avoid conflicts with system pip for nemo containers
54+
# Editable install so example scripts launched as subprocesses resolve modelopt to the same source path as the test process
55+
python -m pip install -e ".${{ inputs.pip_install_extras }}"
5256
5357
if [[ "${{ inputs.example }}" == *"diffusers"* ]]; then
5458
echo "Uninstalling apex for diffusers: T5 Int8 (PixArt) + Apex is not supported as per https://github.com/huggingface/transformers/issues/21391"

.github/workflows/example_tests.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ jobs:
3535
strategy:
3636
fail-fast: false
3737
matrix:
38-
example: [llm_distill, llm_qat, llm_sparsity, diffusers_sparsity, specdec_bench]
38+
example: [diffusers_sparsity, gpt-oss, llm_distill, llm_qat, llm_sparsity, specdec_bench]
3939
include:
4040
- example: speculative_decoding
4141
docker_image: "26.01"
4242
uses: ./.github/workflows/_example_tests_runner.yml
4343
secrets: inherit
4444
with:
45-
docker_image: "nvcr.io/nvidia/pytorch:${{ matrix.docker_image || '26.04' }}-py3"
45+
docker_image: "nvcr.io/nvidia/pytorch:${{ matrix.docker_image || '26.05' }}-py3"
4646
example: ${{ matrix.example }}
4747
timeout_minutes: 30
4848
pip_install_extras: "[hf,dev-test]"
@@ -59,7 +59,7 @@ jobs:
5959
uses: ./.github/workflows/_example_tests_runner.yml
6060
secrets: inherit
6161
with:
62-
docker_image: "nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc16"
62+
docker_image: "nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc17"
6363
example: ${{ matrix.example }}
6464
pip_install_extras: "[hf,dev-test]"
6565
runner: linux-amd64-gpu-rtxpro6000-latest-1
@@ -73,7 +73,7 @@ jobs:
7373
uses: ./.github/workflows/_example_tests_runner.yml
7474
secrets: inherit
7575
with:
76-
docker_image: "nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc16"
76+
docker_image: "nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc17"
7777
example: ${{ matrix.example }}
7878
pip_install_extras: "[hf,dev-test]"
7979
runner: linux-amd64-gpu-rtxpro6000-latest-2
@@ -102,8 +102,9 @@ jobs:
102102
uses: ./.github/workflows/_example_tests_runner.yml
103103
secrets: inherit
104104
with:
105-
docker_image: "nvcr.io/nvidia/tensorrt:26.04-py3"
105+
docker_image: "nvcr.io/nvidia/tensorrt:26.05-py3"
106106
example: ${{ matrix.example }}
107+
timeout_minutes: 45
107108
pip_install_extras: "[onnx,hf,dev-test]"
108109
runner: ${{ startsWith(github.ref, 'refs/heads/pull-request/') && 'linux-amd64-gpu-rtxpro6000-latest-1' || 'linux-amd64-gpu-rtxpro6000-latest-2' }}
109110

.github/workflows/gpu_tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ jobs:
3939
matrix:
4040
include:
4141
- example: gpu
42-
timeout: 75
43-
container_image: nvcr.io/nvidia/pytorch:26.04-py3
42+
timeout: 60
43+
container_image: nvcr.io/nvidia/pytorch:26.05-py3
4444
- example: gpu_megatron
4545
timeout: 60
4646
container_image: nvcr.io/nvidia/nemo:26.04
4747
- example: gpu_trtllm
4848
timeout: 30
49-
container_image: nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc16
49+
container_image: nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc17
5050
- example: gpu_vllm
51-
timeout: 30
51+
timeout: 15
5252
container_image: docker.io/vllm/vllm-openai:v0.20.0
5353
runs-on: ${{ startsWith(github.ref, 'refs/heads/pull-request/') && 'linux-amd64-gpu-rtxpro6000-latest-1' || 'linux-amd64-gpu-rtxpro6000-latest-2' }}
5454
timeout-minutes: ${{ matrix.timeout }}

.github/workflows/unit_tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
linux:
5959
needs: [check-dco]
6060
runs-on: ubuntu-latest
61-
timeout-minutes: 30
61+
timeout-minutes: 15
6262
steps:
6363
- uses: actions/checkout@v6
6464
- uses: ./.github/actions/ubuntu-setup
@@ -78,7 +78,7 @@ jobs:
7878
if: needs.check-file-changes.outputs.any_changed == 'true'
7979
needs: [linux, check-file-changes]
8080
runs-on: windows-latest
81-
timeout-minutes: 30
81+
timeout-minutes: 15
8282
steps:
8383
- uses: actions/checkout@v6
8484
- uses: actions/setup-python@v6
@@ -90,7 +90,7 @@ jobs:
9090
if: needs.check-file-changes.outputs.any_changed == 'true'
9191
needs: [linux, check-file-changes]
9292
runs-on: ubuntu-latest
93-
timeout-minutes: 30
93+
timeout-minutes: 15
9494
strategy:
9595
fail-fast: false
9696
matrix:
@@ -115,7 +115,7 @@ jobs:
115115
if: needs.check-file-changes.outputs.any_changed == 'true'
116116
needs: [linux, check-file-changes]
117117
runs-on: ubuntu-latest
118-
timeout-minutes: 30
118+
timeout-minutes: 15
119119
strategy:
120120
fail-fast: false
121121
matrix:

CONTRIBUTING.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,20 @@ nox -s "unit-3.12(torch_211, tf_latest)"
163163

164164
### Test design principles
165165

166-
- **Develop with focused tests.** During development, write as many focused
167-
tests as needed, including lower-level unit tests or internal probes, to
168-
understand and harden behavior.
169-
- **Curate production tests and keep them lean.** Before staging or committing,
170-
decide which tests should be checked in. Checked-in tests should document
171-
expected behavior, protect against regressions, or flag backward-incompatible
172-
behavior changes. Remove redundant lower-level tests when a higher-level test
173-
already covers the same behavior, keeping CI/CD fast and lean.
166+
- **Develop with focused tests.** During development, write as many focused tests as needed, including lower-level
167+
unit tests or internal probes, to understand and harden behavior.
168+
- **Curate production tests and keep them lean.** Before staging or committing, decide which tests should be checked
169+
in. Checked-in tests should document expected behavior, protect against regressions, or flag backward-incompatible
170+
behavior changes. Remove redundant lower-level tests when a higher-level test already covers the same behavior,
171+
keeping CI/CD fast and lean.
172+
- **Keep `tests/unit` offline — no HuggingFace Hub access.** Unit tests must be hermetic so they never flake on
173+
network/timeout issues. Do not call `from_pretrained("<org>/<model>")`, `load_dataset("<hub-id>")`,
174+
`snapshot_download(...)`, etc. with Hub IDs. Instead build dummy models, tokenizers, configs, and datasets locally —
175+
e.g. the `create_tiny_*` helpers and `get_tiny_tokenizer()` in `tests/_test_utils/`, or a small on-disk dataset
176+
directory written with `datasets.Dataset.from_dict(...).to_parquet(...)`.
177+
- **Respect the per-test timeout.** `tests/conftest.py` applies a default per-test call timeout by directory; override a
178+
single slow test with `@pytest.mark.timeout(<seconds>)`, and register any new top-level `tests/<group>/` in that
179+
mapping (collection errors until you do).
174180

175181
## ✍️ Signing your work
176182

examples/diffusers/quantization/diffusion_trt.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@
6565

6666

6767
@torch.inference_mode()
68-
def generate_image(pipe, prompt, image_name, torch_autocast=False):
68+
def generate_image(pipe, prompt, image_name, torch_autocast=False, num_inference_steps=30):
6969
context = torch.autocast("cuda") if torch_autocast else nullcontext()
7070
seed = 42
7171
with context:
7272
image = pipe(
7373
prompt,
7474
output_type="pil",
75-
num_inference_steps=30,
75+
num_inference_steps=num_inference_steps,
7676
generator=torch.Generator("cuda").manual_seed(seed),
7777
).images[0]
7878
image.save(image_name)
@@ -186,6 +186,12 @@ def main():
186186
help="Use torch.autocast() during inference or benchmarking",
187187
)
188188
parser.add_argument("--skip-image", action="store_true", help="Skip image generation")
189+
parser.add_argument(
190+
"--num-inference-steps",
191+
type=int,
192+
default=30,
193+
help="Number of denoising steps for image generation (lower is faster; tests use few).",
194+
)
189195
args = parser.parse_args()
190196

191197
image_name = args.save_image_as if args.save_image_as else f"{args.model}.png"
@@ -235,7 +241,9 @@ def main():
235241
)
236242

237243
if not args.skip_image:
238-
generate_image(pipe, args.prompt, image_name, args.torch_autocast)
244+
generate_image(
245+
pipe, args.prompt, image_name, args.torch_autocast, args.num_inference_steps
246+
)
239247
return
240248

241249
backbone.to("cuda")
@@ -322,7 +330,7 @@ def main():
322330
pipe.to("cuda")
323331

324332
if not args.skip_image:
325-
generate_image(pipe, args.prompt, image_name, args.torch_autocast)
333+
generate_image(pipe, args.prompt, image_name, args.torch_autocast, args.num_inference_steps)
326334
print(f"Image generated using {args.model} model saved as {image_name}")
327335

328336
if args.benchmark:

examples/llm_eval/run_simple_eval.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ MODEL_NAME=$1
2222
EVALS=$2
2323
BUILD_MAX_OUTPUT_LEN=${3:-2048}
2424
PORT=${4:-8000}
25+
NUM_EXAMPLES=${5:-} # optional: limit examples per eval (default: full eval)
2526

2627
if [ ! -d "human-eval" ]; then
2728
git clone https://github.com/openai/human-eval.git
@@ -42,4 +43,9 @@ popd
4243
export OPENAI_API_KEY="local"
4344
export OPENAI_BASE_URL="http://localhost:$PORT/v1"
4445

45-
python -m simple-evals.simple_evals --model $MODEL_NAME --evals $EVALS --max_tokens $BUILD_MAX_OUTPUT_LEN
46+
examples_flag=""
47+
if [ -n "$NUM_EXAMPLES" ]; then
48+
examples_flag="--examples $NUM_EXAMPLES"
49+
fi
50+
51+
python -m simple-evals.simple_evals --model $MODEL_NAME --evals $EVALS --max_tokens $BUILD_MAX_OUTPUT_LEN $examples_flag

examples/llm_ptq/scripts/huggingface_example.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ if [[ $TASKS =~ "livecodebench" || $TASKS =~ "simple_eval" ]]; then
328328

329329
if [[ $TASKS =~ "simple_eval" ]]; then
330330
echo "Using the following config: max output $BUILD_MAX_OUTPUT_LEN max batch $BUILD_MAX_BATCH_SIZE"
331-
bash run_simple_eval.sh $MODEL_NAME $SIMPLE_EVAL_TASKS $BUILD_MAX_OUTPUT_LEN $PORT | tee $SAVE_PATH/simple_eval.txt
331+
bash run_simple_eval.sh $MODEL_NAME $SIMPLE_EVAL_TASKS $BUILD_MAX_OUTPUT_LEN $PORT $SIMPLE_EVAL_LIMIT | tee $SAVE_PATH/simple_eval.txt
332332
echo "Simple eval results are saved under $SAVE_PATH/simple_eval.txt."
333333
fi
334334

examples/llm_ptq/scripts/parser.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ parse_options() {
3838
CAST_MXFP4_TO_NVFP4=false
3939

4040
# Parse command-line options
41-
ARGS=$(getopt -o "" -l "model:,quant:,recipe:,kv_cache_quant:,tp:,pp:,sparsity:,awq_block_size:,calib:,calib_batch_size:,auto_quantize_bits:,output:,batch:,tasks:,lm_eval_tasks:,lm_eval_limit:,simple_eval_tasks:,trust_remote_code,use_seq_device_map,gpu_max_mem_percentage:,kv_cache_free_gpu_memory_fraction:,low_memory_mode,no-verbose,calib_dataset:,calib_seq:,auto_quantize_method:,auto_quantize_score_size:,auto_quantize_checkpoint:,moe_calib_experts_ratio:,cast_mxfp4_to_nvfp4" -n "$0" -- "$@")
41+
ARGS=$(getopt -o "" -l "model:,quant:,recipe:,kv_cache_quant:,tp:,pp:,sparsity:,awq_block_size:,calib:,calib_batch_size:,auto_quantize_bits:,output:,batch:,tasks:,lm_eval_tasks:,lm_eval_limit:,simple_eval_tasks:,simple_eval_limit:,trust_remote_code,use_seq_device_map,gpu_max_mem_percentage:,kv_cache_free_gpu_memory_fraction:,low_memory_mode,no-verbose,calib_dataset:,calib_seq:,auto_quantize_method:,auto_quantize_score_size:,auto_quantize_checkpoint:,moe_calib_experts_ratio:,cast_mxfp4_to_nvfp4" -n "$0" -- "$@")
4242

4343
eval set -- "$ARGS"
4444
while true; do
@@ -60,6 +60,7 @@ parse_options() {
6060
--lm_eval_tasks ) LM_EVAL_TASKS="$2"; shift 2;;
6161
--lm_eval_limit ) LM_EVAL_LIMIT="$2"; shift 2;;
6262
--simple_eval_tasks ) SIMPLE_EVAL_TASKS="$2"; shift 2;;
63+
--simple_eval_limit ) SIMPLE_EVAL_LIMIT="$2"; shift 2;;
6364
--trust_remote_code ) TRUST_REMOTE_CODE=true; shift;;
6465
--use_seq_device_map ) USE_SEQ_DEVICE_MAP=true; shift;;
6566
--gpu_max_mem_percentage ) GPU_MAX_MEM_PERCENTAGE="$2"; shift 2;;
@@ -159,6 +160,7 @@ parse_options() {
159160
echo "lm_eval_tasks: $LM_EVAL_TASKS"
160161
echo "lm_eval_limit: $LM_EVAL_LIMIT"
161162
echo "simple_eval_tasks: $SIMPLE_EVAL_TASKS"
163+
echo "simple_eval_limit: $SIMPLE_EVAL_LIMIT"
162164
echo "num_sample: $NUM_SAMPLES"
163165
echo "use_seq_device_map: $USE_SEQ_DEVICE_MAP"
164166
echo "gpu_max_mem_percentage: $GPU_MAX_MEM_PERCENTAGE"

examples/llm_sparsity/weight_sparsity/data_prep.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ def preprocess_function(sample):
3939
def parse_args():
4040
parser = argparse.ArgumentParser()
4141
parser.add_argument("--save_path", type=str, default="data")
42+
parser.add_argument(
43+
"--max_samples",
44+
type=int,
45+
default=None,
46+
help="If set, keep only the first N rows of each split before processing. Greatly "
47+
"speeds up preparation for smoke tests (cnn_dailymail train is ~287k rows).",
48+
)
4249
return parser.parse_args()
4350

4451

@@ -48,6 +55,14 @@ def main():
4855
# Load dataset from the hub
4956
dataset = load_dataset(dataset_id, name=dataset_config)
5057

58+
if args.max_samples is not None:
59+
dataset = type(dataset)(
60+
{
61+
split: ds.select(range(min(args.max_samples, len(ds))))
62+
for split, ds in dataset.items()
63+
}
64+
)
65+
5166
# process dataset
5267
tokenized_dataset = dataset.map(
5368
preprocess_function, batched=True, remove_columns=list(dataset["train"].features)

0 commit comments

Comments
 (0)