Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c698999
psudocode
ieivanov Aug 6, 2025
4f703b7
check right shape
ieivanov Aug 6, 2025
f542d2c
first try
tayllatheodoro Aug 25, 2025
da31198
add channel
tayllatheodoro Aug 26, 2025
a3679f8
current stage
tayllatheodoro Aug 26, 2025
5b81b34
working stage
tayllatheodoro Aug 26, 2025
8ac3941
Merge branch 'main' into predict_volume
tayllatheodoro Aug 26, 2025
30b6fbf
api wrapper
tayllatheodoro Aug 26, 2025
433d195
add examples
tayllatheodoro Aug 27, 2025
324cdf1
reorder inputs
tayllatheodoro Aug 27, 2025
8b4d243
rename input tensor
tayllatheodoro Aug 27, 2025
04cbbb1
remove comment
tayllatheodoro Aug 27, 2025
214bbeb
test
tayllatheodoro Aug 27, 2025
22d5f4f
style
tayllatheodoro Aug 27, 2025
f5eacca
add test docstrig
tayllatheodoro Aug 27, 2025
9cf5870
style
tayllatheodoro Aug 27, 2025
612db64
first pass of review corrections
tayllatheodoro Aug 28, 2025
227ef0f
bug fix
tayllatheodoro Aug 28, 2025
1cb4b74
move to translation tests
tayllatheodoro Aug 28, 2025
236dfc6
use predict_step
tayllatheodoro Aug 28, 2025
5117de2
update example
tayllatheodoro Aug 28, 2025
7b1be81
move to shrimpy
tayllatheodoro Aug 28, 2025
e489ef5
docstring
tayllatheodoro Aug 28, 2025
5da4c99
Update viscy/translation/engine.py
tayllatheodoro Sep 5, 2025
70dab29
Update viscy/translation/engine.py
tayllatheodoro Sep 5, 2025
ddbd83a
Update examples/virtual_staining/VS_model_inference/demo_api.py
tayllatheodoro Sep 5, 2025
5b74bc2
Update examples/virtual_staining/VS_model_inference/demo_api.py
tayllatheodoro Sep 5, 2025
b93020b
Update examples/virtual_staining/VS_model_inference/demo_api.py
tayllatheodoro Sep 5, 2025
1ba5bba
Update viscy/translation/engine.py
tayllatheodoro Sep 5, 2025
ecd11b5
Update viscy/translation/engine.py
tayllatheodoro Sep 5, 2025
8f09e40
fallback logic to the init method
tayllatheodoro Sep 5, 2025
f05ace3
doc string
tayllatheodoro Sep 5, 2025
35b70d1
remove torch.cuda.synchronize()
tayllatheodoro Sep 5, 2025
d7ccd36
Merge branch 'main' into predict_volume
edyoshikun Feb 4, 2026
99f2b6e
- Removed the redundant _predict_pad check (lines 566-569) since …
edyoshikun Feb 4, 2026
973329d
comparison example
edyoshikun Feb 4, 2026
c095b9f
format
edyoshikun Feb 4, 2026
a35f097
use the same blending function
edyoshikun Feb 4, 2026
621e178
update comparison prediction script
edyoshikun Feb 4, 2026
9a27478
rename example script
edyoshikun Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions examples/virtual_staining/VS_model_inference/demo_vscyto_w_ttas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# %%
"""
Demo: In-memory volume prediction using predict_sliding_windows.

This API provides the same results as the `viscy predict` CLI (HCSPredictionWriter)
since both use the same linear feathering blending algorithm for overlapping windows.
"""

from pathlib import Path

import napari
import numpy as np
import torch
from iohub import open_ome_zarr

from viscy.translation.engine import AugmentedPredictionVSUNet, VSUNet

DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Instantiate model manually
model = (
VSUNet(
architecture="fcmae",
model_config={
"in_channels": 1,
"out_channels": 2,
"in_stack_depth": 21,
"encoder_blocks": [3, 3, 9, 3],
"dims": [96, 192, 384, 768],
"decoder_conv_blocks": 2,
"stem_kernel_size": [7, 4, 4],
"pretraining": False,
"head_conv": True,
"head_conv_expansion_ratio": 4,
"head_conv_pool": False,
},
ckpt_path="/path/to/checkpoint.ckpt",
)
.to(DEVICE)
.eval()
)

vs = (
AugmentedPredictionVSUNet(
model=model.model,
forward_transforms=[lambda t: t],
inverse_transforms=[lambda t: t],
)
.to(DEVICE)
.eval()
)

# Load data
path = Path("/path/to/your.zarr/0/1/000000")
with open_ome_zarr(path) as ds:
vol_np = np.asarray(ds.data[0:1, 0:1]) # (1, 1, Z, Y, X)

vol = torch.from_numpy(vol_np).float().to(DEVICE)

# Run inference with sliding windows and linear feathering blending
# step=1 gives maximum overlap; increase step for faster inference
with torch.inference_mode():
pred = vs.predict_sliding_windows(vol, out_channel=2, step=1)

# Visualize
pred_np = pred.cpu().numpy()
nuc, mem = pred_np[0, 0], pred_np[0, 1]

viewer = napari.Viewer()
viewer.add_image(vol_np, name="phase_input", colormap="gray")
viewer.add_image(nuc, name="virt_nuclei", colormap="magenta")
viewer.add_image(mem, name="virt_membrane", colormap="cyan")
napari.run()
68 changes: 67 additions & 1 deletion tests/translation/test_predict_writer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import numpy as np
import pytest
import torch
from iohub import open_ome_zarr

from viscy.data.hcs import HCSDataModule
from viscy.trainer import VisCyTrainer
from viscy.translation.engine import VSUNet
from viscy.translation.engine import AugmentedPredictionVSUNet, VSUNet
from viscy.translation.predict_writer import HCSPredictionWriter, _pad_shape


Expand Down Expand Up @@ -67,3 +69,67 @@ def test_predict_writer(preprocessed_hcs_dataset, tmp_path, array_key):
for _, pos in result.positions():
assert pos[array_key][:].any()
assert pos[array_key].shape == expected_shape


def test_blend_in_consistency():
"""Verify _blend_in produces identical results for torch and numpy inputs."""
from viscy.translation.engine import _blend_in

depth = 5
shape_4d = (2, depth, 8, 8) # C, Z, Y, X (numpy from HCSPredictionWriter)

np.random.seed(42)
old_np = np.random.rand(*shape_4d).astype(np.float32)
new_np = np.random.rand(*shape_4d).astype(np.float32)
old_torch = torch.from_numpy(old_np).unsqueeze(0) # Add batch dim
new_torch = torch.from_numpy(new_np).unsqueeze(0)

z_slice = slice(2, 2 + depth)

result_np = _blend_in(old_np, new_np, z_slice)
result_torch = _blend_in(old_torch, new_torch, z_slice)

np.testing.assert_allclose(
result_np, result_torch.squeeze(0).numpy(), rtol=1e-5, atol=1e-5
)


def test_predict_sliding_windows_output_shape(preprocessed_hcs_dataset):
"""Verify predict_sliding_windows produces correct output shape."""
z_window_size = 5
data_path = preprocessed_hcs_dataset
channel_split = 2

with open_ome_zarr(data_path) as dataset:
channel_names = dataset.channel_names
first_pos = next(dataset.positions())[1]
source_data = first_pos["0"][0:1, :channel_split]
source_tensor = torch.from_numpy(source_data).float()

model = VSUNet(
architecture="fcmae",
model_config=dict(
in_channels=channel_split,
out_channels=len(channel_names) - channel_split,
encoder_blocks=[2, 2, 2, 2],
dims=[4, 8, 16, 32],
decoder_conv_blocks=2,
stem_kernel_size=[z_window_size, 4, 4],
in_stack_depth=z_window_size,
pretraining=False,
),
)

vs = AugmentedPredictionVSUNet(model=model.model)

with torch.inference_mode():
output = vs.predict_sliding_windows(
source_tensor,
out_channel=len(channel_names) - channel_split,
step=1,
)

expected_shape = (1, len(channel_names) - channel_split, *source_tensor.shape[2:])
assert output.shape == expected_shape, (
f"Expected {expected_shape}, got {output.shape}"
)
Loading