Repository navigation
Port virtual_staining examples into applications/cytoland #409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
edyoshikun
merged 47 commits into
modular-viscy-staging
from
cytoland-virtual-staining-examples
May 18, 2026
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
c07f9c9
Exempt examples/ from docstring and line-length lint rules
edyoshikun 89a0b82
Port VS_model_inference demos from main into applications/cytoland
edyoshikun 0a9aab3
Port dlmbl_exercise tutorial from main into applications/cytoland
edyoshikun 7bf9a4b
Extend examples/ lint exemption to cover E402 and F821
edyoshikun 08f5979
Port vcp_tutorials from main into applications/cytoland
edyoshikun 2dbbac5
Document ported examples in cytoland README
edyoshikun c8542e1
Port phase_contrast tutorial from main into applications/cytoland
edyoshikun e3b27aa
Teach PyTorch Lightning in the dlmbl exercise
edyoshikun c5cfe6a
Sharpen dlmbl exercise teaching material
edyoshikun 6b156d3
Apply 2025 DL@MBL feedback to dlmbl exercise
edyoshikun 63d96a1
Migrate dlmbl setup from conda to uv
edyoshikun 8bd4ea9
Replace SSIM with microSSIM in dlmbl exercise
edyoshikun 34af4f1
Point dlmbl exercise to zarrv3 datasets
edyoshikun 4453627
Rename dlmbl_exercise to dl-course-exercise
edyoshikun f5ce816
Split dl-course-exercise setup into TA and student scripts
edyoshikun 2eae363
Bump dl-course-exercise to Python 3.13 and viscy>=0.5.0a0
edyoshikun 15b6f16
Polish dl-course-exercise solution.py
edyoshikun 7dbdaa6
Polish prose in dl-course-exercise solution.py
edyoshikun ae01b60
Port Task 2.5 (fluorescence -> phase) from DL@Janelia exercise
edyoshikun 1f92f92
Potential fix for pull request finding
edyoshikun 5fc1d7c
Potential fix for pull request finding
edyoshikun 52b969e
Potential fix for pull request finding
edyoshikun bc71142
Potential fix for pull request finding
edyoshikun 26be25e
Potential fix for pull request finding
edyoshikun 7bbe987
Potential fix for pull request finding
edyoshikun dc5a855
Potential fix for pull request finding
edyoshikun 3f772ec
Potential fix for pull request finding
edyoshikun c5d0eb9
Potential fix for pull request finding
edyoshikun 22d9549
Potential fix for pull request finding
edyoshikun 7df7457
Potential fix for pull request finding
edyoshikun 891cd4e
Potential fix for pull request finding
edyoshikun 1ffb236
Potential fix for pull request finding
edyoshikun acae30b
Potential fix for pull request finding
edyoshikun a738d94
Potential fix for pull request finding
edyoshikun 1ca6fa1
Potential fix for pull request finding
edyoshikun 968c720
Potential fix for pull request finding
edyoshikun 5dd202f
Potential fix for pull request finding
edyoshikun 83dfa24
Potential fix for pull request finding
edyoshikun 0a0933d
Potential fix for pull request finding
edyoshikun f1794d7
Apply suggestions from code review
edyoshikun 3a12a95
Apply suggestions from code review
edyoshikun 830170a
demos: remove invalid `architecture` kwarg from HCSDataModule calls
edyoshikun 84662fe
demo_vscyto_w_ttas: apply precomputed FOV stats normalization
edyoshikun 7c10bdf
phase_contrast setup: resolve cytoland path from script location
edyoshikun 119c301
phase_contrast solution: drop unused trainer, make GPU placement expl…
edyoshikun 8e089b0
dl-course solution: fix DATA_ROOT semantics, TTA ordering, GPU loads
edyoshikun 0698483
dl-course README: recommend solution.ipynb path first, warn about tas…
edyoshikun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
applications/cytoland/examples/VS_model_inference/demo_vscyto2d.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| # %% [markdown] | ||
| """ | ||
| # 2D Virtual Staining of A549 Cells | ||
| --- | ||
| ## Prediction using the VSCyto2D to predict nuclei and plasma membrane from phase. | ||
| This example shows how to virtually stain A549 cells using the _VSCyto2D_ model. | ||
| The model is trained to predict the membrane and nuclei channels from the phase channel. | ||
| """ | ||
|
|
||
| # %% Imports and paths | ||
| from pathlib import Path | ||
|
|
||
| from iohub import open_ome_zarr | ||
| from plot import plot_vs_n_fluor | ||
|
|
||
| # Cytoland and VisCy modular classes for the trainer and model | ||
| from cytoland.engine import FcmaeUNet | ||
| from viscy_data.hcs import HCSDataModule | ||
| from viscy_transforms import NormalizeSampled | ||
| from viscy_utils.callbacks import HCSPredictionWriter | ||
| from viscy_utils.trainer import VisCyTrainer | ||
|
|
||
| # %% [markdown] tags=[] | ||
| # | ||
| # <div class="alert alert-block alert-info"> | ||
| # | ||
| # # Download the dataset and checkpoints for the VSCyto2D model | ||
| # | ||
| # - Download the VSCyto2D test dataset and model checkpoint from here: <br> | ||
| # https://public.czbiohub.org/comp.micro/viscy | ||
| # - Update the `input_data_path` and `model_ckpt_path` variables with the path to the downloaded files. | ||
| # - Select a FOV (i.e 0/0/0). | ||
| # - Set an output path for the predictions. | ||
| # | ||
| # </div> | ||
|
|
||
| # %% | ||
| # TODO: Set download paths | ||
| root_dir = Path("") | ||
| # TODO: modify the path to the downloaded dataset | ||
| input_data_path = root_dir / "VSCyto2D/test/a549_hoechst_cellmask_test.zarr" | ||
| # TODO: modify the path to the downloaded checkpoint | ||
| model_ckpt_path = "/epoch=399-step=23200.ckpt" | ||
| # TODO: modify the path | ||
| # Zarr store to save the predictions | ||
| output_path = root_dir / "./a549_prediction.zarr" | ||
| # TODO: Choose an FOV | ||
| fov = "0/0/0" | ||
|
|
||
| input_data_path = input_data_path / fov | ||
|
|
||
| # %% | ||
| # Create the VSCyto2D network | ||
|
|
||
| # Reduce the batch size if encountering out-of-memory errors | ||
| BATCH_SIZE = 8 | ||
| # NOTE: Set the number of workers to 0 for Windows and macOS | ||
| # since multiprocessing only works with a | ||
| # `if __name__ == '__main__':` guard. | ||
| # On Linux, set it to the number of CPU cores to maximize performance. | ||
| NUM_WORKERS = 0 | ||
| phase_channel_name = "Phase3D" | ||
|
|
||
| # %%[markdown] | ||
| """ | ||
| For this example we will use the following parameters: | ||
| For more information on the VSCyto2D model, | ||
| see ``viscy.unet.networks.fcmae`` | ||
| ([source code](https://github.com/mehta-lab/VisCy/blob/main/viscy/unet/networks/fcmae.py)) | ||
| for configuration details. | ||
| """ | ||
| # %% | ||
| # Setup the data module. | ||
| data_module = HCSDataModule( | ||
| data_path=input_data_path, | ||
| source_channel=phase_channel_name, | ||
| target_channel=["Nuclei", "Membrane"], | ||
| z_window_size=1, | ||
| split_ratio=0.8, | ||
| batch_size=BATCH_SIZE, | ||
| num_workers=NUM_WORKERS, | ||
| normalizations=[ | ||
| NormalizeSampled( | ||
| [phase_channel_name], | ||
| level="fov_statistics", | ||
| subtrahend="median", | ||
| divisor="iqr", | ||
| ) | ||
| ], | ||
| ) | ||
| data_module.prepare_data() | ||
| data_module.setup(stage="predict") | ||
| # %% | ||
| # Setup the model. | ||
| # Dictionary that specifies key parameters of the model. | ||
| config_VSCyto2D = { | ||
| "in_channels": 1, | ||
| "out_channels": 2, | ||
| "encoder_blocks": [3, 3, 9, 3], | ||
| "dims": [96, 192, 384, 768], | ||
| "decoder_conv_blocks": 2, | ||
| "stem_kernel_size": [1, 2, 2], | ||
| "in_stack_depth": 1, | ||
| "pretraining": False, | ||
| } | ||
|
|
||
| model_VSCyto2D = FcmaeUNet.load_from_checkpoint(model_ckpt_path, model_config=config_VSCyto2D) | ||
| model_VSCyto2D.eval() | ||
|
|
||
| # %% | ||
| # Setup the Trainer | ||
| trainer = VisCyTrainer( | ||
| accelerator="gpu", | ||
| callbacks=[HCSPredictionWriter(output_path)], | ||
| ) | ||
|
|
||
| # Start the predictions | ||
| trainer.predict( | ||
| model=model_VSCyto2D, | ||
| datamodule=data_module, | ||
| return_predictions=False, | ||
| ) | ||
|
|
||
| # %% | ||
| # Open the output_zarr store and inspect the output | ||
| # Show the individual channels and the fused in a 1x3 plot | ||
| output_path = Path(output_path) / fov | ||
|
|
||
| # %% | ||
| # Open the predicted data | ||
| vs_store = open_ome_zarr(output_path, mode="r") | ||
| # Get the 2D images | ||
| vs_nucleus = vs_store[0][0, 0, 0] # (t,c,z,y,x) | ||
| vs_membrane = vs_store[0][0, 1, 0] # (t,c,z,y,x) | ||
| # Open the experimental fluorescence | ||
| fluor_store = open_ome_zarr(input_data_path, mode="r") | ||
| # Get the 2D images | ||
| # NOTE: Channel indices hardcoded for this dataset | ||
| fluor_nucleus = fluor_store[0][0, 1, 0] # (t,c,z,y,x) | ||
| fluor_membrane = fluor_store[0][0, 2, 0] # (t,c,z,y,x) | ||
|
|
||
| # Plot | ||
| plot_vs_n_fluor(vs_nucleus, vs_membrane, fluor_nucleus, fluor_membrane) | ||
|
|
||
| vs_store.close() | ||
| fluor_store.close() |
158 changes: 158 additions & 0 deletions
158
applications/cytoland/examples/VS_model_inference/demo_vscyto3d.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| # %% [markdown] | ||
| """ | ||
| # 3D Virtual Staining of HEK293T Cells | ||
| --- | ||
| ## Prediction using the VSCyto3D to predict nuclei and membrane from phase. | ||
| This example shows how to virtually stain HEK293T cells using the _VSCyto3D_ model. | ||
| The model is trained to predict the membrane and nuclei channels from the phase channel. | ||
| """ | ||
|
|
||
| # %% Imports and paths | ||
| from pathlib import Path | ||
|
|
||
| from iohub import open_ome_zarr | ||
| from plot import plot_vs_n_fluor | ||
|
|
||
| # Cytoland and VisCy modular classes for the trainer and model | ||
| from cytoland.engine import VSUNet | ||
| from viscy_data.hcs import HCSDataModule | ||
| from viscy_transforms import NormalizeSampled | ||
| from viscy_utils.callbacks import HCSPredictionWriter | ||
| from viscy_utils.trainer import VisCyTrainer | ||
|
|
||
| # %% [markdown] | ||
| """ | ||
| ## Data and Model Paths | ||
|
|
||
| The dataset and model checkpoint files need to be downloaded before running this example. | ||
| """ | ||
|
|
||
| # %% [markdown] tags=[] | ||
| # | ||
| # <div class="alert alert-block alert-info"> | ||
| # | ||
| # # Download the dataset and checkpoints VSCyto3D | ||
| # | ||
| # - Download the VSCyto3D test dataset and model checkpoint from here: <br> | ||
| # https://public.czbiohub.org/comp.micro/viscy | ||
| # - Update the `input_data_path` and `model_ckpt_path` variables with the path to the downloaded files. | ||
| # - Select a FOV (i.e plate/0/0). | ||
| # - Set an output path for the predictions. | ||
| # | ||
| # </div> | ||
| # %% | ||
| # TODO: modify the path to the downloaded dataset | ||
| input_data_path = "/no_pertubation_Phase1e-3_Denconv_Nuc8e-4_Mem8e-4_pad15_bg50.zarr" | ||
|
|
||
| # TODO: modify the path to the downloaded checkpoint | ||
| model_ckpt_path = "/epoch=48-step=18130.ckpt" | ||
|
|
||
| # TODO: modify the path | ||
| # Zarr store to save the predictions | ||
| output_path = "./hek_prediction_3d.zarr" | ||
|
|
||
| # TODO: Choose an FOV | ||
| # FOV of interest | ||
| fov = "plate/0/0" | ||
|
|
||
| input_data_path = Path(input_data_path) / fov | ||
|
|
||
| # %% | ||
| # Create the VSCyto3D model | ||
|
|
||
| # Reduce the batch size if encountering out-of-memory errors | ||
| BATCH_SIZE = 2 | ||
| # NOTE: Set the number of workers to 0 for Windows and macOS | ||
| # since multiprocessing only works with a | ||
| # `if __name__ == '__main__':` guard. | ||
| # On Linux, set it to the number of CPU cores to maximize performance. | ||
| NUM_WORKERS = 0 | ||
| phase_channel_name = "Phase3D" | ||
|
|
||
| # %%[markdown] | ||
| """ | ||
| For this example we will use the following parameters: | ||
| ### For more information on the VSCyto3D model: | ||
| See ``viscy.unet.networks.unext2`` | ||
| ([source code](https://github.com/mehta-lab/VisCy/blob/main/viscy/unet/networks/unext2.py)) | ||
| for configuration details. | ||
| """ | ||
| # %% | ||
| # Setup the data module. | ||
| data_module = HCSDataModule( | ||
| data_path=input_data_path, | ||
| source_channel=phase_channel_name, | ||
| target_channel=["Nuclei", "Membrane"], | ||
| z_window_size=5, | ||
| split_ratio=0.8, | ||
| batch_size=BATCH_SIZE, | ||
| num_workers=NUM_WORKERS, | ||
| normalizations=[ | ||
| NormalizeSampled( | ||
| [phase_channel_name], | ||
| level="fov_statistics", | ||
| subtrahend="median", | ||
| divisor="iqr", | ||
| ) | ||
| ], | ||
| ) | ||
| data_module.prepare_data() | ||
| data_module.setup(stage="predict") | ||
| # %% | ||
| # Setup the model. | ||
| # Dictionary that specifies key parameters of the model. | ||
| config_VSCyto3D = { | ||
| "in_channels": 1, | ||
| "out_channels": 2, | ||
| "in_stack_depth": 5, | ||
| "backbone": "convnextv2_tiny", | ||
| "stem_kernel_size": (5, 4, 4), | ||
| "decoder_mode": "pixelshuffle", | ||
| "head_expansion_ratio": 4, | ||
| "head_pool": True, | ||
| } | ||
|
|
||
| model_VSCyto3D = VSUNet.load_from_checkpoint(model_ckpt_path, architecture="UNeXt2", model_config=config_VSCyto3D) | ||
| model_VSCyto3D.eval() | ||
|
|
||
| # %% | ||
| # Setup the Trainer | ||
| trainer = VisCyTrainer( | ||
| accelerator="gpu", | ||
| callbacks=[HCSPredictionWriter(output_path)], | ||
| ) | ||
|
|
||
| # Start the predictions | ||
| trainer.predict( | ||
| model=model_VSCyto3D, | ||
| datamodule=data_module, | ||
| return_predictions=False, | ||
| ) | ||
|
|
||
| # %% | ||
| # Open the output_zarr store and inspect the output | ||
| # Show the individual channels and the fused in a 1x3 plot | ||
| output_path = Path(output_path) / fov | ||
|
|
||
| # %% | ||
| # Open the predicted data | ||
| vs_store = open_ome_zarr(output_path, mode="r") | ||
| T, C, Z, Y, X = vs_store.data.shape | ||
|
|
||
| # Get a z-slice | ||
| z_slice = Z // 2 # NOTE: using the middle slice of the stack. Change as needed. | ||
| vs_nucleus = vs_store[0][0, 0, z_slice] # (t,c,z,y,x) | ||
| vs_membrane = vs_store[0][0, 1, z_slice] # (t,c,z,y,x) | ||
| # Open the experimental fluorescence | ||
| fluor_store = open_ome_zarr(input_data_path, mode="r") | ||
| # Get the 2D images | ||
| # NOTE: Channel indices hardcoded for this dataset | ||
| fluor_nucleus = fluor_store[0][0, 2, z_slice] # (t,c,z,y,x) | ||
| fluor_membrane = fluor_store[0][0, 1, z_slice] # (t,c,z,y,x) | ||
|
|
||
| # Plot | ||
| plot_vs_n_fluor(vs_nucleus, vs_membrane, fluor_nucleus, fluor_membrane) | ||
|
|
||
| # Close stores | ||
| vs_store.close() | ||
| fluor_store.close() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.