Skip to content

[OpenVINO backend] supporting inference for Gemma, Mistral and GPT2 with ov backend #2310

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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
21 changes: 17 additions & 4 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,25 @@ jobs:
strategy:
fail-fast: false
matrix:
backend: [tensorflow, jax, torch]
backend: [tensorflow, jax, torch, openvino]
version: [keras-stable]
include:
- backend: jax
version: keras-3.5
- backend: jax
version: keras-nightly
- backend: openvino
version: keras-stable
python-version: '3.10'
runs-on: ubuntu-latest
env:
KERAS_BACKEND: ${{ matrix.backend }}
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.9
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: ${{ matrix.python-version || '3.9' }}
- name: Get pip cache dir
id: pip-cache
run: |
Expand All @@ -48,6 +51,10 @@ jobs:
run: |
pip install -r requirements.txt --progress-bar off
pip install --no-deps -e "." --progress-bar off
if [[ "${{ matrix.backend }}" == "openvino" ]]; then
pip uninstall -y keras
pip install git+https://github.com/Mohamed-Ashraf273/keras.git@gsoc2025 --upgrade --force-reinstall --progress-bar off
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be removed for final merge

fi
- name: Pin Keras 3.5
if: ${{ matrix.version == 'keras-3.5'}}
run: |
Expand All @@ -60,7 +67,13 @@ jobs:
pip install keras-nightly --progress-bar off
- name: Test with pytest
run: |
pytest keras_hub/
if [ "${{ matrix.backend }}" == "openvino" ]; then
IGNORE_FILE="openvino_excluded_tests.txt"
IGNORE_ARGS=$(awk '{print "--ignore=" $0}' "$IGNORE_FILE")
else
IGNORE_ARGS=""
fi
pytest keras_hub/ $IGNORE_ARGS
- name: Run integration tests
run: |
python pip_build.py --install
Expand Down
43 changes: 43 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import keras
import pytest
from keras.src.backend import backend


def pytest_addoption(parser):
Expand Down Expand Up @@ -70,6 +71,10 @@ def pytest_configure(config):
"markers",
"kaggle_key_required: mark test needing a kaggle key",
)
config.addinivalue_line(
"markers",
"requires_trainable_backend: mark test for trainable backend only",
)


def pytest_collection_modifyitems(config, items):
Expand Down Expand Up @@ -110,6 +115,44 @@ def pytest_collection_modifyitems(config, items):
if "kaggle_key_required" in item.keywords:
item.add_marker(kaggle_key_required)

openvino_skipped_tests = []
if backend() == "openvino":
from pathlib import Path

workspace_root = Path(__file__).resolve().parents[0]
file_path = workspace_root / "openvino_excluded_concrete_tests.txt"
with open(file_path, "r") as file:
openvino_skipped_tests = file.readlines()
# it is necessary to check if stripped line is not empty
# and exclude such lines
openvino_skipped_tests = [
line.strip() for line in openvino_skipped_tests if line.strip()
]
Comment on lines +125 to +130

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for reading and processing the skipped tests file can be made more concise and memory-efficient by iterating over the file object directly instead of using readlines().

Suggested change
openvino_skipped_tests = file.readlines()
# it is necessary to check if stripped line is not empty
# and exclude such lines
openvino_skipped_tests = [
line.strip() for line in openvino_skipped_tests if line.strip()
]
openvino_skipped_tests = [
line.strip() for line in file if line.strip()
]


requires_trainable_backend = pytest.mark.skipif(
backend() in ["openvino"],
reason="Trainer not implemented for OpenVINO backend.",
)

for item in items:
if "requires_trainable_backend" in item.keywords:
item.add_marker(requires_trainable_backend)
# also, skip concrete tests for openvino, listed in the special file
# this is more granular mechanism to exclude tests rather
# than using --ignore option
for skipped_test in openvino_skipped_tests:
if skipped_test in item.nodeid:
item.add_marker(
skip_if_backend(
"openvino",
"Not supported operation by openvino backend",
)
)


def skip_if_backend(given_backend, reason):
return pytest.mark.skipif(backend() == given_backend, reason=reason)


# Disable traceback filtering for quicker debugging of tests failures.
keras.config.disable_traceback_filtering()
4 changes: 4 additions & 0 deletions integration_tests/basic_usage_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import keras_hub


@unittest.skipIf(
keras.backend.backend() == "openvino",
"Skip for non-trainable backends like OpenVINO",
)
class BasicUsageTest(unittest.TestCase):
def test_transformer(self):
# Tokenize some inputs with a binary label.
Expand Down
2 changes: 2 additions & 0 deletions keras_hub/src/layers/modeling/alibi_bias_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import keras
import pytest
from keras import ops
from keras import random

Expand All @@ -7,6 +8,7 @@


class AlibiBiasTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
alibi_bias_max = 8
batch_size = 4
Expand Down
1 change: 1 addition & 0 deletions keras_hub/src/layers/modeling/anchor_generator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
reason="Bbox utils are not supported before keras < 3.8.0",
)
class AnchorGeneratorTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
images_shape = (8, 128, 128, 3)
self.run_layer_test(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from keras import ops
from keras import random

Expand All @@ -8,6 +9,7 @@


class CachedMultiHeadAttentionTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=CachedMultiHeadAttention,
Expand Down Expand Up @@ -75,6 +77,7 @@ def call(outputs, cache):
self.assertAllClose(output, no_loop_outputs)
self.assertAllClose(output_cache, no_loop_cache)

@pytest.mark.requires_trainable_backend
def test_training_propagation(self):
batch_size = 2
seq_len = 5
Expand Down
3 changes: 3 additions & 0 deletions keras_hub/src/layers/modeling/f_net_encoder_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from keras import ops
from keras import random

Expand All @@ -6,6 +7,7 @@


class FNetEncoderTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=FNetEncoder,
Expand All @@ -31,6 +33,7 @@ def test_value_error_when_invalid_kernel_initializer(self):
kernel_initializer="Invalid",
)

@pytest.mark.requires_trainable_backend
def test_training_propagation(self):
x = random.uniform(shape=(2, 4, 6))
layer = FNetEncoder(
Expand Down
2 changes: 2 additions & 0 deletions keras_hub/src/layers/modeling/masked_lm_head_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from keras import random

from keras_hub.src.layers.modeling.masked_lm_head import MaskedLMHead
Expand All @@ -8,6 +9,7 @@


class MaskedLMHeadTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=MaskedLMHead,
Expand Down
5 changes: 5 additions & 0 deletions keras_hub/src/layers/modeling/position_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ def call(self, inputs, start_index=0):
(start_index, 0),
(sequence_length, feature_length),
)
if keras.config.backend() == "openvino":
# Reshape to ensure we have the correct 2D shape after slicing
position_embeddings = ops.reshape(
position_embeddings, (sequence_length, feature_length)
)
return ops.broadcast_to(position_embeddings, shape)

def compute_output_shape(self, input_shape):
Expand Down
3 changes: 3 additions & 0 deletions keras_hub/src/layers/modeling/position_embedding_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import keras
import numpy as np
import pytest
from keras import ops
from keras import random

Expand All @@ -15,6 +16,7 @@ def custom_init(shape, dtype=None):


class PositionEmbeddingTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=PositionEmbedding,
Expand All @@ -26,6 +28,7 @@ def test_layer_behaviors(self):
expected_num_trainable_weights=1,
)

@pytest.mark.requires_trainable_backend
def test_layer_behaviors_4d(self):
self.run_layer_test(
cls=PositionEmbedding,
Expand Down
2 changes: 2 additions & 0 deletions keras_hub/src/layers/modeling/reversible_embedding_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import keras
import numpy as np
import pytest
from absl.testing import parameterized
from keras import ops
from keras import random
Expand All @@ -17,6 +18,7 @@ class ReversibleEmbeddingTest(TestCase):
("tie_weights", True),
("untie_weights", False),
)
@pytest.mark.requires_trainable_backend
def test_layer_behaviors_tied(self, tie_weights):
self.run_layer_test(
cls=ReversibleEmbedding,
Expand Down
3 changes: 3 additions & 0 deletions keras_hub/src/layers/modeling/rotary_embedding_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import keras
import numpy as np
import pytest
from keras import ops
from keras import random

Expand All @@ -8,6 +9,7 @@


class RotaryEmbeddingTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=RotaryEmbedding,
Expand All @@ -21,6 +23,7 @@ def test_layer_behaviors(self):
expected_output_shape=(2, 4, 6),
)

@pytest.mark.requires_trainable_backend
def test_layer_behaviors_4d(self):
self.run_layer_test(
cls=RotaryEmbedding,
Expand Down
3 changes: 3 additions & 0 deletions keras_hub/src/layers/modeling/sine_position_encoding_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import keras
import pytest
from keras import ops
from keras import random

Expand All @@ -9,6 +10,7 @@


class SinePositionEncodingTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=SinePositionEncoding,
Expand All @@ -19,6 +21,7 @@ def test_layer_behaviors(self):
expected_output_shape=(2, 4, 6),
)

@pytest.mark.requires_trainable_backend
def test_layer_behaviors_4d(self):
self.run_layer_test(
cls=SinePositionEncoding,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pytest
from keras import ops
from keras import random

Expand All @@ -9,6 +10,7 @@


class TokenAndPositionEmbeddingTest(TestCase):
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self):
self.run_layer_test(
cls=TokenAndPositionEmbedding,
Expand Down
4 changes: 4 additions & 0 deletions keras_hub/src/layers/modeling/transformer_decoder_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from absl.testing import parameterized
from keras import ops
from keras import random
Expand All @@ -11,6 +12,7 @@ class TransformerDecoderTest(TestCase):
("without_norm_first", False),
("with_norm_first", True),
)
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self, normalize_first):
self.run_layer_test(
cls=TransformerDecoder,
Expand All @@ -34,6 +36,7 @@ def test_layer_behaviors(self, normalize_first):
("without_norm_first", False),
("with_norm_first", True),
)
@pytest.mark.requires_trainable_backend
def test_layer_behaviors_with_cross_attention(self, normalize_first):
self.run_layer_test(
cls=TransformerDecoder,
Expand Down Expand Up @@ -89,6 +92,7 @@ def test_value_error_when_invalid_kernel_inititalizer(self):
kernel_initializer="Invalid",
)

@pytest.mark.requires_trainable_backend
def test_training_propagation(self):
decoder = TransformerDecoder(
intermediate_dim=4,
Expand Down
3 changes: 3 additions & 0 deletions keras_hub/src/layers/modeling/transformer_encoder_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import keras
import pytest
from absl.testing import parameterized
from keras import ops
from keras import random
Expand All @@ -12,6 +13,7 @@ class TransformerEncoderTest(TestCase):
("without_norm_first", False),
("with_norm_first", True),
)
@pytest.mark.requires_trainable_backend
def test_layer_behaviors(self, normalize_first):
self.run_layer_test(
cls=TransformerEncoder,
Expand Down Expand Up @@ -69,6 +71,7 @@ def test_value_error_when_invalid_kernel_inititalizer(self):
kernel_initializer="Invalid",
)

@pytest.mark.requires_trainable_backend
def test_training_propagation(self):
encoder = TransformerEncoder(
intermediate_dim=4,
Expand Down
Loading
Loading