> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bioptimus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Inference pipeline

> Configure the whole pipeline with one object — tissue masking, embeddings, predictions, and reproducible workspaces.

The `Inference` pipeline replaces the multi-step manual pipeline (`Backbone` + mask provider + `SlideInference` + writer) with a single, reusable object. The constructor is the pipeline config; the methods do the work. It caches tissue masks, organizes outputs into a structured workspace, and can serialize its config for reproducibility.

## Configure the pipeline

Pick your backend and model — the rest of the guide follows the same steps.

<Tabs>
  <Tab title="On-premise">
    <CodeGroup>
      ```python H-Optimus theme={null}
      from bioptimus.inference import Inference
      from bioptimus.models.types import Models

      infer = Inference(
          model_name=Models.H1,
          api_url="http://localhost:8080",
          tissue=True,
          mask_threshold=0.5,
          output_path="/data/output",
          experiment="h1-embedding-demo",
          run=1,
          description="H1 embeddings with tissue masking",
      )
      ```

      ```python M-Optimus theme={null}
      from bioptimus.inference import Inference
      from bioptimus.models.types import Models

      infer = Inference(
          model_name=Models.M_OPTIMUS,
          api_url="http://localhost:8080",
          tissue=True,
          mask_threshold=0.5,
          output_path="/data/output",
          experiment="m-optimus-demo",
          run=1,
          description="M-Optimus gene expression with tissue masking",
      )
      ```
    </CodeGroup>
  </Tab>

  <Tab title="AWS SageMaker">
    <CodeGroup>
      ```python H-Optimus theme={null}
      from bioptimus.inference import Inference
      from bioptimus.models.types import Models

      infer = Inference(
          model_name=Models.H1,
          backend="aws",
          endpoint_name="h-optimus",
          region_name="us-east-1",
          tissue=True,
          mask_threshold=0.5,
          output_path="/data/output",
          experiment="h1-embedding-demo",
          run=1,
          workers=1,                # ml.g5.xlarge has a single GPU
          description="H1 embeddings with tissue masking",
      )
      ```

      ```python M-Optimus theme={null}
      from bioptimus.inference import Inference
      from bioptimus.models.types import Models

      infer = Inference(
          model_name=Models.M_OPTIMUS,
          backend="aws",
          endpoint_name="m-optimus",
          region_name="us-east-1",
          tissue=True,
          mask_threshold=0.5,
          output_path="/data/output",
          experiment="m-optimus-demo",
          run=1,
          workers=1,                # ml.g5.xlarge has a single GPU
          description="M-Optimus gene expression with tissue masking",
      )
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Run the pipeline

<CodeGroup>
  ```python H-Optimus theme={null}
  infer.tissue(wsi_path)                 # generate (or load cached) tissue mask
  result_path = infer.embed(wsi_path)    # -> <workspace>/h1/embeddings/<slide>.zarr
  ```

  ```python M-Optimus theme={null}
  infer.tissue(wsi_path)                 # generate (or load cached) tissue mask
  result_path = infer.predict(wsi_path)  # -> <workspace>/m-optimus/predictions/<slide>.zarr
  ```
</CodeGroup>

The tissue mask is cached to `<workspace>/tissue/<slide>.png` and reused automatically on later calls.

## Reproducibility

The config is auto-saved to `<workspace>/config.yaml` on first use. Reconstruct the exact pipeline later:

```python theme={null}
infer.save_config()
infer2 = Inference.from_workspace(workspace_dir)   # same workspace; cached masks reused
```

<Tip>
  The same object works across multiple slides — call `infer.embed([s1, s2])` (or `infer.predict([s1, s2])` for M-Optimus) rather than creating a new `Inference` per slide. For full cohorts with bulk RNA, see [Cohorts](/guides/workflows/cohort).
</Tip>

## Workspaces & variants

Your workspace is the directory where all outputs are written. It's resolved from the config you pass:

```text theme={null}
<output_path>/<experiment>/run_<run>/<variant>/
```

Only `output_path` is required; `experiment`, `run`, and `variant` are appended when set:

| Segment         | Config field  | Appended when     |
| --------------- | ------------- | ----------------- |
| `<output_path>` | `output_path` | always (required) |
| `<experiment>`  | `experiment`  | set               |
| `run_<run>`     | `run`         | set               |
| `<variant>`     | `variant`     | set               |

`variant` (a string) adds a final sub-folder so you can keep multiple runs side by side — useful for experiments (e.g. comparing mask thresholds or model versions) without overwriting earlier outputs:

```python theme={null}
infer = Inference(model_name=Models.H1, api_url="http://localhost:8080",
                  output_path="/data/output", experiment="tcga_coad", run=1,
                  variant="mask_0.5")
# -> /data/output/tcga_coad/run_1/mask_0.5/
```

A populated workspace looks like:

<CodeGroup>
  ```text H-Optimus theme={null}
  <output_path>/<experiment>/run_<run>/<variant>/
    config.yaml
    manifest.yaml
    tissue/<slide>.png
    h1/embeddings/<slide>.zarr
  ```

  ```text M-Optimus theme={null}
  <output_path>/<experiment>/run_<run>/<variant>/
    config.yaml
    manifest.yaml
    tissue/<slide>.png
    m-optimus/predictions/<slide>.zarr
  ```
</CodeGroup>
