Nx minmax
Mix.install(
[
{:nx, "~> 0.5.0"},
{:exla, "~> 0.5.0"},
{:evision, "0.1.30"},
{:benchee, "~> 1.1.0"}
],
config: [
nx: [default_backend: EXLA.Backend]
]
)
alias Evision, as: Cv
Data
keypoints =
[
[341.7188653945923, 43.22674134373665],
[347.2751133441925, 38.838579922914505],
[337.92927277088165, 38.542279705405235],
[353.93250143527985, 44.37031477689743],
[332.8073402643204, 43.509576231241226],
[358.5170496702194, 66.75018179416656],
[326.14933770895004, 69.04044127464294],
[346.01376926898956, 90.88503938913345],
[303.05064821243286, 94.19108891487122],
[313.96379578113556, 87.70558965206146],
[302.41149455308914, 88.45037072896957],
[348.3349735736847, 134.9865512251854],
[326.03289169073105, 134.1936908364296],
[351.33337795734406, 197.84249007701874],
[319.55440336465836, 196.71163403987885],
[355.83895242214203, 247.53425693511963],
[340.4989422559738, 243.13054251670837]
]
|> Nx.tensor(names: [:points, :values])
Nx.reduce/4
> Given this function relies on anonymous functions, it may not be available or efficient on all Nx backends. Therefore, you should avoid using reduce/4 whenever possible. Instead, use functions sum/2, reduce_max/2, all/1, and so forth.
Nx.reduce_min/2 and Nx.reduce_max/2
# minimum value of all
keypoints |> Nx.reduce_min() |> Nx.to_number()
# maximum value of all
keypoints |> Nx.reduce_max() |> Nx.to_number()
# minimum values over an axis
keypoints |> Nx.reduce_min(axes: [:points]) |> Nx.to_list()
# maximum values over an axis
keypoints |> Nx.reduce_max(axes: [:points]) |> Nx.to_list()
minmax_by_nx = fn %Nx.Tensor{} = points_nx ->
[x_min, y_min] = points_nx |> Nx.reduce_min(axes: [:points]) |> Nx.to_list()
[x_max, y_max] = points_nx |> Nx.reduce_max(axes: [:points]) |> Nx.to_list()
{floor(x_min), floor(y_min), ceil(x_max), ceil(y_max)}
end
minmax_by_nx.(keypoints)
Find minmax with Cv.boundingRect/1
minmax_by_cv = fn %Nx.Tensor{} = points_nx ->
{x, y, w, h} = Cv.boundingRect(points_nx)
{x, y, x + w, y + h}
end
minmax_by_cv.(keypoints)
Bench
:rand.uniform()
gen_random_points = fn n ->
1..n
|> Enum.map(fn _ -> [:rand.uniform(), :rand.uniform()] end)
|> Nx.tensor(names: [:points, :values])
end
gen_random_points.(10)
inputs = %{
"small tensor" => gen_random_points.(100),
"medium tensor" => gen_random_points.(10_00),
"large tensor" => gen_random_points.(1_000_00)
}
Benchee.run(
%{
"Nx" => minmax_by_nx,
"Cv" => minmax_by_cv
},
inputs: inputs
)