From f6799699cc24b6c644a540d73da2a1dddbbe8236 Mon Sep 17 00:00:00 2001 From: "Peter B. Johnson" Date: Wed, 9 Sep 2026 21:30:10 +0100 Subject: [PATCH] Declare an ONNX inference backend for basic-pitch Basic Pitch chooses a backend at import from whichever of CoreML, TensorFlow, TFLite or ONNX Runtime happens to be installed, and raises NameError while defining ICASSP_2022_MODEL_PATH when it finds none. It declares those backends behind platform markers, so which one arrives depends on the machine doing the install. On linux/arm64 the tensorflow wheel is an empty shim requiring tensorflow-cpu-aws, which never resolved into our lock, so no backend was installed at all. The worker then died at import and the container never started. CI and the AWS build are amd64 and so never saw it. Declare the backend explicitly with the "onnx" extra. ONNX Runtime is the one backend with wheels for every platform we build for. Add tests covering the installed backend, the name whose absence takes the container down, and our own model loader. Co-Authored-By: Claude Opus 5 --- evaluation_function/backend_test.py | 64 +++++++++++++++++++++++++++++ poetry.lock | 53 ++++++++++++++++++++++-- pyproject.toml | 5 ++- 3 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 evaluation_function/backend_test.py diff --git a/evaluation_function/backend_test.py b/evaluation_function/backend_test.py new file mode 100644 index 0000000..82a48c4 --- /dev/null +++ b/evaluation_function/backend_test.py @@ -0,0 +1,64 @@ +""" +backend_test.py +=============== +Tests that the audio-to-MIDI transcription backend is actually available. + +Basic Pitch does not ship inference code of its own. It picks a backend at +import time from whichever of CoreML, TensorFlow, TFLite or ONNX Runtime it +finds installed, and if it finds none it fails while defining +ICASSP_2022_MODEL_PATH: + + NameError: name '_default_model_type' is not defined + +Basic Pitch declares those backends behind platform markers, so which one +arrives depends on the machine doing the install: + + - macOS -> coremltools + - Linux/amd64 -> tensorflow + - Linux/arm64 -> the `tensorflow` wheel is an empty shim that requires + `tensorflow-cpu-aws`, which does not get resolved into + our lock, so no backend is installed at all + +The third case is not hypothetical: it is every container built on an Apple +Silicon machine, where the worker dies at import and the container never +starts. CI and the AWS build are amd64, so they never see it. + +The fix is to stop relying on those markers and declare a backend +explicitly. ONNX Runtime is the one with wheels for every platform we +build for, so these tests assert it is present. + +Run locally with: python -m pytest evaluation_function/backend_test.py -v +""" + +import importlib + + +def test_onnx_runtime_is_installed(): + """ + A backend must be declared explicitly rather than inherited from a + platform marker, so that arm64 containers get one too. + """ + assert importlib.util.find_spec("onnxruntime") is not None, ( + "onnxruntime is not installed; basic-pitch needs an explicitly " + "declared inference backend so that every build platform gets one" + ) + + +def test_basic_pitch_resolves_a_model_path(): + """ + The symptom that takes the container down. Importing this name fails + with NameError when no backend is installed. + """ + from basic_pitch import ICASSP_2022_MODEL_PATH + + assert ICASSP_2022_MODEL_PATH is not None + + +def test_model_loads_through_our_own_loader(): + """ + Guards the entry point the evaluation function actually calls, so a + missing or broken backend fails here rather than at container start. + """ + from .audio_processing import load_basic_pitch_model + + assert load_basic_pitch_model() is not None diff --git a/poetry.lock b/poetry.lock index b065fde..65a6478 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. [[package]] name = "absl-py" @@ -162,6 +162,7 @@ coremltools = {version = "*", markers = "platform_system == \"Darwin\""} librosa = ">=0.8.0" mir-eval = ">=0.6" numpy = ">=1.18" +onnxruntime = {version = "*", optional = true, markers = "extra == \"onnx\""} pretty-midi = ">=0.2.9" resampy = ">=0.2.2,<0.4.3" scikit-learn = "*" @@ -1063,7 +1064,6 @@ description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" groups = ["main"] -markers = "platform_system != \"Darwin\"" files = [ {file = "flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4"}, ] @@ -2148,6 +2148,7 @@ sympy = ">=1.12,<2.0" ujson = "5.10.0" [package.extras] +gcs = ["google-cloud-storage (>=2.18,<3.0)"] http = ["fastapi (>=0.115.0,<0.116.0)"] ipc = ["pywin32 (>=306,<307) ; sys_platform == \"win32\""] parsing = ["antlr4-python3-runtime (==4.13.2)", "lark (==1.2.2)", "latex2sympy @ git+https://github.com/purdue-tlt/latex2sympy.git@1.12.0"] @@ -2156,7 +2157,7 @@ parsing = ["antlr4-python3-runtime (==4.13.2)", "lark (==1.2.2)", "latex2sympy @ type = "git" url = "https://github.com/lambda-feedback/toolkit-python.git" reference = "main" -resolved_reference = "8a687d35284c156f045dde4da15a2e717112c9de" +resolved_reference = "ae52fa6f23c585f2595e6f32dc56ac8984c8fc50" [[package]] name = "libclang" @@ -2941,6 +2942,50 @@ rsa = ["cryptography (>=3.0.0)"] signals = ["blinker (>=1.4.0)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] +[[package]] +name = "onnxruntime" +version = "1.29.0" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +optional = false +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "onnxruntime-1.29.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:07c5907474dec4a2792fd7626b753dc66707808385a6d9eecf993db0066a9d0f"}, + {file = "onnxruntime-1.29.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:16925ef8497e2c07e4b5ae15b504079b3ab3f65e22c58efd10dde0f3caea969a"}, + {file = "onnxruntime-1.29.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:85f8e8406c52658735fe5c7fbfd3ebaa1ed340768324f6252e4274e374580a23"}, + {file = "onnxruntime-1.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:0d4f427afac434b0070fe992b540ddf20a7aff2265f760f314d91331935b6b98"}, + {file = "onnxruntime-1.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:4eae472cf7dc3107dec1bb53cd6d142d1964616d08aae48654cd4254b2363c4b"}, + {file = "onnxruntime-1.29.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3a3814c041251d6a77fdf513fb282056538ee826d2f1178a0df3c549d3fff6ba"}, + {file = "onnxruntime-1.29.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d2fb19e848f7c33ed8d3182b52504aaa11c5e8da438bbb47296f85b133cbcf6b"}, + {file = "onnxruntime-1.29.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2b80d8c7ec2cc7438e4da3760b88c24568cba72c9ace96d668800a6c79419acb"}, + {file = "onnxruntime-1.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:4acf2b4948b7ede87221ca6332344b8facdc8059d6ac751a7d367d04532b02dd"}, + {file = "onnxruntime-1.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:dc61a79cb39afd66ab3f01fd2c23591a7f01de89c1668e1fb6315067fc279164"}, + {file = "onnxruntime-1.29.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:be0f8ed688cfb1d4d5765a137193b7bfab0c8ea214eed99260b380bb525a3a7f"}, + {file = "onnxruntime-1.29.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:d67673c5367727860922c5262d724472f1b5539fb7ccf4c81a638f9b71719803"}, + {file = "onnxruntime-1.29.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e2128f31f449e922c62dbe5d8b6b7b079f0bcaf2d56a102fa203cb6e5bb5ab19"}, + {file = "onnxruntime-1.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:2945e1f82f81f27e88decea88c7861f45baea23818950d467bf3909aa303119e"}, + {file = "onnxruntime-1.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:4b940b0d777590c7e20bf298f5c16af1ea6ad1b400a1c822a6be192f64f4d954"}, + {file = "onnxruntime-1.29.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:533f8370ce124304e5cb08ab961836cf755631e3dd77adc5f3bbdab70c2b7d99"}, + {file = "onnxruntime-1.29.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:c1ad3f437153fe77f9d01a08fbaac0beb030e09b8a80ace1603bcf69b6c95481"}, + {file = "onnxruntime-1.29.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e74b278af1d949876f5d91d1268fd6c680e79f2bac194967394eaba9fdf69e7e"}, + {file = "onnxruntime-1.29.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:939e5d65f332e6d399774b2bd0d3559fd8fa629c1e77833db29d968d2384f23d"}, + {file = "onnxruntime-1.29.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6c0c37b92f67ed68dd36221ce0403e1d9bd4f7efce724439978a2597848530e5"}, + {file = "onnxruntime-1.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:4a3129ae56e70d2618ff773920166916310370a7e3cacb60b9e0e8910092725f"}, + {file = "onnxruntime-1.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:e417ef8628dcce310d2d53023e750ea298ec14d4341ae6dc3a572bfd9bc7fa97"}, + {file = "onnxruntime-1.29.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:11264bb58f7b7cf6af835ab10d36838d73680580820fd6f51d90124a1ca8f449"}, + {file = "onnxruntime-1.29.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1ea91cef3b971506e51ae9c37c16d027774ec64994a524ec1bdfb027d68a9832"}, +] + +[package.dependencies] +flatbuffers = "*" +numpy = ">=1.21.6" +packaging = "*" +protobuf = ">=4.25.8" + +[package.extras] +quantization = ["ml_dtypes"] +symbolic = ["sympy"] + [[package]] name = "opt-einsum" version = "3.4.0" @@ -5422,4 +5467,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.12" -content-hash = "47bf7d0a1f4ad2a4d8bcc6c63b3a918a85411923f78a250939f67d3eb2e4fc53" +content-hash = "43383321d186b8a5e7ea30d2109ec5abbac95d41a08d4641de06840ae1175380" diff --git a/pyproject.toml b/pyproject.toml index cc7a9d8..c33d30c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,10 @@ matplotlib = "^3.11.0" pretty-midi = "^0.2.11" pandas = "^3.0.3" librosa = "^0.11.0" -basic-pitch = "^0.4.0" +# The "onnx" extra pins an inference backend explicitly. Without it, +# basic-pitch relies on platform markers that leave linux/arm64 with no +# backend at all, so the container dies at import. See backend_test.py. +basic-pitch = { version = "^0.4.0", extras = ["onnx"] } setuptools = "<81" tqdm = "^4.68.4" huggingface-hub = "^1.23.0"