# `TFLiteElixir.LiteRT.CompiledModel.Isolated`
[🔗](https://github.com/cocoa-xu/tflite_elixir/blob/main/lib/tflite_elixir/litert/compiled_model_isolated.ex#L1)

A compiled model on a node of its own, so that a crash inside the runtime
costs one node instead of yours.

Everything under this binding is native code, and native code that segfaults
takes the whole VM with it regardless of how carefully the Elixir above it is
written. Where that is unacceptable, this puts the model on a separate BEAM
node and forwards calls to it:

    {:ok, model} = TFLiteElixir.LiteRT.CompiledModel.Isolated.start_link(
                     model_path: path, accelerators: [:cpu, :gpu])
    {:ok, outputs} = TFLiteElixir.LiteRT.CompiledModel.Isolated.run(model, inputs)

The far side is an ordinary `TFLiteElixir.LiteRT.CompiledModel.Server`, so the
calls are the same ones; only the wire is different. When the node dies the
calls answer `{:error, "the isolated model is no longer there"}` rather than
hanging or taking the caller down.

## What it costs

Every input and every output crosses the distribution link, which for image
sized tensors is not free, and the node takes a moment to start. Reach for it
when a crash must not be fatal, not by default.

Distribution is started if it is not already up, because a library should not
insist the caller arranged that in advance.

# `opts`

```elixir
@type opts() :: [
  model_path: String.t(),
  runtime_library_dir: String.t(),
  accelerators: [TFLiteElixir.LiteRT.CompiledModel.accelerator()],
  precision: TFLiteElixir.LiteRT.CompiledModel.precision(),
  profile: boolean(),
  signature: non_neg_integer() | String.t(),
  max_model_bytes: non_neg_integer(),
  max_queue: non_neg_integer(),
  peer_args: [String.t()]
]
```

# `fully_accelerated`

```elixir
@spec fully_accelerated(pid()) :: {:ok, boolean()} | {:error, String.t()}
```

Whether the accelerator took the whole graph.

# `fully_accelerated!`

Raising version of `fully_accelerated/1`.

# `fully_accelerated?`

```elixir
@spec fully_accelerated?(pid()) :: boolean()
```

As `fully_accelerated/1`, answering `false` rather than an error.

# `io_sizes`

```elixir
@spec io_sizes(pid()) ::
  {:ok, {[non_neg_integer()], [non_neg_integer()]}} | {:error, String.t()}
```

The byte size of each input and output tensor, as `{inputs, outputs}`.

# `io_sizes!`

Raising version of `io_sizes/1`.

# `node_of`

```elixir
@spec node_of(pid()) :: {:ok, node()} | {:error, String.t()}
```

The node the model is running on.

# `node_of!`

Raising version of `node_of/1`.

# `pending_events`

```elixir
@spec pending_events(pid()) :: {:ok, non_neg_integer()} | {:error, String.t()}
```

How many profiling events are waiting, without reading them.

# `pending_events!`

Raising version of `pending_events/1`.

# `profile`

```elixir
@spec profile(pid()) ::
  {:ok, [TFLiteElixir.LiteRT.CompiledModel.event()]} | {:error, String.t()}
```

Every profiling event recorded so far.

# `profile`

```elixir
@spec profile(pid(), non_neg_integer()) ::
  {:ok, [TFLiteElixir.LiteRT.CompiledModel.event()]} | {:error, String.t()}
```

The most recent `limit` profiling events, or all of them when zero.

# `profile!`

Raising version of `profile/1`.

# `profile!`

Raising version of `profile/2`.

# `reset_profile`

```elixir
@spec reset_profile(pid()) :: :ok | {:error, String.t()}
```

Forget the events recorded so far and keep recording.

# `reset_profile!`

Raising version of `reset_profile/1`.

# `run`

```elixir
@spec run(pid(), [binary()]) :: {:ok, [binary()]} | {:error, String.t()}
```

Run the model over a list of input binaries.

# `run`

```elixir
@spec run(pid(), [binary()], timeout()) :: {:ok, [binary()]} | {:error, String.t()}
```

Run the model, waiting at most `timeout`.

# `run!`

Raising version of `run/2`.

# `run!`

Raising version of `run/3`.

# `run_with_metrics`

```elixir
@spec run_with_metrics(pid(), [binary()]) ::
  {:ok,
   {[binary()], [{binary(), TFLiteElixir.LiteRT.CompiledModel.metric_value()}]}}
  | {:error, String.t()}
```

Run the model and collect whatever counters the accelerator reports.

# `run_with_metrics`

```elixir
@spec run_with_metrics(pid(), [binary()], non_neg_integer()) ::
  {:ok,
   {[binary()], [{binary(), TFLiteElixir.LiteRT.CompiledModel.metric_value()}]}}
  | {:error, String.t()}
```

As `run_with_metrics/2`, at a given detail level.

# `run_with_metrics`

```elixir
@spec run_with_metrics(pid(), [binary()], non_neg_integer(), timeout()) ::
  {:ok,
   {[binary()], [{binary(), TFLiteElixir.LiteRT.CompiledModel.metric_value()}]}}
  | {:error, String.t()}
```

As `run_with_metrics/3`, waiting at most `timeout`.

# `run_with_metrics!`

Raising version of `run_with_metrics/2`.

# `run_with_metrics!`

Raising version of `run_with_metrics/3`.

# `run_with_metrics!`

Raising version of `run_with_metrics/4`.

# `start`

```elixir
@spec start(opts()) :: {:ok, pid()} | :ignore | {:error, term()}
```

Start one outside a supervision tree.

# `start`

```elixir
@spec start(opts(), list()) :: {:ok, pid()} | :ignore | {:error, term()}
```

As `start/1`, with options for the gen_server itself.

# `start_link`

```elixir
@spec start_link(opts()) :: {:ok, pid()} | :ignore | {:error, term()}
```

Start a model on a node of its own, linked to the caller.

`:model_path` is required. The rest are what
`TFLiteElixir.LiteRT.CompiledModel.new/3` and
`TFLiteElixir.LiteRT.CompiledModel.Server.start_link/3` take, plus:

- `:peer_args`. Extra arguments for the node itself, e.g. `["+sbwt", "none"]`.

# `start_link`

```elixir
@spec start_link(opts(), list()) :: {:ok, pid()} | :ignore | {:error, term()}
```

As `start_link/1`, with options for the gen_server itself.

# `stop`

```elixir
@spec stop(pid()) :: :ok
```

Stop the model and the node it is on.

# `summarise_profile`

```elixir
@spec summarise_profile(pid()) ::
  {:ok, [TFLiteElixir.LiteRT.CompiledModel.summary_entry()]}
  | {:error, String.t()}
```

Per-operator totals over every run since the last reset, slowest first.

# `summarise_profile!`

Raising version of `summarise_profile/1`.

# `with`

```elixir
@spec with(pid(), (reference() -&gt; result)) :: result | {:error, String.t()}
when result: term()
```

Run a function against the compiled model, on the node that owns it.

The callback is sent to that node and applied there, so it must return
something worth sending back: a value, not a handle to something local to it.

# `with`

```elixir
@spec with(pid(), (reference() -&gt; result), timeout()) :: result | {:error, String.t()}
when result: term()
```

As `with/2`, waiting at most `timeout`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
