diff --git a/README.md b/README.md index 53c54fc..281ee16 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,54 @@ iex> result |> Nx.backend_transfer() |> Nx.argmax(axis: 1) ```elixir def deps do [ - {:ortex, "~> 0.1.10"} + {:ortex, "~> 0.2.0-rc.1"} ] end ``` You will need [Rust](https://www.rust-lang.org/tools/install) for compilation to succeed. + +## Execution provider features + +Ortex relies on `ort` cargo features to compile support for non-CPU execution providers. +Defaults are OS-specific: + +- macOS: `coreml` +- Windows: `directml` +- Linux: none (CPU-only) + +Override via `ORTEX_FEATURES` as a comma-separated list. For example: + +```sh +ORTEX_FEATURES=cuda,tensorrt mix compile +``` + +Enabling GPU providers requires the relevant system toolchains to be installed. + +### Packaging and Offline Builds + +If you are packaging Ortex with a precompiled NIF, set `ORTEX_SKIP_COMPILE=1` during +compilation to avoid building the Rust crate. Ensure the NIF (and any required +`libonnxruntime` binaries) are available in `priv/native` for the target platform. + +```sh +ORTEX_SKIP_COMPILE=1 mix compile +``` + +For offline or system-provided ONNX Runtime builds, you can disable downloads and +link dynamically using a local runtime install: + +```sh +ORTEX_SKIP_DOWNLOAD=1 \ +ORT_PREFER_DYNAMIC_LINK=1 \ +ORT_LIB_LOCATION=/path/to/onnxruntime/lib \ +mix compile +``` + +If your package provides `libonnxruntime.pc`, enable pkg-config lookup: + +```sh +ORTEX_FEATURES=pkg-config \ +PKG_CONFIG_PATH=/path/to/onnxruntime/lib/pkgconfig \ +mix compile +``` diff --git a/config/config.exs b/config/config.exs index f693371..55282c4 100644 --- a/config/config.exs +++ b/config/config.exs @@ -8,11 +8,18 @@ config :ortex, # Set the cargo feature flags required to use the matching execution provider # based on the OS we're running on -ortex_features = +default_ortex_features = case :os.type() do {:win32, _} -> ["directml"] {:unix, :darwin} -> ["coreml"] - {:unix, _} -> ["cuda", "tensorrt"] + {:unix, _} -> [] + end + +ortex_features = + case System.get_env("ORTEX_FEATURES") do + nil -> default_ortex_features + "" -> [] + features -> String.split(features, ",", trim: true) end config :ortex, Ortex.Native, features: ortex_features diff --git a/lib/ortex/backend.ex b/lib/ortex/backend.ex index 379330e..27ee488 100644 --- a/lib/ortex/backend.ex +++ b/lib/ortex/backend.ex @@ -60,34 +60,38 @@ defmodule Ortex.Backend do @impl true def backend_transfer(tensor, backend, opts) do - backend.from_binary(tensor, to_binary(tensor), opts) - end - - defp to_binary(%T{data: %{ref: tensor}}) do - # filling the bits and limits with 0 since we aren't using them right now - Ortex.Native.to_binary(tensor, 0, 0) + backend.from_binary(tensor, to_binary(tensor, 0), opts) end @impl true def inspect(%T{} = tensor, inspect_opts) do - limit = if inspect_opts.limit == :infinity, do: :infinity, else: inspect_opts.limit + 1 + limit = + case inspect_opts.limit do + :infinity -> Nx.size(tensor) + value -> min(value + 1, Nx.size(tensor)) + end tensor - |> to_binary(min(limit, Nx.size(tensor))) + |> to_binary(limit) |> then(&Nx.Backend.inspect(tensor, &1, inspect_opts)) |> maybe_add_signature(tensor) end @impl true def slice(out, %T{data: %B{ref: tensor_ref}}, start_indicies, lengths, strides) do - r = Ortex.Native.slice(tensor_ref, start_indicies, lengths, strides) - put_in(out.data, %B{ref: r}) + case Ortex.Native.slice(tensor_ref, start_indicies, lengths, strides) do + {:error, msg} -> raise msg + res -> put_in(out.data, %B{ref: res}) + end end @impl true def reshape(out, %T{data: %B{ref: ref}}) do shape = Nx.shape(out) |> Tuple.to_list() - put_in(out.data, %B{ref: Ortex.Native.reshape(ref, shape)}) + case Ortex.Native.reshape(ref, shape) do + {:error, msg} -> raise msg + res -> put_in(out.data, %B{ref: res}) + end end @impl true @@ -102,7 +106,14 @@ defmodule Ortex.Backend do out | shape: new_shape, names: new_names, - data: %B{ref: Ortex.Native.reshape(ref, new_shape |> Tuple.to_list())} + data: + %B{ + ref: + case Ortex.Native.reshape(ref, new_shape |> Tuple.to_list()) do + {:error, msg} -> raise msg + res -> res + end + } } end end @@ -121,7 +132,10 @@ defmodule Ortex.Backend do type = out.type - %{out | data: %B{ref: Ortex.Native.concatenate(tensor_refs, type, axis)}} + case Ortex.Native.concatenate(tensor_refs, type, axis) do + {:error, msg} -> raise msg + res -> %{out | data: %B{ref: res}} + end end if Application.compile_env(:ortex, :add_backend_on_inspect, true) do diff --git a/lib/ortex/native.ex b/lib/ortex/native.ex index ee16c07..f9e652b 100644 --- a/lib/ortex/native.ex +++ b/lib/ortex/native.ex @@ -1,19 +1,37 @@ defmodule Ortex.Native do @moduledoc false - @rustler_version Application.spec(:rustler, :vsn) |> to_string() |> Version.parse!() + @skip_compile? (case System.get_env("ORTEX_SKIP_COMPILE") do + nil -> false + value -> String.downcase(value) in ["1", "true", "yes", "on"] + end) + @skip_download? (case System.get_env("ORTEX_SKIP_DOWNLOAD") do + nil -> false + value -> String.downcase(value) in ["1", "true", "yes", "on"] + end) # We have to compile the crate before `use Rustler` compiles the crate since # cargo downloads the onnxruntime shared libraries and they are not available # to load or copy into Elixir's during the on_load or Elixir compile steps. # In the future, this may be configurable in Rustler. - if Version.compare(@rustler_version, "0.30.0") in [:gt, :eq] do - Rustler.Compiler.compile_crate(:ortex, Application.compile_env(:ortex, __MODULE__, []), - otp_app: :ortex, - crate: :ortex - ) - else - Rustler.Compiler.compile_crate(__MODULE__, otp_app: :ortex, crate: :ortex) + if not @skip_compile? do + if @skip_download? do + System.put_env("ORT_SKIP_DOWNLOAD", "1") + end + + rustler_version = + Application.spec(:rustler, :vsn) + |> to_string() + |> Version.parse!() + + if Version.compare(rustler_version, "0.30.0") in [:gt, :eq] do + Rustler.Compiler.compile_crate(:ortex, Application.compile_env(:ortex, __MODULE__, []), + otp_app: :ortex, + crate: :ortex + ) + else + Rustler.Compiler.compile_crate(__MODULE__, otp_app: :ortex, crate: :ortex) + end end Ortex.Util.copy_ort_libs() diff --git a/lib/ortex/serving.ex b/lib/ortex/serving.ex index 55ca37d..6c8970c 100644 --- a/lib/ortex/serving.ex +++ b/lib/ortex/serving.ex @@ -59,15 +59,28 @@ defmodule Ortex.Serving do @behaviour Nx.Serving @impl true - def init(_inline_or_process, model, [_defn_options]) do + def init(_inline_or_process, model, defn_options) when is_list(defn_options) do + defn_options = + Enum.map(defn_options, fn opts -> + opts = if is_list(opts), do: opts, else: [] + Keyword.put_new(opts, :compiler, Nx.Defn.Evaluator) + end) + func = fn x -> Ortex.run(model, x) end - {:ok, func} + {:ok, {func, defn_options}} end @impl true - def handle_batch(batch, _partition, function) do - # A hack to move the back into a tensor for Ortex - out = function.(Nx.Defn.jit_apply(&Function.identity/1, [batch])) - {:execute, fn -> {out, :server_info} end, function} + def handle_batch(batch, partition, {function, defn_options}) do + opts = Enum.at(defn_options, partition) || [] + + materialized = + case batch do + %Nx.Batch{} -> Nx.Defn.jit_apply(&Function.identity/1, [batch], opts) + _ -> batch + end + + out = function.(materialized) + {:execute, fn -> {out, :server_info} end, {function, defn_options}} end end diff --git a/lib/ortex/util.ex b/lib/ortex/util.ex index 2914943..52528d7 100644 --- a/lib/ortex/util.ex +++ b/lib/ortex/util.ex @@ -5,31 +5,122 @@ defmodule Ortex.Util do Elixir can use """ def copy_ort_libs() do + suppress_warning? = suppress_copy_warning?() build_root = Path.absname(:code.priv_dir(:ortex)) |> Path.dirname() + ort_lib_location = System.get_env("ORT_LIB_LOCATION") + destination_dir = Path.join([:code.priv_dir(:ortex), "native"]) + File.mkdir_p!(destination_dir) - rust_env = - case Path.join([build_root, "native/ortex/release"]) |> File.ls() do - {:ok, _} -> "release" - _ -> "debug" - end - - # where the libonnxruntime files are stored - rust_path = Path.join([build_root, "native/ortex", rust_env]) + search_patterns = + [build_root, find_project_root(build_root), find_project_root(File.cwd!())] + |> Enum.reject(&is_nil/1) + |> Enum.uniq() + |> Enum.flat_map(&patterns_for_root/1) + |> Enum.concat(ort_lib_location_patterns(ort_lib_location)) + |> Enum.uniq() onnx_runtime_paths = + search_patterns + |> Enum.flat_map(&Path.wildcard/1) + |> Enum.uniq() + + existing = Path.wildcard(lib_glob(destination_dir)) + + cond do + onnx_runtime_paths == [] and existing != [] -> + :ok + + onnx_runtime_paths == [] and not is_nil(ort_lib_location) -> + raise """ + Unable to locate libonnxruntime binaries. + ORT_LIB_LOCATION: #{ort_lib_location} + Searched: #{Enum.join(search_patterns, ", ")} + Destination: #{destination_dir} + """ + + onnx_runtime_paths == [] and (test_env?() or suppress_warning?) -> + :ok + + onnx_runtime_paths == [] -> + :ok + + true -> + Enum.each(onnx_runtime_paths, fn path -> + File.cp!(path, Path.join([destination_dir, Path.basename(path)])) + end) + end + end + + defp patterns_for_root(root) do + [ + Path.join([root, "native/ortex/release"]), + Path.join([root, "native/ortex/debug"]), + Path.join([root, "native/ortex/target/release"]), + Path.join([root, "native/ortex/target/debug"]), + Path.join([root, "native/ortex/target", "**"]) + ] + |> Enum.map(&lib_glob/1) + end + + defp ort_lib_location_patterns(nil), do: [] + + defp ort_lib_location_patterns(path) do + expanded = Path.expand(path) + + if File.dir?(expanded) do + [expanded, Path.join(expanded, "lib"), Path.join(expanded, "lib64")] + |> Enum.filter(&File.dir?/1) + |> Enum.map(&lib_glob/1) + else + [expanded] + end + end + + defp lib_glob(base) do + suffix = case :os.type() do - {:win32, _} -> Path.join([rust_path, "libonnxruntime*.dll*"]) - {:unix, :darwin} -> Path.join([rust_path, "libonnxruntime*.dylib*"]) - {:unix, _} -> Path.join([rust_path, "libonnxruntime*.so*"]) + {:win32, _} -> "libonnxruntime*.dll*" + {:unix, :darwin} -> "libonnxruntime*.dylib*" + {:unix, _} -> "libonnxruntime*.so*" end - |> Path.wildcard() - # where we need to copy the paths - destination_dir = Path.join([:code.priv_dir(:ortex), "native"]) + Path.join([base, suffix]) + end + + defp find_project_root(path) do + expanded = Path.expand(path) + + cond do + File.exists?(Path.join(expanded, "mix.exs")) -> + expanded + + expanded == Path.dirname(expanded) -> + nil + + true -> + find_project_root(Path.dirname(expanded)) + end + end + + defp test_env?() do + cond do + Code.ensure_loaded?(Mix) and function_exported?(Mix, :env, 0) -> + Mix.env() == :test + + true -> + System.get_env("MIX_ENV") == "test" + end + end + + defp suppress_copy_warning?() do + truthy_env?("ORTEX_SKIP_COMPILE") or truthy_env?("ORTEX_SKIP_DOWNLOAD") or + truthy_env?("ORT_PREFER_DYNAMIC_LINK") + end - onnx_runtime_paths - |> Enum.map(fn x -> - File.cp!(x, Path.join([destination_dir, Path.basename(x)])) - end) + defp truthy_env?(name) do + case System.get_env(name) do + nil -> false + value -> String.downcase(value) in ["1", "true", "yes", "on"] + end end end diff --git a/mix.exs b/mix.exs index 0ff357e..7583fc5 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Ortex.MixProject do def project do [ app: :ortex, - version: "0.1.10", + version: "0.2.0-rc.1", elixir: "~> 1.14", start_permanent: Mix.env() == :prod, deps: deps(), @@ -31,12 +31,12 @@ defmodule Ortex.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:rustler, "~> 0.27"}, - {:nx, "~> 0.6"}, - {:tokenizers, "~> 0.4", only: :dev}, + {:rustler, "~> 0.37"}, + {:nx, "~> 0.10"}, + {:tokenizers, "~> 0.5", only: :dev}, {:ex_doc, "0.29.4", only: :dev, runtime: false}, - {:exla, "~> 0.6", only: :dev}, - {:torchx, "~> 0.6", only: :dev} + {:exla, "~> 0.10", only: :dev}, + {:torchx, "~> 0.10", only: :dev} ] end diff --git a/mix.lock b/mix.lock index 8b9284d..16bbd71 100644 --- a/mix.lock +++ b/mix.lock @@ -1,30 +1,22 @@ %{ - "axon": {:hex, :axon, "0.5.1", "1ae3a2193df45e51fca912158320b2ca87cb7fba4df242bd3ebe245504d0ea1a", [:mix], [{:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}, {:kino_vega_lite, "~> 0.1.7", [hex: :kino_vega_lite, repo: "hexpm", optional: true]}, {:nx, "~> 0.5.0", [hex: :nx, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "d36f2a11c34c6c2b458f54df5c71ffdb7ed91c6a9ccd908faba909c84cc6a38e"}, - "axon_onnx": {:hex, :axon_onnx, "0.4.0", "7be4b5ac7a44340ec65eb59c24122a8fe2aa8105da33b3321a378b455a6cd9c6", [:mix], [{:axon, "~> 0.5", [hex: :axon, repo: "hexpm", optional: false]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: false]}, {:protox, "~> 1.6.10", [hex: :protox, repo: "hexpm", optional: false]}], "hexpm", "b98c84e5656caf156ef8998296836349a62bc35598f05cc21eececbbef022d09"}, - "castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"}, - "cc_precompiler": {:hex, :cc_precompiler, "0.1.7", "77de20ac77f0e53f20ca82c563520af0237c301a1ec3ab3bc598e8a96c7ee5d9", [:mix], [{:elixir_make, "~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2768b28bf3c2b4f788c995576b39b8cb5d47eb788526d93bd52206c1d8bf4b75"}, - "complex": {:hex, :complex, "0.5.0", "af2d2331ff6170b61bb738695e481b27a66780e18763e066ee2cd863d0b1dd92", [:mix], [], "hexpm", "2683bd3c184466cfb94fad74cbfddfaa94b860e27ad4ca1bffe3bff169d91ef1"}, - "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "dll_loader_helper": {:hex, :dll_loader_helper, "1.1.0", "e7d015e980942a0d67e306827ec907e7e853a21186bd92bb968d986698591a0f", [:mix], [{:dll_loader_helper_beam, "~> 1.1", [hex: :dll_loader_helper_beam, repo: "hexpm", optional: false]}], "hexpm", "2b6c11ee7bb48f6a132ce8f872202f9e828c019988da1e2d40ad41496195df0c"}, - "dll_loader_helper_beam": {:hex, :dll_loader_helper_beam, "1.2.0", "557c43befb8e3b119b718da302adccde3bd855acdb999498a14a2a8d2814b8b9", [:rebar3], [], "hexpm", "a2115d4bf1cca488a7b33f3c648847f64019b32c0382d10286d84dd5c3cbc0e5"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, - "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, - "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "castore": {:hex, :castore, "1.0.17", "4f9770d2d45fbd91dcf6bd404cf64e7e58fed04fadda0923dc32acca0badffa2", [:mix], [], "hexpm", "12d24b9d80b910dd3953e165636d68f147a31db945d2dcb9365e441f8b5351e5"}, + "complex": {:hex, :complex, "0.6.0", "b0130086a7a8c33574d293b2e0e250f4685580418eac52a5658a4bd148f3ccf1", [:mix], [], "hexpm", "0a5fa95580dcaf30fcd60fe1aaf24327c0fe401e98c24d892e172e79498269f9"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, + "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, - "exla": {:hex, :exla, "0.6.1", "a4400933a04d018c5fb508c75a080c73c3c1986f6c16a79bbfee93ba22830d4d", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nx, "~> 0.6.1", [hex: :nx, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xla, "~> 0.5.0", [hex: :xla, repo: "hexpm", optional: false]}], "hexpm", "f0e95b0f91a937030cf9fcbe900c9d26933cb31db2a26dfc8569aa239679e6d4"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "nx": {:hex, :nx, "0.6.2", "f1d137f477b1a6f84f8db638f7a6d5a0f8266caea63c9918aa4583db38ebe1d6", [:mix], [{:complex, "~> 0.5", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ac913b68d53f25f6eb39bddcf2d2cd6ea2e9bcb6f25cf86a79e35d0411ba96ad"}, - "protox": {:hex, :protox, "1.6.10", "41d0b0c5b9190e7d5e6a2b1a03a09257ead6f3d95e6a0cf8b81430b526126908", [:mix], [{:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "9769fca26ae7abfc5cc61308a1e8d9e2400ff89a799599cee7930d21132832d9"}, - "rustler": {:hex, :rustler, "0.29.1", "880f20ae3027bd7945def6cea767f5257bc926f33ff50c0d5d5a5315883c084d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "109497d701861bfcd26eb8f5801fe327a8eef304f56a5b63ef61151ff44ac9b6"}, - "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.0", "5d0834fc06dbc76dd1034482f17b1797df0dba9b491cef8bb045fcaca94bcade", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "fdf43a6835f4e4de5bfbc4c019bfb8c46d124bd4635fefa3e20d9a2bbbec1512"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "tokenizers": {:hex, :tokenizers, "0.4.0", "140283ca74a971391ddbd83cd8cbdb9bd03736f37a1b6989b82d245a95e1eb97", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "ef1a9824f5a893cd3b831c0e5b3d72caa250d2ec462035cc6afef6933b13a82e"}, - "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, - "torchx": {:hex, :torchx, "0.6.1", "2a9862ebc4b397f42c51f0fa3f9f4e3451a83df6fba42882f8523cbc925c8ae1", [:make, :mix], [{:dll_loader_helper, "~> 0.1 or ~> 1.0", [hex: :dll_loader_helper, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nx, "~> 0.6.1", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "99b3fc73b52d6cfbe5cad8bdd74277ddc99297ce8fc6765b1dabec80681e8d9d"}, - "useful": {:hex, :useful, "1.11.0", "b2d89223563c3354fd56f4da75b63f07f52cb32b243289a7f1fcc37869bcf9c2", [:mix], [], "hexpm", "2e5b2a47acc191bfb38e936f5f1bc57dad3b11133e0defe59a32fda10ebafcff"}, - "xla": {:hex, :xla, "0.5.1", "8ba4c2c51c1a708ff54e9d4f88158c1a75b7f2cb3e5db02bf222b5b3852afffd", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "82a2490f6e9a76c8a29d1aedb47f07c59e3d5081095eac5a74db34d46c8212bc"}, + "exla": {:hex, :exla, "0.10.0", "93e7d75a774fbc06ce05b96de20c4b01bda413b315238cb3c727c09a05d2bc3a", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:nx, "~> 0.10.0", [hex: :nx, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xla, "~> 0.9.0", [hex: :xla, repo: "hexpm", optional: false]}], "hexpm", "16fffdb64667d7f0a3bc683fdcd2792b143a9b345e4b1f1d5cd50330c63d8119"}, + "fine": {:hex, :fine, "0.1.4", "b19a89c1476c7c57afb5f9314aed5960b5bc95d5277de4cb5ee8e1d1616ce379", [:mix], [], "hexpm", "be3324cc454a42d80951cf6023b9954e9ff27c6daa255483b3e8d608670303f5"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "nx": {:hex, :nx, "0.10.0", "128e4a094cb790f663e20e1334b127c1f2a4df54edfb8b13c22757ec33133b4f", [:mix], [{:complex, "~> 0.6", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3db8892c124aeee091df0e6fbf8e5bf1b81f502eb0d4f5ba63e6378ebcae7da4"}, + "rustler": {:hex, :rustler, "0.37.1", "721434020c7f6f8e1cdc57f44f75c490435b01de96384f8ccb96043f12e8a7e0", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "24547e9b8640cf00e6a2071acb710f3e12ce0346692e45098d84d45cdb54fd79"}, + "rustler_precompiled": {:hex, :rustler_precompiled, "0.8.4", "700a878312acfac79fb6c572bb8b57f5aae05fe1cf70d34b5974850bbf2c05bf", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "3b33d99b540b15f142ba47944f7a163a25069f6d608783c321029bc1ffb09514"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "tokenizers": {:hex, :tokenizers, "0.5.1", "b0975d92b4ee5b18e8f47b5d65b9d5f1e583d9130189b1a2620401af4e7d4b35", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "5f08d97cc7f2ed3d71d370d68120da6d3de010948ccf676c9c0eb591ba4bacc9"}, + "torchx": {:hex, :torchx, "0.10.2", "4b8529bfc4b0e641232497c99ef6d2508e652198840b212373333361352f0bae", [:mix], [{:nx, "~> 0.10.0", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "cad541c64df8ddcbf50d9b0f212961632361a03050c8e01493f0fc8d4fed96d9"}, + "xla": {:hex, :xla, "0.9.1", "cca0040ff94902764007a118871bfc667f1a0085d4a5074533a47d6b58bec61e", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "eb5e443ae5391b1953f253e051f2307bea183b59acee138053a9300779930daf"}, } diff --git a/native/ortex/Cargo.lock b/native/ortex/Cargo.lock index cd74a84..4b0782f 100644 --- a/native/ortex/Cargo.lock +++ b/native/ortex/Cargo.lock @@ -1,54 +1,30 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] +version = 4 [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "bitflags" -version = "1.3.2" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "byteorder" @@ -56,218 +32,229 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + [[package]] name = "cc" -version = "1.0.83" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ - "libc", + "find-msvc-tools", + "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ + "core-foundation-sys", "libc", ] [[package]] -name = "crc32fast" -version = "1.4.0" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "crypto-common" -version = "0.1.6" +name = "der" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", + "pem-rfc7468", + "zeroize", ] [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", ] [[package]] -name = "filetime" -version = "0.2.23" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "flate2" -version = "1.0.28" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] -name = "form_urlencoded" -version = "1.2.1" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "percent-encoding", + "foreign-types-shared", ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "getrandom" -version = "0.2.12" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", ] [[package]] name = "half" -version = "2.3.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "idna" -version = "0.5.0" +name = "hmac-sha256" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f0ae375a85536cac3a243e3a9cda80a47910348abdea7e2c22f8ec556d586d" + +[[package]] +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "bytes", + "itoa", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "libc" -version = "0.2.153" +name = "inventory" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] [[package]] -name = "linux-raw-sys" -version = "0.4.13" +name = "itoa" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "log" -version = "0.4.17" +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libloading" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", + "windows-link", ] [[package]] -name = "matchers" -version = "0.1.0" +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lzma-rust2" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1670343e58806300d87950e3401e820b519b9384281bbabfb15e3636689ffd69" [[package]] name = "matrixmultiply" -version = "0.3.2" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ + "autocfg", "rawpointer", ] [[package]] -name = "memchr" -version = "2.5.0" +name = "native-tls" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ - "adler", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] name = "ndarray" -version = "0.16.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" dependencies = [ "matrixmultiply", "num-complex", @@ -278,208 +265,203 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "ort" -version = "2.0.0-rc.8" +version = "2.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11826e6118cc42fea0cb2b102f7d006c1bb339cb167f8badb5fb568616438234" +checksum = "4a5df903c0d2c07b56950f1058104ab0c8557159f2741782223704de9be73c3c" dependencies = [ "half", "ndarray", "ort-sys", + "smallvec", "tracing", + "ureq", ] [[package]] name = "ort-sys" -version = "2.0.0-rc.8" +version = "2.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4780a8b8681e653b2bed85c7f0e2c6e8547224c3e983e5ad27bf0457e012407" +checksum = "06503bb33f294c5f1ba484011e053bfa6ae227074bdb841e9863492dc5960d4b" dependencies = [ - "flate2", - "pkg-config", - "sha2", - "tar", + "hmac-sha256", + "lzma-rust2", "ureq", ] [[package]] name = "ortex" -version = "0.1.0" +version = "0.2.0-rc.1" dependencies = [ "half", "ndarray", - "num-traits", "ort", "rustler", - "rustls", - "tracing-subscriber", ] [[package]] -name = "overload" -version = "0.1.1" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "portable-atomic-util" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a7d5beecc52a491b54d6dd05c7a45ba1801666a5baad9fdbfc6fef8d2d206c" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ "portable-atomic", ] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.27" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] [[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "regex-syntax" -version = "0.6.28" +name = "rawpointer" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] -name = "ring" -version = "0.17.8" +name = "regex-lite" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys", -] +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "rustix" -version = "0.38.31" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.4.2", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -488,93 +470,87 @@ dependencies = [ [[package]] name = "rustler" -version = "0.29.1" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884cb623b9f43d3e2c51f9071c5e96a5acf3e6e6007866812884ff0cb983f1e" +checksum = "a5c708d8b686a8d426681908369f835af90349f7ebb92ab87ddf14a851efd556" dependencies = [ - "lazy_static", + "inventory", + "libloading", + "regex-lite", "rustler_codegen", - "rustler_sys", ] [[package]] name = "rustler_codegen" -version = "0.29.1" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e277af754f2560cf4c4ebedb68c1a735292fb354505c6133e47ec406e699cf" +checksum = "da3f478ec72581782a7dd62a5adb406aa076af7cedd7de63fa3676c927eb216a" dependencies = [ "heck", + "inventory", "proc-macro2", "quote", "syn", ] [[package]] -name = "rustler_sys" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76ba8524729d7c9db2b3e80f2269d1fdef39b5a60624c33fd794797e69b558" -dependencies = [ - "regex", - "unreachable", -] - -[[package]] -name = "rustls" -version = "0.22.4" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", "zeroize", ] [[package]] -name = "rustls-pki-types" -version = "1.3.0" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "rustls-webpki" -version = "0.102.2" +name = "schannel" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", + "windows-sys", ] [[package]] -name = "sha2" -version = "0.10.8" +name = "security-framework" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] -name = "sharded-slab" -version = "0.1.7" +name = "security-framework-sys" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ - "lazy_static", + "core-foundation-sys", + "libc", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" -version = "1.13.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socks" @@ -587,23 +563,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" -version = "2.0.16" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -611,190 +575,99 @@ dependencies = [ ] [[package]] -name = "tar" -version = "0.4.40" +name = "tempfile" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", + "fastrand", + "getrandom", "once_cell", + "rustix", + "windows-sys", ] -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "valuable", ] -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "ureq" -version = "2.9.6" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ "base64", + "der", "log", - "once_cell", - "rustls", + "native-tls", + "percent-encoding", "rustls-pki-types", - "rustls-webpki", "socks", - "url", - "webpki-roots", + "ureq-proto", + "utf-8", + "webpki-root-certs", ] [[package]] -name = "url" -version = "2.5.0" +name = "ureq-proto" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "base64", + "http", + "httparse", + "log", ] [[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" +name = "utf-8" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "void" -version = "1.0.2" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "webpki-roots" -version = "0.26.1" +name = "webpki-root-certs" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" dependencies = [ "rustls-pki-types", ] @@ -822,84 +695,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.0" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] -name = "windows_i686_msvc" -version = "0.52.0" +name = "zerocopy" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "dafd85c832c1b68bbb4ec0c72c7f6f4fc5179627d2bc7c26b30e4c0cc11e76cc" +dependencies = [ + "zerocopy-derive", +] [[package]] -name = "xattr" -version = "1.3.1" +name = "zerocopy-derive" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "7cb7e4e8436d9db52fbd6625dbf2f45243ab84994a72882ec8227b99e72b439a" dependencies = [ - "libc", - "linux-raw-sys", - "rustix", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/native/ortex/Cargo.toml b/native/ortex/Cargo.toml index 4052470..ca9542a 100644 --- a/native/ortex/Cargo.toml +++ b/native/ortex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ortex" -version = "0.1.0" +version = "0.2.0-rc.1" authors = [] edition = "2018" @@ -10,13 +10,10 @@ path = "src/lib.rs" crate-type = ["cdylib"] [dependencies] -rustler = "0.29.0" -ort = { version = "2.0.0-rc.8" } -ndarray = "0.16.1" +rustler = "0.37.1" +ort = { version = "2.0.0-rc.11", features = ["half"] } +ndarray = "0.17.2" half = "2.2.1" -tracing-subscriber = { version = "0.3", features = [ "env-filter", "fmt" ] } -num-traits = "0.2.15" -rustls = "0.22.4" [features] # ONNXRuntime Execution providers diff --git a/native/ortex/src/lib.rs b/native/ortex/src/lib.rs index 0523105..a847422 100644 --- a/native/ortex/src/lib.rs +++ b/native/ortex/src/lib.rs @@ -9,10 +9,9 @@ mod model; mod tensor; mod utils; -use model::OrtexModel; use tensor::OrtexTensor; -use rustler::resource::ResourceArc; +use rustler::ResourceArc; use rustler::types::Binary; use rustler::{Atom, Env, NifResult, Term}; @@ -23,7 +22,8 @@ fn init( eps: Vec, opt: i32, ) -> NifResult> { - let eps = utils::map_eps(env, eps); + let eps = utils::map_eps(env, eps) + .map_err(|e| rustler::Error::Term(Box::new(e)))?; let model = model::init(model_path, eps, opt) .map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?; Ok(ResourceArc::new(model)) @@ -71,7 +71,7 @@ fn to_binary<'a>( } #[rustler::nif] -pub fn slice<'a>( +pub fn slice( tensor: ResourceArc, start_indicies: Vec, lengths: Vec, @@ -81,11 +81,11 @@ pub fn slice<'a>( start_indicies, lengths, strides, - ))) + )?)) } #[rustler::nif] -pub fn reshape<'a>( +pub fn reshape( tensor: ResourceArc, shape: Vec, ) -> NifResult> { @@ -93,32 +93,16 @@ pub fn reshape<'a>( } #[rustler::nif] -pub fn concatenate<'a>( +pub fn concatenate( tensors: Vec>, dtype: Term, axis: i32, ) -> NifResult> { let (dtype_t, dtype_bits): (Term, usize) = dtype.decode()?; let dtype_str = dtype_t.atom_to_string()?; - let concatted = tensor::concatenate(tensors, (&dtype_str, dtype_bits), axis as usize); + let concatted = tensor::concatenate(tensors, (&dtype_str, dtype_bits), axis as usize) + .map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?; Ok(ResourceArc::new(concatted)) } -rustler::init!( - "Elixir.Ortex.Native", - [ - run, - init, - from_binary, - to_binary, - show_session, - slice, - reshape, - concatenate - ], - load = |env: Env, _| { - rustler::resource!(OrtexModel, env); - rustler::resource!(OrtexTensor, env); - true - } -); +rustler::init!("Elixir.Ortex.Native"); diff --git a/native/ortex/src/model.rs b/native/ortex/src/model.rs index f5e04b3..d73e944 100644 --- a/native/ortex/src/model.rs +++ b/native/ortex/src/model.rs @@ -12,22 +12,24 @@ use crate::tensor::OrtexTensor; use crate::utils::{is_bool_input, map_opt_level}; use std::convert::TryInto; use std::iter::zip; +use std::sync::Mutex; -use ort::{Error, ExecutionProviderDispatch, Session}; -use rustler::resource::ResourceArc; -use rustler::Atom; +use ort::execution_providers::ExecutionProviderDispatch; +use ort::session::{Session, SessionInputValue}; +use ort::Error; +use rustler::{Atom, Resource, ResourceArc}; /// Holds the model state which include onnxruntime session and environment. All /// are threadsafe so this can be called concurrently from the beam. pub struct OrtexModel { - pub session: ort::Session, + pub session: Mutex, } -// Since we're only using the session for inference and -// inference is threadsafe, this Sync is safe. Additionally, -// Environment is global and also threadsafe -// https://github.com/microsoft/onnxruntime/issues/114 -unsafe impl Sync for OrtexModel {} +#[rustler::resource_impl(name = "OrtexModel")] +impl Resource for OrtexModel {} + +impl std::panic::RefUnwindSafe for OrtexModel {} +impl std::panic::UnwindSafe for OrtexModel {} /// Creates a model given the path to the model and vector of execution providers. /// The execution providers are Atoms from Erlang/Elixir. @@ -44,7 +46,9 @@ pub fn init( .with_execution_providers(eps)? .commit_from_file(model_path)?; - let state = OrtexModel { session }; + let state = OrtexModel { + session: Mutex::new(session), + }; Ok(state) } @@ -59,19 +63,27 @@ pub fn show( ) { let model: &OrtexModel = &*model; + let session = model.session.lock().unwrap_or_else(|e| e.into_inner()); + let mut inputs = Vec::new(); - for input in model.session.inputs.iter() { - let name = input.name.to_string(); - let repr = format!("{:#?}", input.input_type); - let dims = Option::<&Vec>::cloned(input.input_type.tensor_dimensions()); + for input in session.inputs() { + let name = input.name().to_string(); + let repr = format!("{:#?}", input.dtype()); + let dims = match input.dtype() { + ort::value::ValueType::Tensor { shape, .. } => Some(shape.to_vec()), + _ => None, + }; inputs.push((name, repr, dims)); } let mut outputs = Vec::new(); - for output in model.session.outputs.iter() { - let name = output.name.to_string(); - let repr = format!("{:#?}", output.output_type); - let dims = Option::<&Vec>::cloned(output.output_type.tensor_dimensions()); + for output in session.outputs() { + let name = output.name().to_string(); + let repr = format!("{:#?}", output.dtype()); + let dims = match output.dtype() { + ort::value::ValueType::Tensor { shape, .. } => Some(shape.to_vec()), + _ => None, + }; outputs.push((name, repr, dims)); } @@ -85,36 +97,53 @@ pub fn run( inputs: Vec>, ) -> Result, Vec, Atom, usize)>, Error> { // Grab the session and run a forward pass with it - let session: &ort::Session = &model.session; - - let mut ortified_inputs: Vec = Vec::new(); - - for (elixir_input, onnx_input) in zip(inputs, &session.inputs) { - let derefed_input: &OrtexTensor = &elixir_input; - if is_bool_input(&onnx_input.input_type) { - // this assumes that the boolean input isn't huge -- we're cloning it twice; - // once below, once in the try_into() - let boolified_input: &OrtexTensor = &derefed_input.clone().to_bool(); - let v: ort::SessionInputValue = boolified_input.try_into()?; - ortified_inputs.push(v); - } else { - let v: ort::SessionInputValue = derefed_input.try_into()?; - ortified_inputs.push(v); + let mut session = model.session.lock().unwrap_or_else(|e| e.into_inner()); + let mut ortified_inputs: Vec = Vec::new(); + let output_names: Vec; + + { + let session_inputs = session.inputs(); + let expected_inputs = session_inputs.len(); + if inputs.len() != expected_inputs { + return Err(Error::new(format!( + "Expected {} input(s), got {}", + expected_inputs, + inputs.len() + ))); } + + for (elixir_input, onnx_input) in zip(inputs, session_inputs) { + let derefed_input: &OrtexTensor = &elixir_input; + if is_bool_input(onnx_input.dtype()) { + // this assumes that the boolean input isn't huge -- we're cloning it twice; + // once below, once in the try_into() + let boolified_input = derefed_input.clone().to_bool()?; + let v: SessionInputValue = (&boolified_input).try_into()?; + ortified_inputs.push(v); + } else { + let v: SessionInputValue = derefed_input.try_into()?; + ortified_inputs.push(v); + } + } + + output_names = session + .outputs() + .iter() + .map(|output| output.name().to_string()) + .collect(); } // Construct a Vec of ModelOutput enums based on the DynOrtTensor data type let outputs = session.run(&ortified_inputs[..])?; let mut collected_outputs = Vec::new(); - for output_descriptor in &session.outputs { - let output_name: &str = &output_descriptor.name; - let val = outputs.get(output_name).expect( - &format!( + for output_name in output_names { + let val = outputs.get(&output_name).ok_or_else(|| { + Error::new(format!( "Expected {} to be in the outputs, but didn't find it", output_name - )[..], - ); + )) + })?; // NOTE: try_into impl here will implicitly map bool outputs to u8 outputs let ortextensor: OrtexTensor = val.try_into()?; diff --git a/native/ortex/src/tensor.rs b/native/ortex/src/tensor.rs index d4aecf1..34ff04e 100644 --- a/native/ortex/src/tensor.rs +++ b/native/ortex/src/tensor.rs @@ -2,10 +2,11 @@ use core::convert::TryFrom; use ndarray::prelude::*; use ndarray::{ArrayBase, ArrayView, Data, IxDyn, IxDynImpl, ViewRepr}; -use ort::{DynValue, Error, Value}; -use rustler::resource::ResourceArc; -use rustler::Atom; -use std::convert::TryInto; +use ort::session::SessionInputValue; +use ort::tensor::TensorElementType; +use ort::value::{Tensor, Value, ValueType}; +use ort::Error; +use rustler::{Atom, Error as RustlerError, Resource, ResourceArc}; use crate::constants::ortex_atoms; @@ -27,10 +28,13 @@ pub enum OrtexTensor { f32(Array), f64(Array), // the bool input is for internal use only. - // Any Nx facing ops should panic if called on a bool input + // Nx-facing code treats bool tensors as u8 outputs. bool(Array), } +#[rustler::resource_impl(name = "OrtexTensor")] +impl Resource for OrtexTensor {} + impl OrtexTensor { pub fn shape(&self) -> Vec { match self { @@ -46,7 +50,7 @@ impl OrtexTensor { OrtexTensor::bf16(y) => y.shape().to_owned(), OrtexTensor::f32(y) => y.shape().to_owned(), OrtexTensor::f64(y) => y.shape().to_owned(), - _ => panic!("Can't convert this type to Nx format"), + OrtexTensor::bool(y) => y.shape().to_owned(), } } @@ -112,7 +116,11 @@ impl OrtexTensor { .into_shape_with_order(shape) .map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?, )), - _ => panic!("Can't convert this type to Nx format"), + OrtexTensor::bool(y) => Ok(OrtexTensor::bool( + y.clone() + .into_shape_with_order(shape) + .map_err(|e| rustler::Error::Term(Box::new(e.to_string())))?, + )), } } @@ -130,7 +138,7 @@ impl OrtexTensor { OrtexTensor::bf16(_) => (ortex_atoms::bf(), 16), OrtexTensor::f32(_) => (ortex_atoms::f(), 32), OrtexTensor::f64(_) => (ortex_atoms::f(), 64), - _ => panic!("Can't convert this type to Nx format"), + OrtexTensor::bool(_) => (ortex_atoms::u(), 8), } } @@ -148,7 +156,7 @@ impl OrtexTensor { OrtexTensor::bf16(y) => get_bytes(y), OrtexTensor::f32(y) => get_bytes(y), OrtexTensor::f64(y) => get_bytes(y), - _ => panic!("Can't convert this type to Nx format"), + OrtexTensor::bool(y) => get_bytes(y), }; contents } @@ -158,7 +166,36 @@ impl OrtexTensor { start_indicies: Vec, lengths: Vec, strides: Vec, - ) -> Self { + ) -> rustler::NifResult { + let rank = match self { + OrtexTensor::s8(y) => y.ndim(), + OrtexTensor::s16(y) => y.ndim(), + OrtexTensor::s32(y) => y.ndim(), + OrtexTensor::s64(y) => y.ndim(), + OrtexTensor::u8(y) => y.ndim(), + OrtexTensor::u16(y) => y.ndim(), + OrtexTensor::u32(y) => y.ndim(), + OrtexTensor::u64(y) => y.ndim(), + OrtexTensor::f16(y) => y.ndim(), + OrtexTensor::bf16(y) => y.ndim(), + OrtexTensor::f32(y) => y.ndim(), + OrtexTensor::f64(y) => y.ndim(), + OrtexTensor::bool(y) => y.ndim(), + }; + + if start_indicies.len() != rank || lengths.len() != rank || strides.len() != rank { + return Err(RustlerError::Term(Box::new(format!( + "Slice arguments must match tensor rank of {}", + rank + )))); + } + + if strides.iter().any(|s| *s == 0) { + return Err(RustlerError::Term(Box::new( + "Slice stride must be non-zero".to_string(), + ))); + } + let mut slice_specs: Vec<(isize, Option, isize)> = vec![]; for ((start_index, length), stride) in start_indicies .iter() @@ -167,7 +204,7 @@ impl OrtexTensor { { slice_specs.push((*start_index, Some(*length + *start_index), *stride)); } - match self { + let sliced = match self { OrtexTensor::s8(y) => OrtexTensor::s8(slice_array(y, &slice_specs).to_owned()), OrtexTensor::s16(y) => OrtexTensor::s16(slice_array(y, &slice_specs).to_owned()), OrtexTensor::s32(y) => OrtexTensor::s32(slice_array(y, &slice_specs).to_owned()), @@ -180,25 +217,30 @@ impl OrtexTensor { OrtexTensor::bf16(y) => OrtexTensor::bf16(slice_array(y, &slice_specs).to_owned()), OrtexTensor::f32(y) => OrtexTensor::f32(slice_array(y, &slice_specs).to_owned()), OrtexTensor::f64(y) => OrtexTensor::f64(slice_array(y, &slice_specs).to_owned()), - _ => panic!("Can't convert this type to Nx format"), - } + OrtexTensor::bool(y) => OrtexTensor::bool(slice_array(y, &slice_specs).to_owned()), + }; + Ok(sliced) } - pub fn to_bool(self) -> OrtexTensor { + pub fn to_bool(self) -> Result { match self { OrtexTensor::u8(y) => { - let bool_tensor = y.to_owned().mapv(|x| match x { - 0 => false, - 1 => true, - _ => { - panic!( - "Tried to convert a u8 tensor to bool, but not every element is 0 or 1" - ) - } - }); - OrtexTensor::bool(bool_tensor) + let values: Result, Error> = y + .iter() + .map(|x| match x { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Error::new( + "Tried to convert a u8 tensor to bool, but not every element is 0 or 1", + )), + }) + .collect(); + + let bool_tensor = + Array::from_shape_vec(y.raw_dim(), values?).map_err(|e| Error::new(e.to_string()))?; + Ok(OrtexTensor::bool(bool_tensor)) } - t => panic!("Can't convert this type {:?} to bool", t.dtype()), + t => Err(Error::new(format!("Can't convert this type {:?} to bool", t.dtype()))), } } } @@ -230,85 +272,88 @@ where impl TryFrom<&Value> for OrtexTensor { type Error = Error; fn try_from(e: &Value) -> Result { - let dtype: ort::ValueType = e.dtype(); + let dtype = e.dtype(); let ty = match dtype { - ort::ValueType::Tensor { - ty: t, - dimensions: _, - } => t, - _ => panic!("can't decode non tensor, got {}", dtype), + ValueType::Tensor { ty, .. } => ty, + _ => return Err(Error::new(format!("Expected tensor output, got {:?}", dtype))), }; - let tensor = match ty { - ort::TensorElementType::Bfloat16 => { - OrtexTensor::bf16(e.try_extract_tensor::()?.into_owned()) + let tensor = match *ty { + TensorElementType::Bfloat16 => { + OrtexTensor::bf16(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Float16 => { - OrtexTensor::f16(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Float16 => { + OrtexTensor::f16(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Float32 => { - OrtexTensor::f32(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Float32 => { + OrtexTensor::f32(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Float64 => { - OrtexTensor::f64(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Float64 => { + OrtexTensor::f64(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Uint8 => { - OrtexTensor::u8(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Uint8 => { + OrtexTensor::u8(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Uint16 => { - OrtexTensor::u16(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Uint16 => { + OrtexTensor::u16(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Uint32 => { - OrtexTensor::u32(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Uint32 => { + OrtexTensor::u32(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Uint64 => { - OrtexTensor::u64(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Uint64 => { + OrtexTensor::u64(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Int8 => { - OrtexTensor::s8(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Int8 => { + OrtexTensor::s8(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Int16 => { - OrtexTensor::s16(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Int16 => { + OrtexTensor::s16(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Int32 => { - OrtexTensor::s32(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Int32 => { + OrtexTensor::s32(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::Int64 => { - OrtexTensor::s64(e.try_extract_tensor::()?.into_owned()) + TensorElementType::Int64 => { + OrtexTensor::s64(e.try_extract_array::()?.to_owned()) } - ort::TensorElementType::String => { - todo!("Can't return string tensors") + TensorElementType::String => { + return Err(Error::new("String tensors are not supported")) } // map the output into u8 space - ort::TensorElementType::Bool => { - let nd_array = e.try_extract_tensor::()?.into_owned(); + TensorElementType::Bool => { + let nd_array = e.try_extract_array::()?; OrtexTensor::u8(nd_array.mapv(|x| x as u8)) } + other => { + return Err(Error::new(format!( + "Tensor element type {:?} is not supported", + other + ))) + } }; Ok(tensor) } } -impl TryFrom<&OrtexTensor> for ort::SessionInputValue<'_> { +impl TryFrom<&OrtexTensor> for SessionInputValue<'_> { type Error = Error; fn try_from(ort_tensor: &OrtexTensor) -> Result { - let r: DynValue = match ort_tensor { - OrtexTensor::s8(arr) => arr.to_owned().try_into()?, - OrtexTensor::s16(arr) => arr.clone().try_into()?, - OrtexTensor::s32(arr) => arr.clone().try_into()?, - OrtexTensor::s64(arr) => arr.clone().try_into()?, - OrtexTensor::f16(arr) => arr.clone().try_into()?, - OrtexTensor::f32(arr) => arr.clone().try_into()?, - OrtexTensor::f64(arr) => arr.clone().try_into()?, - OrtexTensor::bf16(arr) => arr.clone().try_into()?, - OrtexTensor::u8(arr) => arr.clone().try_into()?, - OrtexTensor::u16(arr) => arr.clone().try_into()?, - OrtexTensor::u32(arr) => arr.clone().try_into()?, - OrtexTensor::u64(arr) => arr.clone().try_into()?, - OrtexTensor::bool(arr) => arr.clone().try_into()?, + let r: SessionInputValue = match ort_tensor { + OrtexTensor::s8(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::s16(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::s32(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::s64(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::f16(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::f32(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::f64(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::bf16(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::u8(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::u16(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::u32(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::u64(arr) => Tensor::from_array(arr.to_owned())?.into(), + OrtexTensor::bool(arr) => Tensor::from_array(arr.to_owned())?.into(), }; - Ok(r.into()) + Ok(r) } } @@ -343,7 +388,7 @@ macro_rules! concatenate { // `typ` is the actual datatype, `ort_tensor_kind` is the OrtexTensor variant ($tensors:expr, $axis:expr, $typ:ty, $ort_tensor_kind:ident) => {{ type ArrayType<'a> = ArrayBase, Dim>; - fn filter(tensor: &OrtexTensor) -> Option { + fn filter<'a>(tensor: &'a OrtexTensor) -> Option> { match tensor { OrtexTensor::$ort_tensor_kind(x) => Some(x.view()), _ => None, @@ -351,17 +396,25 @@ macro_rules! concatenate { } // hack way to type coalesce. Filters out any ndarray's that don't // have the desired type + let input_len = $tensors.len(); let tensors: Vec = $tensors .iter() .filter_map(|tensor| filter(tensor)) .collect(); + if tensors.len() != input_len { + return Err(Error::new( + "Concatenate called with mixed tensor types", + )); + } - let tensors = ndarray::concatenate(Axis($axis), &tensors).unwrap(); + let tensors = + ndarray::concatenate(Axis($axis), &tensors).map_err(|e| Error::new(e.to_string()))?; // data is not contiguous after the concatenation above. To decode // properly, need to create a new contiguous vector let tensors = - Array::from_shape_vec(tensors.raw_dim(), tensors.iter().cloned().collect()).unwrap(); - OrtexTensor::$ort_tensor_kind(tensors) + Array::from_shape_vec(tensors.raw_dim(), tensors.iter().cloned().collect()) + .map_err(|e| Error::new(e.to_string()))?; + Ok(OrtexTensor::$ort_tensor_kind(tensors)) }}; } @@ -369,7 +422,10 @@ pub fn concatenate( tensors: Vec>, dtype: (&str, usize), axis: usize, -) -> OrtexTensor { +) -> Result { + if tensors.is_empty() { + return Err(Error::new("Concatenate requires at least one tensor")); + } match dtype { ("s", 8) => concatenate!(tensors, axis, i8, s8), ("s", 16) => concatenate!(tensors, axis, i16, s16), @@ -383,6 +439,9 @@ pub fn concatenate( ("bf", 16) => concatenate!(tensors, axis, half::bf16, bf16), ("f", 32) => concatenate!(tensors, axis, f32, f32), ("f", 64) => concatenate!(tensors, axis, f64, f64), - _ => unimplemented!(), + _ => Err(Error::new(format!( + "Unsupported dtype {} with {} bits for concatenate", + dtype.0, dtype.1 + ))), } } diff --git a/native/ortex/src/utils.rs b/native/ortex/src/utils.rs index 8d96117..4eba370 100644 --- a/native/ortex/src/utils.rs +++ b/native/ortex/src/utils.rs @@ -3,20 +3,60 @@ use crate::constants::*; use crate::tensor::OrtexTensor; -use ndarray::{ArrayViewMut, Ix, IxDyn}; +use ndarray::{Array, IxDyn}; -use ndarray::ShapeError; - -use rustler::resource::ResourceArc; use rustler::types::Binary; -use rustler::{Atom, Env, NifResult}; +use rustler::{Atom, Env, Error as RustlerError, NifResult, ResourceArc}; + +use ort::execution_providers::{ + ACLExecutionProvider, CPUExecutionProvider, CUDAExecutionProvider, CoreMLExecutionProvider, + DirectMLExecutionProvider, ExecutionProviderDispatch, OneDNNExecutionProvider, + ROCmExecutionProvider, TensorRTExecutionProvider, +}; +use ort::session::builder::GraphOptimizationLevel; +use ort::tensor::TensorElementType; +use ort::value::ValueType; + +fn element_count(shape: &[usize]) -> Result { + shape + .iter() + .try_fold(1usize, |acc, dim| { + acc.checked_mul(*dim) + .ok_or_else(|| "Tensor shape is too large to index".to_string()) + }) +} + +fn array_from_binary( + bin: &Binary, + shape: &[usize], +) -> Result, String> { + let elements = element_count(shape)?; + let elem_size = std::mem::size_of::(); + let expected_bytes = elements + .checked_mul(elem_size) + .ok_or_else(|| "Tensor binary size overflows usize".to_string())?; -use ort::{ExecutionProviderDispatch, GraphOptimizationLevel}; + if bin.len() != expected_bytes { + return Err(format!( + "Binary length mismatch for shape {:?}: expected {} bytes, got {}", + shape, + expected_bytes, + bin.len() + )); + } + + let mut data = vec![T::default(); elements]; + if expected_bytes > 0 { + unsafe { + std::ptr::copy_nonoverlapping( + bin.as_ptr(), + data.as_mut_ptr() as *mut u8, + expected_bytes, + ); + } + } -/// A faster (unsafe) way of creating an Array from an Erlang binary -fn initialize_from_raw_ptr(ptr: *const T, shape: &[Ix]) -> ArrayViewMut { - let array = unsafe { ArrayViewMut::from_shape_ptr(shape, ptr as *mut T) }; - array + Array::from_shape_vec(IxDyn(shape), data).map_err(|e| e.to_string()) } /// Given a Binary term, shape, and dtype from the BEAM, constructs an OrtexTensor and @@ -37,45 +77,48 @@ pub fn from_binary( shape: Vec, dtype_str: String, dtype_bits: usize, -) -> Result, ShapeError> { +) -> Result, String> { match (dtype_str.as_ref(), dtype_bits) { ("bf", 16) => Ok(ResourceArc::new(OrtexTensor::bf16( - initialize_from_raw_ptr(bin.as_ptr() as *const half::bf16, &shape).to_owned(), + array_from_binary::(&bin, &shape)?, ))), ("f", 16) => Ok(ResourceArc::new(OrtexTensor::f16( - initialize_from_raw_ptr(bin.as_ptr() as *const half::f16, &shape).to_owned(), - ))), - ("f", 32) => Ok(ResourceArc::new(OrtexTensor::f32( - initialize_from_raw_ptr(bin.as_ptr() as *const f32, &shape).to_owned(), - ))), - ("f", 64) => Ok(ResourceArc::new(OrtexTensor::f64( - initialize_from_raw_ptr(bin.as_ptr() as *const f64, &shape).to_owned(), - ))), - ("s", 8) => Ok(ResourceArc::new(OrtexTensor::s8( - initialize_from_raw_ptr(bin.as_ptr() as *const i8, &shape).to_owned(), + array_from_binary::(&bin, &shape)?, ))), - ("s", 16) => Ok(ResourceArc::new(OrtexTensor::s16( - initialize_from_raw_ptr(bin.as_ptr() as *const i16, &shape).to_owned(), - ))), - ("s", 32) => Ok(ResourceArc::new(OrtexTensor::s32( - initialize_from_raw_ptr(bin.as_ptr() as *const i32, &shape).to_owned(), - ))), - ("s", 64) => Ok(ResourceArc::new(OrtexTensor::s64( - initialize_from_raw_ptr(bin.as_ptr() as *const i64, &shape).to_owned(), - ))), - ("u", 8) => Ok(ResourceArc::new(OrtexTensor::u8( - initialize_from_raw_ptr(bin.as_ptr() as *const u8, &shape).to_owned(), - ))), - ("u", 16) => Ok(ResourceArc::new(OrtexTensor::u16( - initialize_from_raw_ptr(bin.as_ptr() as *const u16, &shape).to_owned(), - ))), - ("u", 32) => Ok(ResourceArc::new(OrtexTensor::u32( - initialize_from_raw_ptr(bin.as_ptr() as *const u32, &shape).to_owned(), - ))), - ("u", 64) => Ok(ResourceArc::new(OrtexTensor::u64( - initialize_from_raw_ptr(bin.as_ptr() as *const u64, &shape).to_owned(), - ))), - (&_, _) => unimplemented!(), + ("f", 32) => Ok(ResourceArc::new(OrtexTensor::f32(array_from_binary::( + &bin, &shape, + )?))), + ("f", 64) => Ok(ResourceArc::new(OrtexTensor::f64(array_from_binary::( + &bin, &shape, + )?))), + ("s", 8) => Ok(ResourceArc::new(OrtexTensor::s8(array_from_binary::( + &bin, &shape, + )?))), + ("s", 16) => Ok(ResourceArc::new(OrtexTensor::s16(array_from_binary::( + &bin, &shape, + )?))), + ("s", 32) => Ok(ResourceArc::new(OrtexTensor::s32(array_from_binary::( + &bin, &shape, + )?))), + ("s", 64) => Ok(ResourceArc::new(OrtexTensor::s64(array_from_binary::( + &bin, &shape, + )?))), + ("u", 8) => Ok(ResourceArc::new(OrtexTensor::u8(array_from_binary::( + &bin, &shape, + )?))), + ("u", 16) => Ok(ResourceArc::new(OrtexTensor::u16(array_from_binary::( + &bin, &shape, + )?))), + ("u", 32) => Ok(ResourceArc::new(OrtexTensor::u32(array_from_binary::( + &bin, &shape, + )?))), + ("u", 64) => Ok(ResourceArc::new(OrtexTensor::u64(array_from_binary::( + &bin, &shape, + )?))), + (&_, _) => Err(format!( + "Unsupported dtype {} with {} bits", + dtype_str, dtype_bits + )), } } @@ -84,25 +127,64 @@ pub fn from_binary( pub fn to_binary<'a>( env: Env<'a>, reference: ResourceArc, - _bits: usize, - _limit: usize, + bits: usize, + limit: usize, ) -> NifResult> { - Ok(reference.make_binary(env, |x| x.to_bytes())) + if bits == 0 || limit == 0 { + return Ok(reference.make_binary(env, |x| x.to_bytes())); + } + + if bits % 8 != 0 { + return Err(RustlerError::Term(Box::new(format!( + "Invalid element bit size: {}", + bits + )))); + } + + let elem_size = bits / 8; + let elem_count = element_count(&reference.shape()) + .map_err(|e| RustlerError::Term(Box::new(e)))?; + let capped = std::cmp::min(limit, elem_count); + let byte_limit = capped + .checked_mul(elem_size) + .ok_or_else(|| RustlerError::Term(Box::new("Binary size overflows usize".to_string())))?; + + Ok(reference.make_binary(env, |x| { + let bytes = x.to_bytes(); + let len = std::cmp::min(byte_limit, bytes.len()); + &bytes[..len] + })) } /// Takes a vec of Atoms and transforms them into a vec of ExecutionProvider Enums -pub fn map_eps(env: rustler::env::Env, eps: Vec) -> Vec { +pub fn map_eps( + env: rustler::env::Env, + eps: Vec, +) -> Result, String> { eps.iter() - .map(|e| match &e.to_term(env).atom_to_string().unwrap()[..] { - CPU => ort::CPUExecutionProvider::default().build(), - CUDA => ort::CUDAExecutionProvider::default().build(), - TENSORRT => ort::TensorRTExecutionProvider::default().build(), - ACL => ort::ACLExecutionProvider::default().build(), - ONEDNN => ort::OneDNNExecutionProvider::default().build(), - COREML => ort::CoreMLExecutionProvider::default().build(), - DIRECTML => ort::DirectMLExecutionProvider::default().build(), - ROCM => ort::ROCmExecutionProvider::default().build(), - _ => ort::CPUExecutionProvider::default().build(), + .map(|e| { + let atom_str = e + .to_term(env) + .atom_to_string() + .map_err(|_| "Execution provider must be an atom".to_string())?; + match atom_str.as_str() { + CPU => Ok(CPUExecutionProvider::default().build()), + CUDA => Ok(CUDAExecutionProvider::default().build()), + TENSORRT => Ok(TensorRTExecutionProvider::default().build()), + ACL => Ok(ACLExecutionProvider::default().build()), + ONEDNN | "dnnl" => Ok(OneDNNExecutionProvider::default().build()), + COREML => Ok(CoreMLExecutionProvider::default().build()), + DIRECTML => Ok(DirectMLExecutionProvider::default().build()), + ROCM => Ok(ROCmExecutionProvider::default().build()), + _ => Err(format!( + "Unknown execution provider: {}. Expected one of: {}", + atom_str, + vec![ + CPU, CUDA, TENSORRT, ACL, ONEDNN, "dnnl", COREML, DIRECTML, ROCM + ] + .join(", ") + )), + } }) .collect() } @@ -117,11 +199,11 @@ pub fn map_opt_level(opt: i32) -> GraphOptimizationLevel { } } -pub fn is_bool_input(inp: &ort::ValueType) -> bool { +pub fn is_bool_input(inp: &ValueType) -> bool { match inp { - ort::ValueType::Tensor { ty, .. } => ty == &ort::TensorElementType::Bool, - ort::ValueType::Map { value, .. } => value == &ort::TensorElementType::Bool, - ort::ValueType::Sequence(boxed_input) => is_bool_input(boxed_input), - ort::ValueType::Optional(boxed_input) => is_bool_input(boxed_input), + ValueType::Tensor { ty, .. } => ty == &TensorElementType::Bool, + ValueType::Map { value, .. } => value == &TensorElementType::Bool, + ValueType::Sequence(boxed_input) => is_bool_input(boxed_input), + ValueType::Optional(boxed_input) => is_bool_input(boxed_input), } } diff --git a/python/export_resnet.py b/python/export_resnet.py index d60c1da..0212eba 100644 --- a/python/export_resnet.py +++ b/python/export_resnet.py @@ -1,19 +1,53 @@ +from pathlib import Path +import importlib + import torch -import torchvision.models as models +from torchvision.models import ResNet50_Weights, resnet50 + + +def require_module(module_name: str, pip_name: str | None = None) -> None: + try: + importlib.import_module(module_name) + except ModuleNotFoundError: + install_name = pip_name or module_name + raise SystemExit( + f"Missing dependency: {module_name}. " + f"Install it with `python3 -m pip install {install_name}`." + ) + -model = models.resnet50(pretrained=True) +require_module("onnx") +USE_DYNAMO = True +try: + importlib.import_module("onnxscript") +except ModuleNotFoundError: + USE_DYNAMO = False + +model = resnet50(weights=ResNet50_Weights.IMAGENET1K_V1) model.eval() + onnx_input = torch.randn(1, 3, 224, 224) +repo_root = Path(__file__).resolve().parents[1] +models_dir = repo_root / "models" +models_dir.mkdir(parents=True, exist_ok=True) +output_path = models_dir / "resnet50.onnx" + +if not USE_DYNAMO: + print("onnxscript not available; exporting with legacy ONNX exporter.") + +with torch.inference_mode(): + torch.onnx.export( + model, + (onnx_input,), + output_path, + verbose=False, + input_names=["input"], + output_names=["output"], + dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}, + export_params=True, + opset_version=19, + dynamo=USE_DYNAMO, + ) -torch.onnx.export( - model, - onnx_input, - "resnet50.onnx", - verbose=False, - input_names=["input"], - output_names=["output"], - dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}, - export_params=True, - opset_version=19, -) +print(f"Wrote {output_path}") diff --git a/test/shape/concat_test.exs b/test/shape/concat_test.exs index 3ab9a54..9210991 100644 --- a/test/shape/concat_test.exs +++ b/test/shape/concat_test.exs @@ -6,16 +6,16 @@ defmodule Ortex.TestConcat do %{ "s8" => {:s, 8}, "s16" => {:s, 16}, - "s32" => {:s, 16}, - "s64" => {:s, 16}, - "u8" => {:s, 16}, - "u16" => {:s, 16}, - "u32" => {:s, 16}, - "u64" => {:s, 16}, - "f16" => {:s, 16}, - "bf16" => {:s, 16}, - "f32" => {:s, 16}, - "f64" => {:s, 16} + "s32" => {:s, 32}, + "s64" => {:s, 64}, + "u8" => {:u, 8}, + "u16" => {:u, 16}, + "u32" => {:u, 32}, + "u64" => {:u, 64}, + "f16" => {:f, 16}, + "bf16" => {:bf, 16}, + "f32" => {:f, 32}, + "f64" => {:f, 64} } |> Enum.each(fn {type_str, type_tuple} -> test "Concat 1d tensors #{type_str}" do