Repository navigation
Fix metric gathering with sized samplers - #4501
gorkadabo1 wants to merge 1 commit into
Conversation
|
Additional coverage at Unlike a subset, oversampling produces intentional repeats that metrics must retain. The tests compare the complete gathered sequence with a separately seeded sampler and assert a remainder of 2. Both pass on this PR; restoring the parent Validation: 4 passed, 40 deselected (2 new + the PR's subset and changing-length regressions); Ruff check/format passed. This is real single-process CPU Prepared and tested with OpenAI Codex assistance. Optional regression patchdiff --git a/tests/test_weighted_metrics.py b/tests/test_weighted_metrics.py
new file mode 100644
--- /dev/null
+++ b/tests/test_weighted_metrics.py
@@ -0,0 +1,42 @@
+# Copyright 2026 The HuggingFace Team. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+import torch
+from torch.utils.data import BatchSampler, DataLoader, WeightedRandomSampler
+
+from accelerate import Accelerator
+
+
+@pytest.mark.parametrize("explicit_batch_sampler", [False, True])
+def test_metrics_keep_all_weighted_replacement_samples(explicit_batch_sampler):
+ weights = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])
+
+ def make_sampler():
+ return WeightedRandomSampler(weights, 14, replacement=True, generator=torch.Generator().manual_seed(123))
+
+ expected = list(make_sampler())
+ sampler = make_sampler()
+ loader = (
+ DataLoader(range(5), batch_sampler=BatchSampler(sampler, 4, drop_last=False))
+ if explicit_batch_sampler
+ else DataLoader(range(5), batch_size=4, sampler=sampler)
+ )
+ accelerator = Accelerator(cpu=True)
+ prepared = accelerator.prepare(loader)
+ actual = []
+ for batch in prepared:
+ actual.extend(accelerator.gather_for_metrics(batch).tolist())
+ assert actual == expected
+ assert prepared.remainder == 2 |
What does this PR do?
Fixes #4410
This PR computes the final-batch remainder using the sized sampler, following batch-sampler wrappers and respecting
drop_last. For unsized samplers, it keeps the existing dataset-length fallback. It also sets the shard sampler's epoch before reading its length, so metric gathering stays correct when the sampler length changes between epochs.Related PRs
I also reviewed #4412 (closed) and #4489 (open), which aim to fix the same issue. Both pass the original
SubsetRandomSamplerreproduction, but I found additional cases where they still return incorrect results:skip_first_batches: with zero batches skipped, both return 13 samples instead of 10. With one batch skipped, they return 5 instead of 2.This PR also handles these cases with a smaller change to the production code.
Validation
mainand pass with the fix.drop_last.make style,make qualityandgit diff --checkpass.I did not run the full test suite or GPU tests.
Before submitting
Who can review?
Core library: @BenjaminBossan @SunMarc