Skip to content
Open
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2944c22
support for celu, one hot, avg pooling
danielenricocahall Oct 31, 2025
2b09bc3
ctc loss
danielenricocahall Oct 31, 2025
a37a7f4
revert test change
danielenricocahall Oct 31, 2025
2d6527e
Update keras/src/backend/openvino/nn.py
danielenricocahall Oct 31, 2025
b9d7618
Update keras/src/backend/openvino/nn.py
danielenricocahall Oct 31, 2025
a54b884
fix one hot with sparse check
danielenricocahall Oct 31, 2025
aa4ff5e
simplify pooling
danielenricocahall Oct 31, 2025
5421b36
handle dtype of one_hot
danielenricocahall Oct 31, 2025
2548b33
use swish op for silu
danielenricocahall Oct 31, 2025
80dcb9c
support for log_sigmoid
danielenricocahall Oct 31, 2025
467f418
address gemini feedback
danielenricocahall Oct 31, 2025
e5e5c0b
Update keras/src/backend/openvino/nn.py
danielenricocahall Oct 31, 2025
357f5e9
fix consolidated pool function
danielenricocahall Oct 31, 2025
a32fc57
enable testing
danielenricocahall Nov 6, 2025
4805c2e
fix max_pool call
danielenricocahall Nov 6, 2025
618cf53
fix dtype for ctc_loss
danielenricocahall Nov 6, 2025
51152ee
fix dtype for swish
danielenricocahall Nov 6, 2025
fb133d2
permit nn test to be run
danielenricocahall Nov 6, 2025
c745159
support for more activation functions, enabling tests that should sta…
danielenricocahall Nov 6, 2025
6397f92
support squareplus and sparse_plus
danielenricocahall Nov 6, 2025
38eca85
enable selu test
danielenricocahall Nov 6, 2025
fdb2d0a
support threshold
danielenricocahall Nov 6, 2025
a993580
selu test
danielenricocahall Nov 6, 2025
8714a49
Merge branch 'master' into openvino-nn-functions
danielenricocahall Nov 11, 2025
764e4fb
support scaled dot product attention
danielenricocahall Nov 11, 2025
93fd96d
Update keras/src/backend/openvino/nn.py
danielenricocahall Nov 11, 2025
c7b59f0
Update keras/src/ops/nn_test.py
danielenricocahall Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 94 additions & 14 deletions keras/src/backend/openvino/nn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from openvino import Type

from keras.src import backend
from keras.src.backend.openvino.core import OPENVINO_DTYPES
from keras.src.backend.openvino.core import OpenVINOKerasTensor
from keras.src.backend.openvino.core import get_ov_output

Expand All @@ -16,6 +17,23 @@ def relu6(x):
return OpenVINOKerasTensor(ov_opset.clamp(x, 0.0, 6.0).output(0))


def celu(x, alpha=1.0):
x = get_ov_output(x)
const_zero = get_ov_output(0.0, x.get_element_type())
const_alpha = get_ov_output(alpha, x.get_element_type())
const_one = get_ov_output(1.0, x.get_element_type())
exp_x_div_alpha = ov_opset.exp(ov_opset.divide(x, const_alpha)).output(0)
negative_branch = ov_opset.multiply(
const_alpha, ov_opset.subtract(exp_x_div_alpha, const_one)
)

celu_x = ov_opset.add(
ov_opset.maximum(x, const_zero).output(0),
ov_opset.minimum(negative_branch, const_zero).output(0),
)
return OpenVINOKerasTensor(celu_x.output(0))


def sigmoid(x):
x = get_ov_output(x)
return OpenVINOKerasTensor(ov_opset.sigmoid(x).output(0))
Expand All @@ -38,14 +56,14 @@ def softsign(x):

def silu(x):
x = get_ov_output(x)
return OpenVINOKerasTensor(
ov_opset.multiply(x, ov_opset.sigmoid(x)).output(0)
)
return OpenVINOKerasTensor(ov_opset.swish(x).output(0))


def log_sigmoid(x):
raise NotImplementedError(
"`log_sigmoid` is not supported with openvino backend"
x = get_ov_output(x)
neg_x = ov_opset.negative(x)
return OpenVINOKerasTensor(
ov_opset.negative(ov_opset.softplus(neg_x)).output(0)
)


Expand Down Expand Up @@ -128,8 +146,13 @@ def max_pool(
padding="valid",
data_format=None,
):
raise NotImplementedError(
"`max_pool` is not supported with openvino backend"
return _pool(
inputs,
pool_size,
ov_opset.max_pool,
strides=strides,
padding=padding,
data_format=data_format,
)


Expand All @@ -140,11 +163,50 @@ def average_pool(
padding="valid",
data_format=None,
):
raise NotImplementedError(
"`average_pool` is not supported with openvino backend"
return _pool(
inputs,
pool_size,
ov_opset.avg_pool,
strides=strides,
padding=padding,
data_format=data_format,
)


def _pool(
inputs,
pool_size,
pooling_func,
strides=None,
padding="valid",
data_format=None,
):
data_format = backend.standardize_data_format(data_format)
inputs = get_ov_output(inputs)

num_spatial_dims = inputs.get_partial_shape().rank.get_length() - 2
if isinstance(pool_size, int):
pool_size = [pool_size] * num_spatial_dims

if strides is None:
strides = pool_size

strides = _adjust_strides_dilation(strides, num_spatial_dims)
pad_mode, pads_begin, pads_end = _adjust_padding(padding)
inputs = _adjust_input(inputs, num_spatial_dims, data_format)
pooled = pooling_func(
inputs,
kernel=pool_size,
strides=strides,
auto_pad=pad_mode,
exclude_pad=True,
pads_begin=pads_begin,
pads_end=pads_end,
).output(0)
adjusted_pooled = _adjust_outputs(pooled, num_spatial_dims, data_format)
return OpenVINOKerasTensor(adjusted_pooled)


def _adjust_strides_dilation(
x,
num_spatial_dims,
Expand Down Expand Up @@ -374,9 +436,22 @@ def conv_transpose(


def one_hot(x, num_classes, axis=-1, dtype=None, sparse=False):
raise NotImplementedError(
"`one_hot` is not supported with openvino backend"
)
if sparse:
raise ValueError("`sparse=True` is not supported with openvino backend")
x = get_ov_output(x)
if dtype is None:
dtype = backend.floatx()
ov_dtype = OPENVINO_DTYPES[dtype]
on_value = get_ov_output(1, ov_dtype)
off_value = get_ov_output(0, ov_dtype)
one_hot_encoded = ov_opset.one_hot(
x,
depth=num_classes,
axis=axis,
on_value=on_value,
off_value=off_value,
).output(0)
return OpenVINOKerasTensor(one_hot_encoded)


def multi_hot(x, num_classes, axis=-1, dtype=None, sparse=False):
Expand Down Expand Up @@ -465,9 +540,14 @@ def batch_normalization(


def ctc_loss(target, output, target_length, output_length, mask_index=0):
raise NotImplementedError(
"`ctc_loss` is not supported with openvino backend"
target = get_ov_output(target)
output = get_ov_output(output)
target_length = get_ov_output(target_length)
output_length = get_ov_output(output_length)
ctc_loss_ = ov_opset.ctc_loss(
output, output_length, target, target_length, blank_index=mask_index
)
return OpenVINOKerasTensor(ctc_loss_.output(0))


def ctc_decode(
Expand Down