diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b9577bbb2..2c4c3f971 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -91,6 +91,7 @@ jobs: device: openvino suffixes: '-openvino' platforms: linux/amd64 + runner-mapping: '{"linux/amd64": "pokedex-large"}' - image: immich-machine-learning device: armnn suffixes: '-armnn' diff --git a/machine-learning/Dockerfile b/machine-learning/Dockerfile index 25e367b14..fdb070203 100644 --- a/machine-learning/Dockerfile +++ b/machine-learning/Dockerfile @@ -2,7 +2,48 @@ ARG DEVICE=cpu FROM python:3.13-slim-trixie@sha256:9d2e5553305c7c7b0097999bb17187c69b921ccd6bc9d40e4bb5ebe652c00285 AS builder-cpu -FROM builder-cpu AS builder-openvino +FROM python:3.13-slim-trixie@sha256:7c61056e61ac89e852de05f3dc6fa51a6dd2181797bceed46aa725dd7cb2cd3b AS builder-openvino + +# renovate: datasource=github-releases depName=microsoft/onnxruntime +ARG ONNXRUNTIME_VERSION="v1.30.0" +ENV VIRTUAL_ENV=/opt/venv \ + OpenVINO_DIR=/opt/venv/lib/python3.13/site-packages/openvino/cmake \ + CCACHE_DIR=/ccache + +RUN apt-get update && apt-get install -y --no-install-recommends g++ make patch git cmake ccache patchelf +RUN git clone --depth 1 --branch "${ONNXRUNTIME_VERSION}" https://github.com/microsoft/onnxruntime /code/onnxruntime + +COPY --from=ghcr.io/astral-sh/uv:0.8.15@sha256:a5727064a0de127bdb7c9d3c1383f3a9ac307d9f2d8a391edc7896c54289ced0 /uv /uvx /bin/ +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --frozen --extra openvino --group onnxruntime-openvino-build --no-dev --no-editable --no-install-project --no-progress --active --link-mode copy + +WORKDIR /code/onnxruntime +# Note: the `parallel` setting uses a substantial amount of RAM +RUN --mount=type=cache,target=/ccache \ + /opt/venv/bin/python tools/ci_build/build.py \ + --allow_running_as_root \ + --build_dir build \ + --config Release \ + --build_wheel \ + --update \ + --build \ + --parallel 16 \ + --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF \ + --skip_tests \ + --use_openvino CPU \ + --use_cache \ + --compile_no_warning_as_error + +# bundle openvino into the wheel as the published one does, so it is what the EP loads beside it +WORKDIR /code/onnxruntime/build/Release/dist +RUN /opt/venv/bin/wheel unpack onnxruntime_openvino-*.whl && \ + capi=$(echo onnxruntime_openvino-*/onnxruntime/capi) && \ + cp /opt/venv/lib/python3.13/site-packages/openvino/libs/* "$capi" && \ + mv "$capi"/libopenvino_c.so.* "$capi/libopenvino_c.so" && \ + patchelf --set-rpath '$ORIGIN' --force-rpath "$capi/libonnxruntime_providers_openvino.so" && \ + /opt/venv/bin/wheel pack onnxruntime_openvino-*/ -d /opt FROM python:3.13-slim-bookworm@sha256:2325bb286ec344af3e5898cc224b5844e2707ac6e26b1632516fd3edc84a5e26 AS builder-cuda @@ -37,7 +78,8 @@ COPY --from=ghcr.io/astral-sh/uv:0.8.15@sha256:a5727064a0de127bdb7c9d3c1383f3a9a RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - uv sync --frozen --extra ${DEVICE} --no-dev --no-editable --no-install-project --compile-bytecode --no-progress --active --link-mode copy + uv sync --frozen --extra ${DEVICE} --no-dev --no-editable --no-install-project --compile-bytecode --no-progress --active --link-mode copy && \ + if [ "$DEVICE" = "openvino" ]; then uv pip install --no-deps /opt/onnxruntime_openvino-*.whl; fi FROM python:3.13-slim-trixie@sha256:9d2e5553305c7c7b0097999bb17187c69b921ccd6bc9d40e4bb5ebe652c00285 AS prod-cpu diff --git a/machine-learning/immich_ml/sessions/ort.py b/machine-learning/immich_ml/sessions/ort.py index 805d19205..8f96a29c8 100644 --- a/machine-learning/immich_ml/sessions/ort.py +++ b/machine-learning/immich_ml/sessions/ort.py @@ -359,7 +359,7 @@ def _overrides(policy: ShapePolicy, pins: Mapping[str, int]) -> list[tuple[str, @cache def _intel_gpu(device: str) -> Device: - """The IP version and execution units OpenVINO keys its blobs by, and the driver it checks them against.""" + """The IP version, release and execution units OpenVINO keys its blobs by, and the driver it checks them against.""" ov = ctypes.CDLL(str(Path(ort.__file__).parent / "capi" / "libopenvino_c.so")) core, wanted = ctypes.c_void_p(), ctypes.c_char_p() ov.ov_core_create(ctypes.byref(core)) @@ -367,6 +367,10 @@ def _intel_gpu(device: str) -> Device: uuid = wanted.value ov.ov_free(wanted) ov.ov_core_free(core) + release = (ctypes.c_char_p * 2)() # ov_version_t: build number, description + ov.ov_get_openvino_version(release) + openvino = (release[0] or b"").decode() + ov.ov_version_free(release) cl, gpu = ctypes.CDLL("libOpenCL.so.1"), ctypes.c_uint64(1 << 2) # CL_DEVICE_TYPE_GPU platforms, devices, count = (ctypes.c_void_p * 8)(), (ctypes.c_void_p * 8)(), ctypes.c_uint32() cl.clGetPlatformIDs(8, platforms, ctypes.byref(count)) @@ -381,7 +385,7 @@ def _intel_gpu(device: str) -> Device: cl.clGetDeviceInfo(ctypes.c_void_p(handle), key, ctypes.sizeof(value), ctypes.byref(value), None) if bytes(own).hex().encode() == uuid: version = f"{ip.value >> 22}.{ip.value >> 14 & 0xFF}.{ip.value & 0x3FFF}" - return Device(f"{version}-{units.value}eu", driver.value.decode()) + return Device(f"{version}-{units.value}eu", f"{driver.value.decode()} {openvino}") raise LookupError(f"OpenCL has no GPU with the UUID of OpenVINO's {device}") diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 0656445e7..8f64cde52 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -45,6 +45,8 @@ lint = [ { include-group = "types" }, ] dev = ["locust>=2.15.1", { include-group = "test" }, { include-group = "lint" }] +# the image replaces onnxruntime-openvino with one built against and bundling this openvino +onnxruntime-openvino-build = ["openvino>=2026.4.1,<2027", "setuptools", "wheel"] [project.optional-dependencies] cpu = ["onnxruntime>=1.23.2,<2"] diff --git a/machine-learning/uv.lock b/machine-learning/uv.lock index 77a91aec1..c0656e4c1 100644 --- a/machine-learning/uv.lock +++ b/machine-learning/uv.lock @@ -744,6 +744,11 @@ lint = [ { name = "types-simplejson" }, { name = "types-ujson" }, ] +onnxruntime-openvino-build = [ + { name = "openvino" }, + { name = "setuptools" }, + { name = "wheel" }, +] test = [ { name = "httpx" }, { name = "pytest" }, @@ -813,6 +818,11 @@ lint = [ { name = "types-simplejson", specifier = ">=3.20.0.20250218" }, { name = "types-ujson", specifier = ">=5.10.0.20240515" }, ] +onnxruntime-openvino-build = [ + { name = "openvino", specifier = ">=2026.4.1,<2027" }, + { name = "setuptools" }, + { name = "wheel" }, +] test = [ { name = "httpx", specifier = ">=0.24.1" }, { name = "pytest", specifier = ">=7.3.1" }, @@ -1434,7 +1444,7 @@ name = "opencv-python" version = "4.11.0.86" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/17/06/68c27a523103dad5837dc5b87e71285280c4f098c60e4fe8a8db6486ab09/opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4", size = 95171956, upload-time = "2025-01-16T13:52:24.737Z" } @@ -1457,6 +1467,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ad/8d/db8673846ee53cbb5de4c2b4decc11cf733e203eb7d5146297869f69bd48/opencv_python_headless-4.14.0.94-cp37-abi3-win_amd64.whl", hash = "sha256:cbed65415b8f6a9541c705afe3e64795840524d0ff3bc58f507826284a1dc64b", size = 41028030, upload-time = "2026-07-28T18:32:36.724Z" }, ] +[[package]] +name = "openvino" +version = "2026.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "openvino-telemetry" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/4e/865889882a3be23beaf9808f93069c05e2eb8c8ff4e9b913568fc0383ce4/openvino-2026.4.1-22982-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:726ac547b8474a5e7b145bc1ae5a8bb6fbcbb60b79bd9a611c67eec2c74b7a5f", size = 33341733, upload-time = "2026-10-01T09:58:47.515Z" }, + { url = "https://files.pythonhosted.org/packages/ec/3a/2a173ac1ad749ff0b041788eefc1ade0d410231fedfc43f77474f3b806cc/openvino-2026.4.1-22982-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6b4375c17ddcac83a5180349e2e2bb811185c261066e2a920659892d58ef0e3b", size = 59144434, upload-time = "2026-10-01T09:58:51.34Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d7/390c0ec5b81b6e089b012aaba6a2dc14f3ac7c52bfd78d10f074e72616ab/openvino-2026.4.1-22982-cp312-cp312-manylinux_2_35_aarch64.whl", hash = "sha256:82efccb2f9f1bdc7e5a1996e05a3b719ebff9232dd54b44150d6d2e983a86b7d", size = 30332437, upload-time = "2026-10-01T09:58:54.385Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/66a61b7cfccea1dfa20e95a04b4157f07a0e4dc3f7e894b22a92abb8822b/openvino-2026.4.1-22982-cp312-cp312-win_amd64.whl", hash = "sha256:4e04316abff1b99e29b8cbd38deaef9bde4739eba216d982d4b3981e456ecd87", size = 84964415, upload-time = "2026-10-01T09:58:59.18Z" }, + { url = "https://files.pythonhosted.org/packages/3e/75/66fc1f74a4c9cdc7bf2d4773dd7e199589ec87884d10b9e58b4eca1e3a50/openvino-2026.4.1-22982-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:60496e3153122913c8a2fa69d86b3a77ccc4e2469db87d76eb8acb49a5d22d63", size = 33341974, upload-time = "2026-10-01T09:59:03.149Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8b/d2fb2611cd8160cb4c0e5401b9d87312961d77891eade431381e396a8d83/openvino-2026.4.1-22982-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a9b637846c579d7b81b17b6585e0c7b1947574e8d13cf83d7307ce50cd2c352e", size = 59142703, upload-time = "2026-10-01T09:59:06.972Z" }, + { url = "https://files.pythonhosted.org/packages/4f/2b/e3b9cb3870cfeb0f9b2ad0f9adba18e06e0168e0c72ed14a11adb66982e1/openvino-2026.4.1-22982-cp313-cp313-manylinux_2_35_aarch64.whl", hash = "sha256:fc45339ff7d539de76e6d7b04135c120504c797cfc8c2a0dde3d2d616b30c758", size = 30333747, upload-time = "2026-10-01T09:59:10.03Z" }, + { url = "https://files.pythonhosted.org/packages/35/e2/917952cd8d21351d10bf0ce694421de92a2b14a6269f0ba13d2504fcf6a9/openvino-2026.4.1-22982-cp313-cp313-win_amd64.whl", hash = "sha256:37c270c99d6de23439965e97cb5106389d3c8985f3b8bb90909a6ea0270db3f2", size = 84964362, upload-time = "2026-10-01T09:59:15.467Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0d/113b7dad0f3a2a87b394898bfafa810c50a97ebfa10e91ab03a9bbce11d6/openvino-2026.4.1-22982-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f57d1cc75c77c18b2be8ab628d8e0a8e01f4be44f521823b6fba7ede31d708d3", size = 33317735, upload-time = "2026-10-01T09:59:20.236Z" }, + { url = "https://files.pythonhosted.org/packages/77/cf/830aff97404d73b8ada3ba3f02a626089a384299322cb94b52c37eaebd18/openvino-2026.4.1-22982-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3631dd889dccf3d5087775948590a6609a662f90c24a9cf85bb4dfa0cdd7fd2f", size = 59145072, upload-time = "2026-10-01T09:59:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/5d/97/6fe7443b66179413c21cca9e36267e22711398debdd3ba4ad59fa2f933b3/openvino-2026.4.1-22982-cp314-cp314-manylinux_2_35_aarch64.whl", hash = "sha256:b70a01f6961bf8fe4b647b14fb122be4d30ece02292a9831f9241a64be089676", size = 30342100, upload-time = "2026-10-01T09:59:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/56/bc/5ebb236e5c10155d7693ea282308b9dbfe4142c5f3350a77203ab859684b/openvino-2026.4.1-22982-cp314-cp314-win_amd64.whl", hash = "sha256:96d5ecb8cca4d61a3eee754c9e477702509cf782eb45596c653a00ddb2176d96", size = 84966232, upload-time = "2026-10-01T09:59:32.323Z" }, + { url = "https://files.pythonhosted.org/packages/14/b0/a0e6a1b0938ed87107a1db91d27c0f57168e20b066a3681adc430c51cd46/openvino-2026.4.1-22982-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:24c73d3c61a8b71c09bf512a294d37ff8ea6e4b0c65c1b136bb842bbbd6c9c31", size = 33553140, upload-time = "2026-10-01T09:59:35.894Z" }, + { url = "https://files.pythonhosted.org/packages/e6/81/f437957dbb73002e38a3c25cfcb0eddf3faa3b328bae586836d40ff13cc2/openvino-2026.4.1-22982-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:645e8788370b1037cc21d19078f2f235478292e23938b00ab4fe0d2614a5f7d0", size = 59189953, upload-time = "2026-10-01T09:59:39.877Z" }, + { url = "https://files.pythonhosted.org/packages/da/d1/3904a8913f717d92ef383e7f105425944012ed73c816d85f790dc2fb5923/openvino-2026.4.1-22982-cp314-cp314t-manylinux_2_35_aarch64.whl", hash = "sha256:6c5672d6cc0fba4e22fd8d1352ffd7e395f6135da741e002bfad7a0344c183f2", size = 27452183, upload-time = "2026-10-01T09:59:43.135Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b4/0f24c785d915269fa2fc087cc2242b1216f6ed2584598ba0f8bada2d53e9/openvino-2026.4.1-22982-cp314-cp314t-win_amd64.whl", hash = "sha256:c383422d3e7e457441ec88911da0b16ed5132f55b8c9fb21411749d3eff90a60", size = 85132406, upload-time = "2026-10-01T09:59:47.575Z" }, +] + +[[package]] +name = "openvino-telemetry" +version = "2025.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/8a/89d82f1a9d913fb266c2e6dc2f6030935db24b7152963a8db6c4f039787f/openvino_telemetry-2025.2.0.tar.gz", hash = "sha256:8bf8127218e51e99547bf38b8fb85a8b31c9bf96e6f3a82eb0b3b6a34155977c", size = 18894, upload-time = "2025-07-07T10:29:51.159Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ac/5ab0ca0aa269ad3c73f7bfc3801b10e5f56f75a31bf68c1ae8bd51cf70a4/openvino_telemetry-2025.2.0-py3-none-any.whl", hash = "sha256:bcb667e83a44f202ecf4cfa49281715c6d7e21499daec04ff853b7f964833599", size = 25227, upload-time = "2025-07-07T10:29:50.189Z" }, +] + [[package]] name = "orjson" version = "3.12.0" @@ -2451,6 +2497,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/6e/e792999e816d19d7fcbfa94c730936750036d65656a76a5a688b57a656c4/werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8", size = 227274, upload-time = "2024-05-05T23:10:29.567Z" }, ] +[[package]] +name = "wheel" +version = "0.45.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, +] + [[package]] name = "wsproto" version = "1.2.0"