-
Notifications
You must be signed in to change notification settings - Fork 2.6k
add evaluate method for einsum #30934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
add evaluate method for einsum #30934
Conversation
Hi @Mohamed-Ashraf273, could you share reproducer to this issue? In OV Einsum and many other ops don't have evaluate in core implementation by design to reduce binary size. |
import numpy as np
from keras import ops
from openvino import Model, compile_model
index = ops.convert_to_tensor(0, np.int32)
arr = ops.convert_to_tensor(np.array([[1, 2], [3, 4]]))
mask = ops.convert_to_tensor(np.array([[1, 0], [0, 1]]))
loop_vars = (index, arr, mask)
index = ops.convert_to_tensor(0, np.int32)
arr = ops.convert_to_tensor(np.array([[1, 2], [3, 4]]).astype(np.float16))
mask = ops.convert_to_tensor(np.array([[1, 0], [0, 1]]).astype(np.float16))
# Add two tensors for einsum
a = ops.convert_to_tensor(np.random.randn(1, 1, 2048).astype(np.float16))
b = ops.convert_to_tensor(np.random.randn(1, 2048, 256).astype(np.float16))
loop_vars = (index, arr, mask, a, b)
def cond(index, arr, mask, a, b):
row_idx = ops.mod(index, 2)
arr_slice = ops.slice(arr, [row_idx, 0], [1, 2])
sum_slice = ops.sum(arr_slice, axis=[0, 1])
index_lt_4 = ops.less(index, 4)
sum_lt_30 = ops.less(sum_slice, 30)
return ops.logical_and(index_lt_4, sum_lt_30)
def body(index, arr, mask, a, b):
row_idx = ops.mod(index, 2)
mask_slice = ops.slice(mask, [row_idx, 0], [1, 2])
arr_slice = ops.slice(arr, [row_idx, 0], [1, 2])
mask_slice = ops.reshape(mask_slice, [1, 2])
arr_slice = ops.reshape(arr_slice, [1, 2])
arr_slice_updated = ops.where(mask_slice == 1, ops.multiply(arr_slice, 2), arr_slice + 5)
arr_parts = []
for i in range(2):
current_row_idx = ops.mod(index, 2)
is_target_row = ops.equal(i, current_row_idx)
part = ops.where(is_target_row, arr_slice_updated, ops.slice(arr, [i, 0], [1, 2]))
arr_parts.append(part)
arr_updated = ops.concatenate(arr_parts, axis=0)
mask_next = 1 - mask
arr_final = arr_updated + index
# Use einsum_out: add its sum to arr_final (broadcasted)
einsum_out = ops.einsum('btd,ndh->btnh', a, b)
einsum_sum = ops.sum(einsum_out, axis=[0, 1, 2, 3]) # scalar
arr_final = arr_final + einsum_sum # broadcast add
return (index + 1, arr_final, mask_next, a, b)
result = ops.while_loop(cond, body, loop_vars, maximum_iterations=4)
final_index, final_arr, final_mask = result[:3]
ov_outputs = [final_index.output, final_arr.output, final_mask.output]
ov_model = Model(results=ov_outputs, parameters=[])
#save_model(ov_model, "while_loop_model.xml")
compiled = compile_model(ov_model, "CPU")
outputs = compiled({})
print("Final index:", outputs[0])
print("Final array:\n", outputs[1])
print("Final mask:\n", outputs[2])
Hi @mmikolajcz |
Thanks @Mohamed-Ashraf273, I was able to reproduce it using keras master patched with https://github.com/keras-team/keras/pull/21369/files#diff-b15baa80baacd1d26bf238fc6c762baefee763b860076b8ee80308afd80cfa82 openvino/src/common/transformations/src/transformations/common_optimizations/moc_transformations.cpp Line 174 in c458a6b
@itikhono from your experience with transformations, have you encountered something similar or do you know how to proceed? |
Thanks for the solution. It worked. |
Details:
Identified that the einsum operation was not functioning properly due to the absence of an overridden evaluate method and no optimized kernel.
Implemented the evaluate method for einsum to ensure correct execution within
loop
nodes.Tested the fix.
Tickets:
GSoC2025 – pipeline enablement on Keras with OpenVINO backend
@rkazants