geneflowdecoder 0.1.0__tar.gz → 0.1.2__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.
- {geneflowdecoder-0.1.0/src/geneflowdecoder.egg-info → geneflowdecoder-0.1.2}/PKG-INFO +1 -1
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/pyproject.toml +1 -1
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder/_core.py +118 -16
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder/_version.py +1 -1
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2/src/geneflowdecoder.egg-info}/PKG-INFO +1 -1
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/LICENSE +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/README.md +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/setup.cfg +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder/__init__.py +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder.egg-info/SOURCES.txt +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder.egg-info/dependency_links.txt +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder.egg-info/requires.txt +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder.egg-info/top_level.txt +0 -0
- {geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/tests/test_api.py +0 -0
|
@@ -28,31 +28,121 @@ try:
|
|
|
28
28
|
import torch.nn as nn
|
|
29
29
|
import torch.nn.functional as F
|
|
30
30
|
_no_grad = torch.no_grad
|
|
31
|
+
_TORCH_AVAILABLE = True
|
|
31
32
|
except Exception: # pragma: no cover - soft dep for import-only environments
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
import types
|
|
34
|
+
|
|
35
|
+
torch = types.ModuleType("torch")
|
|
36
|
+
nn = types.ModuleType("torch.nn")
|
|
37
|
+
F = types.ModuleType("torch.nn.functional")
|
|
38
|
+
class _NoGrad:
|
|
39
|
+
"""无 torch 时充当 ``@torch.no_grad()`` 与 ``with torch.no_grad():`` 的透明桩。"""
|
|
40
|
+
|
|
41
|
+
def __call__(self, fn=None):
|
|
42
|
+
return fn if fn is not None else self
|
|
43
|
+
|
|
44
|
+
def __enter__(self):
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def __exit__(self, *args):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
_no_grad = _NoGrad()
|
|
51
|
+
_TORCH_AVAILABLE = False
|
|
52
|
+
|
|
53
|
+
class _Device(str):
|
|
54
|
+
"""``torch.device(device)`` 的桩:保留字符串语义与 ``.type`` 属性。"""
|
|
55
|
+
|
|
56
|
+
def __new__(cls, dev):
|
|
57
|
+
dev = str(dev)
|
|
58
|
+
if dev.startswith("cuda"):
|
|
59
|
+
dev = "cuda"
|
|
60
|
+
return super().__new__(cls, dev)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def type(self):
|
|
64
|
+
return str(self)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# 让 ``class Foo(nn.Module)`` 与 ``Tensor`` 注解在无 torch 时仍能解析。
|
|
68
|
+
# 运行时真正调用前向/构造模型会立即报清晰的错误,而不是在 import 期崩。
|
|
69
|
+
class _ModuleStub:
|
|
70
|
+
def __init_subclass__(cls, **kwargs):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
nn.Module = _ModuleStub # type: ignore[attr-defined]
|
|
74
|
+
|
|
75
|
+
# 补齐 GeneFlowDecoder 类体里会用到的 torch 属性,保持 import 期可解析
|
|
76
|
+
torch.Tensor = object # type: ignore[attr-defined]
|
|
77
|
+
torch.no_grad = _no_grad # 即 _NoGrad() 实例 # type: ignore[attr-defined]
|
|
78
|
+
torch.device = _Device # type: ignore[attr-defined]
|
|
79
|
+
torch.cuda = types.ModuleType("torch.cuda")
|
|
80
|
+
torch.cuda.is_available = lambda: False
|
|
81
|
+
torch.utils = types.ModuleType("torch.utils")
|
|
82
|
+
torch.utils.data = types.ModuleType("torch.utils.data")
|
|
83
|
+
torch.utils.data.TensorDataset = object
|
|
84
|
+
torch.utils.data.DataLoader = object
|
|
39
85
|
Tensor = object # placeholder for type annotations only
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
from torch import Tensor as _TorchTensor # noqa: F401
|
|
89
|
+
Tensor = _TorchTensor # type: ignore
|
|
90
|
+
except Exception:
|
|
91
|
+
Tensor = object # placeholder for type annotations only
|
|
40
92
|
|
|
41
|
-
|
|
42
|
-
from torch import Tensor as _TorchTensor # noqa: F401
|
|
43
|
-
Tensor = _TorchTensor # type: ignore
|
|
44
|
-
except Exception:
|
|
45
|
-
pass
|
|
93
|
+
Array = Union[np.ndarray, Tensor] # type: ignore[valid-type]
|
|
46
94
|
|
|
47
|
-
Array = Union[np.ndarray, torch.Tensor]
|
|
48
95
|
|
|
96
|
+
def _as_tensor(x: Array, device: "torch.device") -> "torch.Tensor":
|
|
97
|
+
"""把 numpy / CPU / GPU 输入规范化成 torch 张量。
|
|
49
98
|
|
|
50
|
-
|
|
99
|
+
关键:输入**已经**在 GPU 上时,保留其原设备,不再 ``.to(device)``。
|
|
100
|
+
否则 cuda 输入会被拷回 CPU,DataLoader 的 pin_memory 又会对它报错:
|
|
101
|
+
RuntimeError: cannot pin 'torch.cuda.FloatTensor'
|
|
102
|
+
"""
|
|
103
|
+
if not _TORCH_AVAILABLE:
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
"GeneFlowDecoder requires PyTorch, but it could not be imported. "
|
|
106
|
+
"Install it with: pip install 'torch>=2.1'"
|
|
107
|
+
)
|
|
51
108
|
if isinstance(x, np.ndarray):
|
|
52
|
-
|
|
109
|
+
return torch.as_tensor(x, device=device) # CPU numpy -> CPU tensor
|
|
110
|
+
if x.device.type != "cpu":
|
|
111
|
+
return x # 已在 GPU:原样返回
|
|
53
112
|
return x.to(device, non_blocking=True)
|
|
54
113
|
|
|
55
114
|
|
|
115
|
+
def _is_cuda_array(x: Array) -> bool:
|
|
116
|
+
"""判断输入是否已经落在 GPU 上。
|
|
117
|
+
|
|
118
|
+
numpy 数组一定在 CPU;torch 张量则可能已在 cuda。DataLoader 的
|
|
119
|
+
``pin_memory`` 只接受 CPU tensor,输入已经是 cuda 时必须降级为 False,
|
|
120
|
+
否则会在 ``pin_memory()`` 处抛出
|
|
121
|
+
``RuntimeError: cannot pin 'torch.cuda.FloatTensor'``。
|
|
122
|
+
|
|
123
|
+
注意:无 torch 时 ``torch.Tensor`` 只是一个占位桩(object),此时 numpy
|
|
124
|
+
数组不该被当成 Tensor,故先用 ``not isinstance(x, (np.ndarray, ...))``
|
|
125
|
+
兜底,保证纯 numpy 输入永远返回 False(即开启 pin_memory)。
|
|
126
|
+
"""
|
|
127
|
+
if isinstance(x, np.ndarray):
|
|
128
|
+
return False
|
|
129
|
+
try:
|
|
130
|
+
return isinstance(x, torch.Tensor) and x.device.type != "cpu"
|
|
131
|
+
except Exception:
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _want_pin_memory(X: Array, z: Array) -> bool:
|
|
136
|
+
"""输入全在 CPU 时开启 pin_memory 加速;任一在 GPU 则关闭。
|
|
137
|
+
|
|
138
|
+
numpy 输入一律视为 CPU 数据,走加速路径;只有在 torch 可用且输入
|
|
139
|
+
device 为 cuda 时才关闭。
|
|
140
|
+
"""
|
|
141
|
+
if isinstance(X, np.ndarray) and isinstance(z, np.ndarray):
|
|
142
|
+
return True
|
|
143
|
+
return not (_is_cuda_array(X) or _is_cuda_array(z))
|
|
144
|
+
|
|
145
|
+
|
|
56
146
|
# ----------------------------------------------------------------------
|
|
57
147
|
# 1. Conditional modulation & transformer blocks
|
|
58
148
|
# ----------------------------------------------------------------------
|
|
@@ -244,6 +334,11 @@ class GeneFlowDecoder(nn.Module):
|
|
|
244
334
|
device: str = "auto",
|
|
245
335
|
):
|
|
246
336
|
super().__init__()
|
|
337
|
+
if not _TORCH_AVAILABLE:
|
|
338
|
+
raise RuntimeError(
|
|
339
|
+
"GeneFlowDecoder requires PyTorch, but it could not be imported. "
|
|
340
|
+
"Install it with: pip install 'torch>=2.1'"
|
|
341
|
+
)
|
|
247
342
|
if device == "auto":
|
|
248
343
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
249
344
|
self.device = torch.device(device)
|
|
@@ -398,13 +493,20 @@ class GeneFlowDecoder(nn.Module):
|
|
|
398
493
|
X = _as_tensor(X, self.device)
|
|
399
494
|
z = self._maybe_detach(_as_tensor(z, self.device), snapshot=True)
|
|
400
495
|
|
|
496
|
+
# pin_memory 要求 CPU tensor;若 X/z 已在 GPU(常见于 scVI / mudata
|
|
497
|
+
# 把 .X 或 obsm 留在 cuda 的情况),强制关闭,避免
|
|
498
|
+
# RuntimeError: cannot pin 'torch.cuda.FloatTensor'
|
|
499
|
+
# 注:_as_tensor 对 cuda 输入原样返回,因此这里 X/z 仍在 GPU。
|
|
500
|
+
pin_memory = _want_pin_memory(X, z)
|
|
501
|
+
assert X.device.type == "cpu" or z.device.type == "cpu" or not pin_memory
|
|
502
|
+
|
|
401
503
|
ds = torch.utils.data.TensorDataset(X, z)
|
|
402
504
|
dl = torch.utils.data.DataLoader(
|
|
403
505
|
ds,
|
|
404
506
|
batch_size=int(batch_size),
|
|
405
507
|
shuffle=True,
|
|
406
508
|
num_workers=int(num_workers),
|
|
407
|
-
pin_memory=
|
|
509
|
+
pin_memory=pin_memory,
|
|
408
510
|
)
|
|
409
511
|
|
|
410
512
|
has_val = False
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geneflowdecoder-0.1.0 → geneflowdecoder-0.1.2}/src/geneflowdecoder.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|