Evision.DNN Example - Benchmark using Densenet121
Mix.install([
{:evision, "~> 0.2"},
{:kino, "~> 0.7"},
{:req, "~> 0.5"}
], system_env: [
# optional, defaults to `true`
# set `EVISION_PREFER_PRECOMPILED` to `false`
# if you prefer `:evision` to be compiled from source
# note that to compile from source, you may need at least 1GB RAM
{"EVISION_PREFER_PRECOMPILED", true},
# optional, defaults to `true`
# set `EVISION_ENABLE_CONTRIB` to `false`
# if you don't need modules from `opencv_contrib`
{"EVISION_ENABLE_CONTRIB", true},
# optional, defaults to `false`
# set `EVISION_ENABLE_CUDA` to `true`
# if you wish to use CUDA related functions
# note that `EVISION_ENABLE_CONTRIB` also has to be `true`
# because cuda related modules come from the `opencv_contrib` repo
{"EVISION_ENABLE_CUDA", false},
# required when
# - `EVISION_ENABLE_CUDA` is `true`
# - and `EVISION_PREFER_PRECOMPILED` is `true`
#
# set `EVISION_CUDA_VERSION` to the version that matches
# your local CUDA runtime version
#
# current available versions are
# - 118
# - 121
{"EVISION_CUDA_VERSION", "118"},
# require for Windows users when
# - `EVISION_ENABLE_CUDA` is `true`
# set `EVISION_CUDA_RUNTIME_DIR` to the directory that contains
# CUDA runtime libraries
{"EVISION_CUDA_RUNTIME_DIR", "C:/PATH/TO/CUDA/RUNTIME"}
])
Define Some Helper Functions
defmodule Helper do
def download!(url, save_as, overwrite? \\ false) do
unless File.exists?(save_as) do
Req.get!(url, http_errors: :raise, into: File.stream!(save_as), cache: not overwrite?)
end
:ok
end
end
Write the Benchmark Module
alias Evision, as: Cv
defmodule DetectionModel do
def benchmark(times, mat, model, out_names, opts \\ []) do
mean = opts[:mean] || [0, 0, 0]
scalefactor = opts[:scalefactor] || 1.0
for _ <- 1..times, reduce: {[], []} do
{forward_only, all} ->
start_time_1 = :os.system_time(:millisecond)
blob = Cv.DNN.blobFromImage(mat, opts)
model = Cv.DNN.Net.setInput(model, blob, name: "", scalefactor: scalefactor, mean: mean)
start_time_2 = :os.system_time(:millisecond)
_detections = Cv.DNN.Net.forward(model, outBlobNames: out_names)
end_time = :os.system_time(:millisecond)
inference_time_1 = end_time - start_time_1
inference_time_2 = end_time - start_time_2
IO.puts("Inference time=>#{inference_time_2} ms")
{[inference_time_2 | forward_only], [inference_time_1 | all]}
end
end
def get_model(filename) do
net = Cv.DNN.readNetFromONNX(filename)
out_names = Cv.DNN.Net.getUnconnectedOutLayersNames(net)
{:ok, net, out_names}
end
end
Write the DenseNet121 Module
defmodule DenseNet121 do
defp download_model(opset_version) when opset_version in [3, 6, 7, 8, 9, 12] do
onnx_filename = "densenet-#{opset_version}.onnx"
test_filename = "CyprusShorthair.jpg"
Helper.download!(
"https://github.com/onnx/models/raw/main/vision/classification/densenet-121/model/densenet-#{opset_version}.onnx",
onnx_filename
)
Helper.download!(
"https://upload.wikimedia.org/wikipedia/commons/b/b9/CyprusShorthair.jpg",
"CyprusShorthair.jpg"
)
{onnx_filename, test_filename}
end
def get_detection_model(opset_version \\ 12) do
{onnx_filename, test_filename} = download_model(opset_version)
{:ok, net, out_names} = DetectionModel.get_model(onnx_filename)
test_mat = Cv.imread(test_filename)
{net, out_names, test_mat}
end
def benchmark(times, opset_version \\ 12) do
{net, out_names, test_mat} = get_detection_model(opset_version)
DetectionModel.benchmark(times, test_mat, net, out_names,
scalefactor: 1,
swapRB: true,
mean: {128, 128, 128},
size: {224, 224}
)
end
end
Load and Run
{forward_only, all} = DenseNet121.benchmark(50)
avg_forward_only = Enum.sum(forward_only) / Enum.count(forward_only)
avg_all = Enum.sum(all) / Enum.count(all)
{avg_forward_only, avg_all}