Skip to content

GroupQueryAttention fails to load when total_sequence_length is computed from static shapes (ParseData type mismatch) #33865

Closed

Description

On 1.29.0 and 1.31.1 (not on 1.23.2), a GroupQueryAttention whose total_sequence_length is computed from static shapes, Squeeze(Cast(Shape(query)[1:2], to=int32)), fails at session creation, even with all graph optimizations disabled. Shape inference evaluates the value ahead of time but reads it as int64, although the Cast makes it int32. The same graph with the value as an int32 constant loads and runs. Exporters that compute the total length from the query's shape hit this on every static export.

Repro:

"""ONNX Runtime 1.29: a `GroupQueryAttention` whose `total_sequence_length` is computed from static shapes
(`Squeeze(Cast(Shape(query)[1:2], int32))`) fails to load: shape inference reads it as int64. The same graph with the
value as an int32 constant loads and runs."""

import numpy as np
import onnxruntime as ort
from onnx import TensorProto, helper, numpy_helper

BATCH, LENGTH, HEADS, KV_HEADS, HEAD_SIZE = 1, 7, 4, 2, 16


def build(constant_total: bool) -> bytes:
    nodes = [
        helper.make_node("Shape", ["query"], ["length64"], start=1, end=2),
        helper.make_node("Cast", ["length64"], ["length"], to=TensorProto.INT32),
        helper.make_node("Sub", ["length", "one"], ["last"]),
        helper.make_node("Expand", ["last", "batch"], ["seqlens_k"]),
    ]
    initializers = [
        numpy_helper.from_array(np.array([1], np.int32), "one"),
        numpy_helper.from_array(np.array([BATCH], np.int64), "batch"),
    ]
    if constant_total:
        initializers.append(numpy_helper.from_array(np.array(LENGTH, np.int32), "total"))
    else:
        nodes.append(helper.make_node("Squeeze", ["length"], ["total"]))
    nodes.append(
        helper.make_node(
            "GroupQueryAttention",
            ["query", "key", "value", "", "", "seqlens_k", "total"],
            ["output", "present_key", "present_value"],
            domain="com.microsoft",
            num_heads=HEADS,
            kv_num_heads=KV_HEADS,
        )
    )
    inputs = [
        helper.make_tensor_value_info("query", TensorProto.FLOAT, [BATCH, LENGTH, HEADS * HEAD_SIZE]),
        helper.make_tensor_value_info("key", TensorProto.FLOAT, [BATCH, LENGTH, KV_HEADS * HEAD_SIZE]),
        helper.make_tensor_value_info("value", TensorProto.FLOAT, [BATCH, LENGTH, KV_HEADS * HEAD_SIZE]),
    ]
    outputs = [helper.make_tensor_value_info(name, TensorProto.FLOAT, None) for name in ("output", "present_key", "present_value")]
    graph = helper.make_graph(nodes, "gqa", inputs, outputs, initializers)
    opsets = [helper.make_opsetid("", 20), helper.make_opsetid("com.microsoft", 1)]
    return helper.make_model(graph, opset_imports=opsets, ir_version=10).SerializeToString()


rng = np.random.default_rng(0)
feeds = {
    "query": rng.standard_normal((BATCH, LENGTH, HEADS * HEAD_SIZE)).astype(np.float32),
    "key": rng.standard_normal((BATCH, LENGTH, KV_HEADS * HEAD_SIZE)).astype(np.float32),
    "value": rng.standard_normal((BATCH, LENGTH, KV_HEADS * HEAD_SIZE)).astype(np.float32),
}
print("onnxruntime", ort.__version__)
for constant_total in (False, True):
    label = "total_sequence_length as an int32 constant" if constant_total else "total_sequence_length from Cast(Shape)"
    try:
        session = ort.InferenceSession(build(constant_total), providers=["CPUExecutionProvider"])
        session.run(None, feeds)
        print(f"  {label}: loads and runs")
    except Exception as error:
        print(f"  {label}: {str(error).splitlines()[0][:200]}")
onnxruntime 1.23.2
  total_sequence_length from Cast(Shape): loads and runs
  total_sequence_length as an int32 constant: loads and runs
onnxruntime 1.29.0
  total_sequence_length from Cast(Shape): [ONNXRuntimeError] : 1 : FAIL : Node () Op (GroupQueryAttention) [ShapeInferenceError] ParseData type mismatch for tensor: . Expected:int32 Actual:int64
  total_sequence_length as an int32 constant: loads and runs
onnxruntime 1.31.1
  total_sequence_length from Cast(Shape): [ONNXRuntimeError] : 1 : FAIL : Node () Op (GroupQueryAttention) [ShapeInferenceError] ParseData type mismatch for tensor: . Expected:int32 Actual:int64
  total_sequence_length as an int32 constant: loads and runs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions