Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / data / omni / metadata.py: 83%
24 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 07:18 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 07:18 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Metadata for whole, already-transformed Omni image-text conversations."""
17from collections.abc import Mapping
18from typing import Any
20from hyper_parallel.distributed_data.schema import SampleMetadata, WorkloadCost
23def vlm_sample_metadata(sample: Mapping[str, Any]) -> SampleMetadata:
24 """Estimate visual work without changing native VLM sample fields.
26 Args:
27 sample: One CPU Omni transform output before collation.
29 Returns:
30 Physical padded sequence width for capacity and raw image patch count
31 for encoder cost. LLM cost uses the padded width: the native dense
32 text computation does not disappear at masked padding positions.
34 Raises:
35 ValueError: If sequence or image tensors do not follow the native schema.
37 Note:
38 These are workload proxies, not calibrated time estimates. Image patches
39 come from the processor's actual grid, not a hard-coded patch/merge size.
40 Decode/transform has already run on the Reader and is not balanced here.
41 """
42 input_ids = sample.get("input_ids")
43 grid = sample.get("image_grid_thw")
44 pixels = sample.get("pixel_values")
45 if input_ids is None or input_ids.ndim != 1 or input_ids.shape[0] == 0:
46 raise ValueError("VLM metadata requires one non-empty 1-D input_ids tensor before collation")
47 if grid is None or grid.ndim != 2 or grid.shape[1] != 3:
48 raise ValueError("VLM metadata requires image_grid_thw with shape [num_images, 3]")
49 if grid.device.type != "cpu":
50 raise ValueError("VLM metadata must be extracted on CPU before device transfer")
51 image_patches = 0
52 for dimensions in grid.tolist():
53 if any(not isinstance(dimension, int) or isinstance(dimension, bool) for dimension in dimensions):
54 raise ValueError("VLM image_grid_thw must contain integer patch dimensions")
55 if any(dimension <= 0 for dimension in dimensions):
56 raise ValueError("VLM image_grid_thw dimensions must be positive")
57 image_patches += dimensions[0] * dimensions[1] * dimensions[2]
58 if pixels is None or pixels.ndim != 2 or pixels.shape[0] != image_patches:
59 raise ValueError("VLM pixel_values rows must equal the raw patch count from image_grid_thw")
60 seq_len = int(input_ids.shape[0])
61 return SampleMetadata(
62 pack_tokens=seq_len,
63 features={"P": seq_len, "D": 0, "image_patches": image_patches},
64 cost=WorkloadCost(encoder=float(image_patches), llm=float(seq_len)),
65 )