omniem 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. omniem-0.1.0/.gitignore +33 -0
  2. omniem-0.1.0/CHANGELOG.md +48 -0
  3. omniem-0.1.0/LICENSE +21 -0
  4. omniem-0.1.0/PKG-INFO +307 -0
  5. omniem-0.1.0/README.md +291 -0
  6. omniem-0.1.0/docs/api.md +264 -0
  7. omniem-0.1.0/docs/cli.md +376 -0
  8. omniem-0.1.0/examples/2d_MitoEM_H_0_0_0.tif +0 -0
  9. omniem-0.1.0/examples/3d_AxonEM-H-0-0-0_0_0_0.tif +0 -0
  10. omniem-0.1.0/examples/gly-z=0.tif +0 -0
  11. omniem-0.1.0/omniem/__init__.py +72 -0
  12. omniem-0.1.0/omniem/_extras.py +97 -0
  13. omniem-0.1.0/omniem/cli.py +1564 -0
  14. omniem-0.1.0/omniem/config/__init__.py +17 -0
  15. omniem-0.1.0/omniem/config/base.py +240 -0
  16. omniem-0.1.0/omniem/config/model.py +226 -0
  17. omniem-0.1.0/omniem/encoders/__init__.py +10 -0
  18. omniem-0.1.0/omniem/encoders/base.py +496 -0
  19. omniem-0.1.0/omniem/encoders/dinov2/__init__.py +9 -0
  20. omniem-0.1.0/omniem/encoders/dinov2/backbone.py +714 -0
  21. omniem-0.1.0/omniem/encoders/dinov2/build.py +33 -0
  22. omniem-0.1.0/omniem/encoders/dinov2/forward.py +849 -0
  23. omniem-0.1.0/omniem/encoders/registry.py +260 -0
  24. omniem-0.1.0/omniem/errors.py +109 -0
  25. omniem-0.1.0/omniem/models/__init__.py +40 -0
  26. omniem-0.1.0/omniem/models/adapter.py +89 -0
  27. omniem-0.1.0/omniem/models/base.py +1794 -0
  28. omniem-0.1.0/omniem/models/omniemv1_net.py +380 -0
  29. omniem-0.1.0/omniem/models/output.py +83 -0
  30. omniem-0.1.0/omniem/models/registry.py +181 -0
  31. omniem-0.1.0/omniem/models/upsample.py +194 -0
  32. omniem-0.1.0/omniem/prepared.py +114 -0
  33. omniem-0.1.0/omniem/py.typed +0 -0
  34. omniem-0.1.0/pyproject.toml +33 -0
  35. omniem-0.1.0/scripts/build_docs.sh +39 -0
@@ -0,0 +1,33 @@
1
+ /weights/
2
+ /configs/
3
+ /out/
4
+
5
+ *.pyc
6
+ *.txt
7
+ # requirements-dev.txt is tracked dev tooling, NOT a runtime data file — it must NOT
8
+ # match the broad `*.txt` rule above (otherwise a fresh clone has no dev-deps file).
9
+ !requirements-dev.txt
10
+ *.pth
11
+ *~
12
+
13
+ build/
14
+ dist/
15
+ *.egg-info/
16
+ **/__pycache__/
17
+
18
+ # Generated API docs — pdoc HTML built by scripts/build_docs.sh. A build
19
+ # artifact regenerated from the docstrings on demand; never committed.
20
+ /docs/api/
21
+
22
+ # Codex-review fix #5: local agent / tooling state. These dirs contain user-/
23
+ # machine-specific settings (Claude Code permissions, Codex profile) and must not
24
+ # be committed.
25
+ .claude/
26
+ .codex/
27
+
28
+ # Editor / pytest / ruff caches
29
+ .pytest_cache/
30
+ .ruff_cache/
31
+ .mypy_cache/
32
+ .vscode/
33
+ .idea/
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+
4
+ ## [0.1.0]
5
+
6
+
7
+ ### Added
8
+
9
+ - **Encoder.** `EMEncoder` — `load(arch, weights)` (raw `vit.*` checkpoint, loaded
10
+ directly), single-shot `forward` → CLS / patch / inner-block features,
11
+ `apply_input` (split-out input transform), and `name_parameter_group`. The
12
+ owner-frozen encoder arch catalog: `list_encoders` / `arch_info` (`emdinov1`).
13
+ - **Model.** `OmniEM` (EM-DINO encoder + STAdapter z-fusion + UNETR decoder) —
14
+ `load` / `from_config` (optional, separable weight loading: merged, or
15
+ encoder-/head-only, or none → random init), `predict` (single-shot forward →
16
+ **pure logits** at the caller's shape), `apply_input`, the `task_type`-gated output
17
+ stage `apply_output` (`image2image` → sigmoid+uint image; `image2label` → argmax
18
+ label map), `save_weights` (merged or backbone+head split), and `prepare_train`
19
+ (training handoff: unfreeze, optionally fix the encoder backbone). The owner-frozen
20
+ model arch catalog: `list_models` / `model_arch_info` (`omniemv1`).
21
+ - **Shared-encoder borrow.** `OmniEM.load` / `from_config` accept `encoder=` (a
22
+ pre-built `EMEncoder`) to share one ViT backbone by reference across many heads
23
+ (memory-efficient). Head-only load; borrowed models are read-only (whole-model
24
+ mutators rejected) so the shared encoder is never mutated.
25
+ - **Input conform round-trip.** `predict` / `apply_input` accept
26
+ `conform={'strict','pad','resize'}` so non-square / non-stride-multiple XY is handled
27
+ gracefully and the output is round-tripped to the original shape.
28
+ - **Output-size control (CLI super-resolution).** `omniem infer --output-scale F`
29
+ bicubic-resizes the input XY by `F` before inference; since the model is
30
+ shape-preserving, the output lands at the scaled size (`F>1` super-resolution,
31
+ `F<1` quick-inference). XY only — Z is never resized; 3D (`zyx`) inputs warn
32
+ (anisotropy / no Z alignment) and still run. Orthogonal to `--conform`; CLI-only
33
+ (the Python API resizes the input directly — see `docs/api.md`). The resize is
34
+ recorded in the infer sidecar (`output_scale: {factor, input_yx, scaled_yx}`).
35
+ - **CLI** (`omniem`): `list-encoders`, `list-models`, `features` (single-shot encoder
36
+ feature extraction), `infer` (single-shot model inference with `--weights` merged or
37
+ `--backbone`/`--head` split, `--conform`, `--output-scale`,
38
+ `--scale`/`--unit-range`/`--norm`/`--mean`/`--std`, `--out-dtype`, `--save-logits`),
39
+ and `split` / `merge` (weight-file utilities: split a merged `.pt` into a
40
+ `--backbone` + `--head` pair, or merge a pair back — the boundary is the net's
41
+ derived encoder prefix, not a hardcoded `vit.`). Each `features`/`infer` run writes a
42
+ store + a JSON reproducibility sidecar.
43
+ - **Typed error taxonomy** under `OmniEMError`: `ConfigError`, `WeightFormatError`,
44
+ `MissingExtraError`, `InputContractError`, `OOMError`.
45
+ - **Config.** `omniem.config.ModelConfig` (+ `BaseConfig`) with YAML I/O and a
46
+ schema-version policy.
47
+
48
+
omniem-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 the omniem authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
omniem-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,307 @@
1
+ Metadata-Version: 2.4
2
+ Name: omniem
3
+ Version: 0.1.0
4
+ Summary: Inference and utilities for EM-specific encoders and OmniEM models.
5
+ Author-email: Liuyuan He <liyhe@pku.edu.cn>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: monai<2,>=1.2
10
+ Requires-Dist: numpy>=1.24
11
+ Requires-Dist: pydantic>=2.0
12
+ Requires-Dist: pyyaml>=6.0
13
+ Requires-Dist: tifffile>=2023.1.0
14
+ Requires-Dist: torch>=2.3
15
+ Description-Content-Type: text/markdown
16
+
17
+ # omniem
18
+
19
+ `omniem` is a GUI-free Python package for electron microscopy (EM) image
20
+ workflows, introduced from [EM-SSL project](https://github.com/pku-maleilab/EM-SSL-project). It provides two main capabilities:
21
+
22
+ - **Run OmniEM models** for single-shot segmentation or restoration.
23
+ - **Run EM-DINO encoders** to extract CLS, patch, or inner-block features from
24
+ EM images.
25
+
26
+ Downstream tools build on the same public API: the
27
+ [`omniem-train`](https://github.com/pku-maleilab/omniem-train) training pipeline
28
+ and the [napari-omniem](https://github.com/pku-maleilab/napari-omniem) GUI plugin.
29
+
30
+ ## Contents
31
+
32
+ - [Install](#install)
33
+ - [Main Features](#main-features)
34
+ - [Model Config YAML](#model-config-yaml)
35
+ - [First Commands](#first-commands)
36
+ - [Full Guides](#full-guides)
37
+ - [Related Projects](#related-projects)
38
+ - [Future Features](#future-features)
39
+ - [License](#license)
40
+
41
+ ## Install
42
+
43
+ `omniem` requires **Python >= 3.10**.
44
+
45
+ For inference and feature extraction, CUDA is recommended when you have a
46
+ supported NVIDIA GPU. Install the PyTorch build that matches your CUDA driver /
47
+ runtime first; use the selector in the
48
+ [PyTorch install guide](https://pytorch.org/get-started/locally/) for the exact
49
+ command for your machine.
50
+
51
+ Then install `omniem` from PyPI:
52
+
53
+ ```bash
54
+ pip install omniem
55
+ ```
56
+
57
+ Or clone the package repository and install it locally:
58
+
59
+ ```bash
60
+ git clone https://github.com/pku-maleilab/omniem-package.git
61
+ cd omniem-package
62
+ pip install .
63
+ ```
64
+
65
+ Core runtime dependencies include
66
+ [PyTorch](https://pytorch.org/), [NumPy](https://numpy.org/),
67
+ [tifffile](https://github.com/cgohlke/tifffile),
68
+ [Pydantic](https://docs.pydantic.dev/), [PyYAML](https://pyyaml.org/), and
69
+ [MONAI](https://monai.io/).
70
+
71
+ ## Main Features
72
+
73
+ | Feature | Use it when | Main CLI | Main Python API |
74
+ |---|---|---|---|
75
+ | Model inference | you have a model config plus model weights and want segmentation, restoration, or raw logits | `omniem infer` | `OmniEM.load(...)`, `model.predict(...)`, `model.apply_output(...)` |
76
+ | Encoder features | you only need EM-DINO backbone features, without a model head | `omniem features` | `EMEncoder.load(...)`, `enc(...)` |
77
+
78
+ ### Common Concepts
79
+
80
+ #### Model = Config + Weights
81
+
82
+ An OmniEM model is fully specified by a model config YAML plus model weights.
83
+ The config describes how to build the head and interpret its output: model
84
+ architecture, encoder architecture, 2D/3D shape, output channels, `task_type`,
85
+ and the fixed training `mean`/`std` in `[0, 1]` image space.
86
+
87
+ Weights are plain PyTorch `state_dict` files. They may be split into a shared
88
+ EM-DINO backbone file plus a head file, or stored as one merged whole-model file.
89
+ Split weights are useful when several heads share one encoder backbone. Merged
90
+ weights are convenient when you want one standalone model file.
91
+
92
+ ### Available Models
93
+
94
+ Model files are distributed outside the Python wheel. Download config YAML files
95
+ from [here](https://drive.google.com/drive/folders/1cFPBmozY5VAh8ZgSe16U7ydX9RMmvbzu?usp=drive_link). Download backbone and head weight files from [here](https://drive.google.com/drive/folders/1vpzVk6vDui8Aj34FdTMfJpXbt5wlMsx_?usp=drive_link).
96
+
97
+ #### Encoder
98
+
99
+ Use an encoder when you only need the EM-DINO backbone output, without an
100
+ OmniEM head or model config. The encoder converts an EM image into feature
101
+ tensors that downstream code can reuse:
102
+
103
+ - `cls`: one global feature vector for the image;
104
+ - `patch`: a grid of local patch features;
105
+ - `inner`: optional intermediate block features.
106
+
107
+ For a 2D image, the encoder extracts features from that single XY tile. For a
108
+ 3D volume, each XY slice is encoded with the same backbone, and the resulting
109
+ features are kept alongside the z-axis so downstream code can relate features
110
+ back to their original slices.
111
+
112
+ Available encoder models:
113
+
114
+ | Encoder arch | Description | Default norm | Input stride | Weights |
115
+ |---|---|---|---|---|
116
+ | `emdinov1` | EM-DINOv2 ViT-L/14, EM-domain pretrained encoder | mean `0.595446`, std `0.211906` in `[0, 1]` image space | 14 | `backbone_emdino_v1.pt` (bare `vit.*` checkpoint) |
117
+
118
+ #### OmniEM
119
+
120
+ Use an OmniEM model when you have a config YAML, model weights, and a 2D or 3D
121
+ EM image. The model returns raw logits internally; the config controls whether
122
+ `omniem` also applies a canonical output transform.
123
+
124
+ Available OmniEM models:
125
+
126
+ | Model | Purpose | Training on | Input | Weights | Config YAML |
127
+ |---|---|---|---|---|---|
128
+ | `mito-seg-ViT-L-2D` | mitochondria segmentation (2D) | MitoLab dataset | 2D EM tile | `backbone_emdino_v1.pt` + `head_mito-seg-ViT-L-2D.pt` | `model_mito-seg-ViT-L-2D.yaml` |
129
+ | `mito-seg-ViT-L-3D` | mitochondria segmentation (3D) | MitoEM-R | 3D subvolume (z >= 16) | `backbone_emdino_v1.pt` + `head_mito-seg-ViT-L-3D.pt` | `model_mito-seg-ViT-L-3D.yaml` |
130
+ | `denoise-emdiffuse-l` | image denoise | Low-level denoise EMDiffuse | 2D EM tile | `backbone_emdino_v1.pt` + `head_denoise-emdiffuse-l.pt` | `model_denoise-emdiffuse-l.yaml` |
131
+ | `superreso-emdiffuse-l` | image super-resolution | Low-level superresolution EMDiffuse | 2D EM tile | `backbone_emdino_v1.pt` + `head_superreso-emdiffuse-l.pt` | `model_superreso-emdiffuse-l.yaml` |
132
+
133
+ ## Model Config YAML
134
+
135
+ A model config tells `OmniEM` how to build the model head and how to interpret
136
+ outputs.
137
+
138
+ ```yaml
139
+ arch: omniemv1
140
+ encoder: emdinov1
141
+ img_z: 1
142
+ out_channels: 2
143
+ kernel3d_z: null
144
+ task_type: image2label
145
+ resize4emdino: false
146
+ mean: 0.5333333333333333
147
+ std: 0.23137254901960785
148
+ ```
149
+
150
+ Field guide:
151
+
152
+ | Field | Meaning |
153
+ |---|---|
154
+ | `arch` | model architecture; see `omniem list-models` |
155
+ | `encoder` | encoder architecture; see `omniem list-encoders` |
156
+ | `img_z` | `1` for 2D heads; `>1` for 3D heads |
157
+ | `out_channels` | model output channels |
158
+ | `kernel3d_z` | z-kernel for 3D heads; usually `null` for 2D |
159
+ | `task_type` | `image2label`, `image2image`, or `null` |
160
+ | `resize4emdino` | whether the model uses resize-to-encoder-grid behavior |
161
+ | `mean`, `std` | fixed training normalization for this head |
162
+
163
+ `task_type` controls the canonical output transform:
164
+
165
+ | `task_type` | Meaning | Output transform |
166
+ |---|---|---|
167
+ | `image2label` | segmentation / labels | `argmax` over channels |
168
+ | `image2image` | restoration / denoise | `sigmoid`, clamp to `[0, 1]`, scale to uint |
169
+ | omitted / `null` | model has no output opinion | raw float logits only |
170
+
171
+ For a denoise/restoration head, `out_channels` is usually `1` and
172
+ `task_type: image2image`. For segmentation, `out_channels` is the number of
173
+ classes and `task_type: image2label`.
174
+
175
+ ## First Commands
176
+
177
+ ### Get the example inputs, configs, and weights
178
+
179
+ The commands below read from three local folders. None of them ship inside the
180
+ pip wheel, so gather them once before running anything:
181
+
182
+ | Folder | What it holds | How to get it |
183
+ |---|---|---|
184
+ | `examples/` | small example EM images (`.tif`) | tracked in the repo (see below) |
185
+ | `configs/` | model config YAMLs | Google Drive (see [Available Models](#available-models)) |
186
+ | `weights/` | backbone + head weight files | Google Drive (see [Available Models](#available-models)) |
187
+
188
+ **`examples/`** — if you installed by `git clone`, the example images are already
189
+ in `examples/`. If you installed with `pip`, download them into a local
190
+ `examples/` folder:
191
+
192
+ ```bash
193
+ mkdir -p examples
194
+ BASE=https://raw.githubusercontent.com/pku-maleilab/omniem-package/main/examples
195
+ curl -L -o examples/2d_MitoEM_H_0_0_0.tif "$BASE/2d_MitoEM_H_0_0_0.tif"
196
+ curl -L -o examples/3d_AxonEM-H-0-0-0_0_0_0.tif "$BASE/3d_AxonEM-H-0-0-0_0_0_0.tif"
197
+ curl -L -o "examples/gly-z=0.tif" "$BASE/gly-z=0.tif"
198
+ ```
199
+
200
+ **`configs/` and `weights/`** — these are distributed outside the wheel. Download
201
+ the model config YAMLs and the backbone/head weight files from the Google Drive
202
+ links in [Available Models](#available-models), then place them in local
203
+ `configs/` and `weights/` folders so the paths below resolve:
204
+
205
+ ```text
206
+ configs/ model_*.yaml (config YAMLs)
207
+ weights/ backbone_emdino_v1.pt, head_*.pt (weight files)
208
+ ```
209
+
210
+ Run the commands from the directory that contains these `examples/`, `configs/`,
211
+ and `weights/` folders.
212
+
213
+ ### Run a model
214
+
215
+ Run model inference from the CLI:
216
+
217
+ ```bash
218
+ omniem infer \
219
+ -i examples/2d_MitoEM_H_0_0_0.tif \
220
+ -m configs/model_mito-seg-ViT-L-2D.yaml \
221
+ --backbone weights/backbone_emdino_v1.pt \
222
+ --head weights/head_mito-seg-ViT-L-2D.pt \
223
+ -o out/mito_labels.tif
224
+ ```
225
+
226
+ Run the same model from Python:
227
+
228
+ ```python
229
+ import numpy as np
230
+ import tifffile
231
+ import torch
232
+ from omniem import OmniEM
233
+
234
+ model = OmniEM.load(
235
+ "configs/model_mito-seg-ViT-L-2D.yaml",
236
+ backbone="weights/backbone_emdino_v1.pt",
237
+ head="weights/head_mito-seg-ViT-L-2D.pt",
238
+ )
239
+
240
+ img = tifffile.imread("examples/2d_MitoEM_H_0_0_0.tif")
241
+ x = torch.from_numpy(img.astype(np.float32) / 255.0)
242
+ logits = model.predict(x, axes="yx")
243
+ labels = model.apply_output(logits, axes="yx", dtype="uint8")
244
+ ```
245
+
246
+ ### Output-size control (super-resolution)
247
+
248
+ OmniEM models are shape-preserving (output XY == input XY). To get a larger
249
+ output, for example super-resolution, resize the input up first with
250
+ `--output-scale F`; the model then returns its output at the scaled size
251
+ (`F > 1` upscales, `F < 1` is a quick-inference speed trade-off). It is XY-only
252
+ (Z is never resized; 3D volumes warn) and orthogonal to `--conform`:
253
+
254
+ ```bash
255
+ omniem infer \
256
+ -i examples/2d_MitoEM_H_0_0_0.tif \
257
+ -m configs/model_superreso-emdiffuse-l.yaml \
258
+ --backbone weights/backbone_emdino_v1.pt \
259
+ --head weights/head_superreso-emdiffuse-l.pt \
260
+ --output-scale 1.5 \
261
+ -o out/mito_1.5x.tif
262
+ ```
263
+
264
+ ### Split or merge weight files
265
+
266
+ Convert between a merged whole-model `.pt` and a `backbone` + `head` pair. The
267
+ boundary is the net's derived encoder prefix, so it is correct for any encoder.
268
+
269
+ ```bash
270
+ # merged -> split pair
271
+ omniem split -m configs/model_mito-seg-ViT-L-2D.yaml \
272
+ -i weights/merged_mito-seg.pt \
273
+ --backbone weights/backbone_emdino_v1.pt --head weights/head_mito-seg-ViT-L-2D.pt
274
+
275
+ # split pair -> merged
276
+ omniem merge -m configs/model_mito-seg-ViT-L-2D.yaml \
277
+ --backbone weights/backbone_emdino_v1.pt --head weights/head_mito-seg-ViT-L-2D.pt \
278
+ -o weights/merged_mito-seg.pt
279
+ ```
280
+
281
+ ## Full Guides
282
+
283
+ - [CLI guide](docs/cli.md): all `omniem infer`, `omniem features`, `omniem split`,
284
+ and `omniem merge` options, with command examples.
285
+ - [Python API guide](docs/api.md): `OmniEM`, `EMEncoder`, shared encoders,
286
+ lower-level calls, weight saving, errors, and API-doc generation.
287
+
288
+ ## Related Projects
289
+
290
+ - [omniem-train](https://github.com/pku-maleilab/omniem-train): the recommended
291
+ training pipeline for OmniEM heads; it builds on this package's public API.
292
+ - [napari-omniem](https://github.com/pku-maleilab/napari-omniem): a napari GUI
293
+ plugin for interactive OmniEM inference.
294
+
295
+ ## Future Features
296
+
297
+ The current package focuses on the core model/encoder surface. These features are
298
+ planned for later releases:
299
+
300
+ - large-image tiling and blending (`Inferer`);
301
+ - volume streaming and hdf5/zarr/n5 IO;
302
+ - feature-export orchestration (`Exporter`);
303
+ - install extras such as `[infer]`, `[volume]`, and `[full]`.
304
+
305
+ ## License
306
+
307
+ [MIT](LICENSE).