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

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


The following commit(s) were added to refs/heads/master by this push:
     new 729b62e2fb [python] Avoid an extra shared-memory copy for LeRobot 
video batches (#10733)
729b62e2fb is described below

commit 729b62e2fbd8a2514ce376d1183c1e1830c50adf
Author: XiaoHongbo <[email protected]>
AuthorDate: Thu Oct 22 09:06:59 2026 +0800

    [python] Avoid an extra shared-memory copy for LeRobot video batches 
(#10733)
---
 .../pypaimon/multimodal/lerobot/dataset.py         | 18 +++++++--
 .../tests/video_decode_parallelism_test.py         | 43 ++++++++++++++++++++++
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/paimon-python/pypaimon/multimodal/lerobot/dataset.py 
b/paimon-python/pypaimon/multimodal/lerobot/dataset.py
index 5456ff7cf7..60386c82f4 100644
--- a/paimon-python/pypaimon/multimodal/lerobot/dataset.py
+++ b/paimon-python/pypaimon/multimodal/lerobot/dataset.py
@@ -1580,10 +1580,20 @@ def _decode_video_windows_with_pool(
                     shape = ((len(plans), window_size)
                              + tuple(frames.shape[1:]))
                     if output is None:
-                        output = torch.empty(
-                            shape, dtype=output_dtype, device=frames.device)
-                        if share_memory:
-                            output.share_memory_()
+                        if share_memory and frames.device.type == "cpu":
+                            empty = frames.new_empty(0, dtype=output_dtype)
+                            numel = 1
+                            for size in shape:
+                                numel *= size
+                            # Match DataLoader collation: allocate shared 
storage directly.
+                            storage = empty._typed_storage()._new_shared(
+                                numel, device=empty.device)
+                            output = empty.new(storage).resize_(shape)
+                        else:
+                            output = torch.empty(
+                                shape, dtype=output_dtype, 
device=frames.device)
+                            if share_memory:
+                                output.share_memory_()
                     elif tuple(output.shape) != shape \
                             or output.dtype != output_dtype:
                         raise ValueError(
diff --git a/paimon-python/pypaimon/tests/video_decode_parallelism_test.py 
b/paimon-python/pypaimon/tests/video_decode_parallelism_test.py
index 17fa76a124..dfeb41bbb5 100644
--- a/paimon-python/pypaimon/tests/video_decode_parallelism_test.py
+++ b/paimon-python/pypaimon/tests/video_decode_parallelism_test.py
@@ -391,6 +391,49 @@ class VideoDecodeParallelismTest(unittest.TestCase):
                 finally:
                     dataset.close()
 
+    def test_single_payload_shared_batch_matches_windows(self):
+        try:
+            import torch
+        except ImportError as error:
+            self.skipTest(str(error))
+        from pypaimon.multimodal.lerobot.dataset import _decode_video_windows
+        from pypaimon.table.row.blob import VideoFrameDescriptor
+
+        pixels = torch.arange(10 * 4 * 5 * 3).reshape(10, 4, 5, 
3).to(torch.uint8)
+        rows = {i: {"camera": VideoFrameDescriptor("video", 0, 1, i, -1, 
0).serialize()}
+                for i in range(10)}
+        windows = ([0, 0, 2], [2, 3, 4], [9, 7, 8], [0, 0, 2])
+        plans = [{"windows": {"camera": indices}} for indices in windows]
+        collator = self.collator()
+        decoder = SimpleNamespace(get_frames_at=lambda indices: 
SimpleNamespace(
+            data=pixels[indices].permute(0, 3, 1, 2)))
+        original_device = torch.get_default_device()
+        try:
+            with patch.object(collator, "_decoder", return_value=decoder), \
+                    patch("torch.get_num_threads", return_value=1), \
+                    patch.object(torch.Tensor, "share_memory_",
+                                 side_effect=AssertionError("Unexpected 
storage copy")):
+                for default_device in ("cpu", "meta"):
+                    torch.set_default_device(default_device)
+                    for uint8 in (True, False):
+                        result = _decode_video_windows(
+                            plans, rows, [collator],
+                            {"camera": {"dtype": "video", "shape": [4, 5, 
3]}}, uint8,
+                            return_batch=True, share_memory=True)["camera"]
+                        expected = torch.stack([pixels[w].permute(0, 3, 1, 2) 
for w in windows])
+                        if not uint8:
+                            expected = expected.float().div_(255)
+                        self.assertEqual(result.device.type, "cpu")
+                        self.assertTrue(torch.equal(result, expected))
+                        self.assertTrue(result.is_shared())
+                        self.assertTrue(result.is_contiguous())
+                        saved = result[3].clone()
+                        result[0].zero_()
+                        self.assertTrue(torch.equal(result[3], saved))
+        finally:
+            torch.set_default_device(original_device)
+            collator.close()
+
     def test_real_pyav_payloads_match_serial(self):
         try:
             import av

Reply via email to