| """Initialization and utility helpers for DeepPTR.""" |
|
|
| from __future__ import annotations |
|
|
| from typing import TYPE_CHECKING |
|
|
| import numpy as np |
| import torch |
| from torch import nn |
|
|
| if TYPE_CHECKING: |
| from anndata import AnnData |
|
|
|
|
| def init_weights(module: nn.Module) -> None: |
| """Xavier-uniform initialization for linear layers.""" |
| if isinstance(module, nn.Linear): |
| nn.init.xavier_uniform_(module.weight) |
| if module.bias is not None: |
| nn.init.zeros_(module.bias) |
|
|
|
|
| def beta_from_adata(adata: AnnData) -> torch.Tensor: |
| """Extract analytical beta estimates from *adata* for warm-starting. |
| |
| Falls back to ones if ``adata.var['beta']`` is absent. |
| |
| Returns |
| ------- |
| torch.Tensor |
| Shape ``(n_genes,)``, dtype float32. |
| """ |
| if "beta" in adata.var.columns: |
| beta = adata.var["beta"].values.astype(np.float32) |
| beta = np.clip(beta, 1e-4, None) |
| return torch.from_numpy(np.log(beta)) |
| return torch.zeros(adata.n_vars, dtype=torch.float32) |
|
|
|
|
| def get_library_sizes(adata: AnnData) -> tuple[np.ndarray, np.ndarray]: |
| """Compute per-cell library sizes for unspliced and spliced layers. |
| |
| Uses raw integer counts stored in ``adata.layers``. |
| |
| Returns |
| ------- |
| (l_u, l_s) : tuple of np.ndarray |
| Each shape ``(n_obs,)``, float32. |
| """ |
| from scipy.sparse import issparse |
|
|
| for layer in ("spliced", "unspliced"): |
| if layer not in adata.layers: |
| raise KeyError(f"Missing required layer: {layer}") |
|
|
| def _sum(mat: np.ndarray | "scipy.sparse.spmatrix") -> np.ndarray: |
| if issparse(mat): |
| return np.asarray(mat.sum(axis=1)).ravel().astype(np.float32) |
| return np.asarray(mat.sum(axis=1)).ravel().astype(np.float32) |
|
|
| l_s = _sum(adata.layers["spliced"]) |
| l_u = _sum(adata.layers["unspliced"]) |
|
|
| |
| l_s = np.clip(l_s, 1.0, None) |
| l_u = np.clip(l_u, 1.0, None) |
|
|
| return l_u, l_s |
|
|