This is an automated email from the ASF dual-hosted git repository.

shunping pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new e3b4d8c5d0e Fix flaky ML RunInference tests by disabling reshuffle on 
beam.Create (#39118)
e3b4d8c5d0e is described below

commit e3b4d8c5d0eb8090ff8c0a9e8ea34ccc3ab15cf6
Author: Shunping Huang <[email protected]>
AuthorDate: Sat Jun 27 04:29:20 2026 -0400

    Fix flaky ML RunInference tests by disabling reshuffle on beam.Create 
(#39118)
---
 sdks/python/apache_beam/ml/inference/base_test.py  |  2 +-
 .../ml/inference/pytorch_inference_test.py         |  5 ++-
 .../ml/inference/sklearn_inference_test.py         |  4 +-
 .../ml/inference/tensorflow_inference_test.py      |  4 +-
 .../ml/inference/tensorrt_inference_test.py        | 11 +++--
 sdks/python/apache_beam/transforms/util_test.py    | 49 ++++++++++++++++++++++
 6 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/sdks/python/apache_beam/ml/inference/base_test.py 
b/sdks/python/apache_beam/ml/inference/base_test.py
index 3f0bea7fbe1..7bca1fc6338 100644
--- a/sdks/python/apache_beam/ml/inference/base_test.py
+++ b/sdks/python/apache_beam/ml/inference/base_test.py
@@ -1047,7 +1047,7 @@ class RunInferenceBaseTest(unittest.TestCase):
   def test_forwards_batch_args(self):
     examples = list(range(100))
     with TestPipeline('FnApiRunner') as pipeline:
-      pcoll = pipeline | 'start' >> beam.Create(examples)
+      pcoll = pipeline | 'start' >> beam.Create(examples, reshuffle=False)
       actual = pcoll | base.RunInference(FakeModelHandlerNeedsBigBatch())
       assert_that(actual, equal_to(examples), label='assert:inferences')
 
diff --git a/sdks/python/apache_beam/ml/inference/pytorch_inference_test.py 
b/sdks/python/apache_beam/ml/inference/pytorch_inference_test.py
index 50279820b26..8efec14c865 100644
--- a/sdks/python/apache_beam/ml/inference/pytorch_inference_test.py
+++ b/sdks/python/apache_beam/ml/inference/pytorch_inference_test.py
@@ -635,7 +635,8 @@ class PytorchRunInferencePipelineTest(unittest.TestCase):
           min_batch_size=2,
           max_batch_size=2)
 
-      pcoll = pipeline | 'start' >> beam.Create(KEYED_TORCH_EXAMPLES)
+      pcoll = pipeline | 'start' >> beam.Create(
+          KEYED_TORCH_EXAMPLES, reshuffle=False)
       inference_args_side_input = (
           pipeline | 'create side' >> beam.Create(inference_args))
       predictions = pcoll | RunInference(
@@ -709,7 +710,7 @@ class PytorchRunInferencePipelineTest(unittest.TestCase):
           min_batch_size=2,
           max_batch_size=2)
 
-      pcoll = pipeline | 'start' >> beam.Create(examples)
+      pcoll = pipeline | 'start' >> beam.Create(examples, reshuffle=False)
       predictions = pcoll | RunInference(model_handler)
       assert_that(
           predictions,
diff --git a/sdks/python/apache_beam/ml/inference/sklearn_inference_test.py 
b/sdks/python/apache_beam/ml/inference/sklearn_inference_test.py
index 400ac77cf49..76d6bc65729 100644
--- a/sdks/python/apache_beam/ml/inference/sklearn_inference_test.py
+++ b/sdks/python/apache_beam/ml/inference/sklearn_inference_test.py
@@ -299,7 +299,7 @@ class SkLearnRunInferenceTest(unittest.TestCase):
     with TestPipeline() as pipeline:
       examples = [numpy.array([0, 0]), numpy.array([1, 1])]
 
-      pcoll = pipeline | 'start' >> beam.Create(examples)
+      pcoll = pipeline | 'start' >> beam.Create(examples, reshuffle=False)
       actual = pcoll | RunInference(
           SklearnModelHandlerNumpy(
               model_uri=temp_file_name,
@@ -457,7 +457,7 @@ class SkLearnRunInferenceTest(unittest.TestCase):
     with TestPipeline() as pipeline:
       dataframe = pandas_dataframe()
       splits = [dataframe.loc[[i]] for i in dataframe.index]
-      pcoll = pipeline | 'start' >> beam.Create(splits)
+      pcoll = pipeline | 'start' >> beam.Create(splits, reshuffle=False)
       actual = pcoll | RunInference(
           SklearnModelHandlerPandas(
               model_uri=temp_file_name,
diff --git a/sdks/python/apache_beam/ml/inference/tensorflow_inference_test.py 
b/sdks/python/apache_beam/ml/inference/tensorflow_inference_test.py
index c884ee58b0a..3a2e58e378e 100644
--- a/sdks/python/apache_beam/ml/inference/tensorflow_inference_test.py
+++ b/sdks/python/apache_beam/ml/inference/tensorflow_inference_test.py
@@ -165,7 +165,7 @@ class TFRunInferenceTest(unittest.TestCase):
               examples, [tf.math.multiply(n, 2) for n in examples])
       ]
 
-      pcoll = pipeline | 'start' >> beam.Create(examples)
+      pcoll = pipeline | 'start' >> beam.Create(examples, reshuffle=False)
       predictions = pcoll | RunInference(model_handler)
       assert_that(
           predictions,
@@ -258,7 +258,7 @@ class TFRunInferenceTest(unittest.TestCase):
               examples, [numpy.multiply(n, 2) for n in examples])
       ]
 
-      pcoll = pipeline | 'start' >> beam.Create(examples)
+      pcoll = pipeline | 'start' >> beam.Create(examples, reshuffle=False)
       predictions = pcoll | RunInference(model_handler)
       assert_that(
           predictions,
diff --git a/sdks/python/apache_beam/ml/inference/tensorrt_inference_test.py 
b/sdks/python/apache_beam/ml/inference/tensorrt_inference_test.py
index 39e46c7f7c0..80a01b8f4d4 100644
--- a/sdks/python/apache_beam/ml/inference/tensorrt_inference_test.py
+++ b/sdks/python/apache_beam/ml/inference/tensorrt_inference_test.py
@@ -362,7 +362,8 @@ class TensorRTRunInferencePipelineTest(unittest.TestCase):
           max_batch_size=4,
           engine_path=
           'gs://apache-beam-ml/models/single_tensor_features_engine.trt')
-      pcoll = pipeline | 'start' >> beam.Create(SINGLE_FEATURE_EXAMPLES)
+      pcoll = pipeline | 'start' >> beam.Create(
+          SINGLE_FEATURE_EXAMPLES, reshuffle=False)
       predictions = pcoll | RunInference(engine_handler)
       assert_that(
           predictions,
@@ -423,7 +424,8 @@ class TensorRTRunInferencePipelineTest(unittest.TestCase):
           'gs://apache-beam-ml/models/single_tensor_features_engine.trt',
           inference_fn=fake_inference_fn,
           large_model=True)
-      pcoll = pipeline | 'start' >> beam.Create(SINGLE_FEATURE_EXAMPLES)
+      pcoll = pipeline | 'start' >> beam.Create(
+          SINGLE_FEATURE_EXAMPLES, reshuffle=False)
       predictions = pcoll | RunInference(engine_handler)
       assert_that(
           predictions,
@@ -443,7 +445,7 @@ class TensorRTRunInferencePipelineTest(unittest.TestCase):
       self.assertFalse('FOO' in os.environ)
       _ = (
           pipeline
-          | 'start' >> beam.Create(SINGLE_FEATURE_EXAMPLES)
+          | 'start' >> beam.Create(SINGLE_FEATURE_EXAMPLES, reshuffle=False)
           | RunInference(engine_handler))
       pipeline.run()
       self.assertTrue('FOO' in os.environ)
@@ -457,7 +459,8 @@ class TensorRTRunInferencePipelineTest(unittest.TestCase):
           max_batch_size=4,
           engine_path=
           'gs://apache-beam-ml/models/multiple_tensor_features_engine.trt')
-      pcoll = pipeline | 'start' >> beam.Create(TWO_FEATURES_EXAMPLES)
+      pcoll = pipeline | 'start' >> beam.Create(
+          TWO_FEATURES_EXAMPLES, reshuffle=False)
       predictions = pcoll | RunInference(engine_handler)
       assert_that(
           predictions,
diff --git a/sdks/python/apache_beam/transforms/util_test.py 
b/sdks/python/apache_beam/transforms/util_test.py
index a965ff33d82..63ce42726c1 100644
--- a/sdks/python/apache_beam/transforms/util_test.py
+++ b/sdks/python/apache_beam/transforms/util_test.py
@@ -75,6 +75,8 @@ from apache_beam.transforms.trigger import Repeatedly
 from apache_beam.transforms.util import GcpHsmGeneratedSecret
 from apache_beam.transforms.util import GcpSecret
 from apache_beam.transforms.util import Secret
+from apache_beam.transforms.util import _BatchSizeEstimator
+from apache_beam.transforms.util import _GlobalWindowsBatchingDoFn
 from apache_beam.transforms.window import FixedWindows
 from apache_beam.transforms.window import GlobalWindow
 from apache_beam.transforms.window import GlobalWindows
@@ -1258,6 +1260,53 @@ class BatchElementsTest(unittest.TestCase):
       checks = batches | beam.Map(check_batch_homogeneity)
       assert_that(checks, is_not_empty())
 
+  def test_global_batching_dofn_single_vs_multiple_bundles(self):
+    # This test directly verifies how bundling affects the batch sizes 
produced by
+    # the internal _GlobalWindowsBatchingDoFn of BatchElements.
+
+    # 1. Single Bundle Scenario:
+    # Four elements processed within the same start_bundle / finish_bundle 
lifecycle.
+    # min_batch_size = 2, max_batch_size = 2.
+    estimator = _BatchSizeEstimator(min_batch_size=2, max_batch_size=2)
+    dofn = _GlobalWindowsBatchingDoFn(estimator, element_size_fn=lambda x: 1)
+
+    dofn.start_bundle()
+    outputs = []
+    for elem in [1, 2, 3, 4]:
+      outputs.extend(dofn.process(elem))
+    outputs.extend(dofn.finish_bundle() or [])
+
+    # We should get exactly two batches of size 2.
+    batch_sizes = [len(wv.value) for wv in outputs]
+    self.assertEqual(batch_sizes, [2, 2])
+
+    # 2. Multiple Bundles Scenario (simulating elements split due to 
Reshuffle/GroupByKey):
+    # The runner splits elements into multiple bundles:
+    # Bundle 1 gets elements 1, 2, 3.
+    # Bundle 2 gets element 4.
+    estimator = _BatchSizeEstimator(min_batch_size=2, max_batch_size=2)
+    dofn = _GlobalWindowsBatchingDoFn(estimator, element_size_fn=lambda x: 1)
+
+    outputs = []
+    # Bundle 1
+    dofn.start_bundle()
+    for elem in [1, 2, 3]:
+      outputs.extend(dofn.process(elem))
+    outputs.extend(dofn.finish_bundle() or [])
+
+    # Bundle 2
+    dofn.start_bundle()
+    for elem in [4]:
+      outputs.extend(dofn.process(elem))
+    outputs.extend(dofn.finish_bundle() or [])
+
+    # The batch sizes will be [2, 1, 1] instead of [2, 2] because of bundle 
flushes.
+    # Specifically:
+    # - Bundle 1 emits a batch of 2, and then the remaining 1 element is 
flushed at finish_bundle (batch size 1).
+    # - Bundle 2 emits its 1 element at finish_bundle (batch size 1).
+    batch_sizes = [len(wv.value) for wv in outputs]
+    self.assertEqual(batch_sizes, [2, 1, 1])
+
 
 class SortAndBatchElementsTest(unittest.TestCase):
   """Tests for SortAndBatchElements transform."""

Reply via email to