Download tools/_native_scimilarity.py from microsoft/scFM-dataselection: direct link, hf CLI and curl.
- Browser
- Download file 2.72 kB
-
https://huggingface.co/microsoft/scFM-dataselection/resolve/main/tools/_native_scimilarity.py
- Command line
-
hf download hf://microsoft/scFM-dataselection/tools/_native_scimilarity.py
-
curl -L -o _native_scimilarity.py https://huggingface.co/microsoft/scFM-dataselection/resolve/main/tools/_native_scimilarity.py
2.72 kB
| """Load the study's native SCimilarity encoder and decoder with PyTorch.""" | |
| import json | |
| from pathlib import Path | |
| import torch | |
| from _scimilarity_networks import Decoder, Encoder | |
| class SCimilarity(torch.nn.Module): | |
| def __init__(self, gene_order, hidden_dim, latent_dim): | |
| super().__init__() | |
| self.gene_order = tuple(gene_order) | |
| self.n_genes = len(self.gene_order) | |
| self.latent_dim = latent_dim | |
| self.encoder = Encoder(self.n_genes, latent_dim=latent_dim, hidden_dim=hidden_dim) | |
| self.decoder = Decoder(self.n_genes, latent_dim=latent_dim, hidden_dim=hidden_dim) | |
| def forward(self, expression): | |
| embedding = self.encoder(expression) | |
| return embedding, self.decoder(embedding) | |
| def _load_state(path): | |
| checkpoint = torch.load(path, map_location="cpu", weights_only=True) | |
| if not isinstance(checkpoint, dict) or set(checkpoint) != {"state_dict"}: | |
| raise ValueError(f"Expected only a state_dict in {path}") | |
| state = checkpoint["state_dict"] | |
| if not isinstance(state, dict) or not state: | |
| raise ValueError(f"Missing model tensors in {path}") | |
| if any(not isinstance(value, torch.Tensor) or not torch.isfinite(value).all() | |
| for value in state.values()): | |
| raise ValueError(f"Non-tensor or nonfinite model state in {path}") | |
| return state | |
| def load_scimilarity(model_directory): | |
| directory = Path(model_directory) | |
| gene_order = [ | |
| line.strip() for line in (directory / "gene_order.tsv").read_text().splitlines() | |
| ] | |
| if not gene_order or any(not gene for gene in gene_order) or len(set(gene_order)) != len(gene_order): | |
| raise ValueError("SCimilarity gene order must contain unique, nonempty gene symbols") | |
| encoder_state = _load_state(directory / "encoder.ckpt") | |
| layer_sizes = json.loads((directory / "layer_sizes.json").read_text()) | |
| if {name: list(value.shape) for name, value in encoder_state.items()} != layer_sizes: | |
| raise ValueError("SCimilarity encoder tensors disagree with layer_sizes.json") | |
| layers = [ | |
| shape for name, shape in sorted( | |
| layer_sizes.items(), key=lambda item: int(item[0].split(".")[1]) | |
| ) | |
| if name.endswith(".weight") and len(shape) == 2 | |
| ] | |
| if len(layers) < 2 or layers[0][1] != len(gene_order): | |
| raise ValueError("SCimilarity network dimensions disagree with the gene order") | |
| model = SCimilarity( | |
| gene_order, hidden_dim=[shape[0] for shape in layers[:-1]], | |
| latent_dim=layers[-1][0], | |
| ) | |
| model.encoder.load_state_dict(encoder_state, strict=True) | |
| model.decoder.load_state_dict(_load_state(directory / "decoder.ckpt"), strict=True) | |
| model.eval() | |
| return model | |