zipoop 0.2.0__tar.gz → 0.2.1__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.
- {zipoop-0.2.0/zipoop.egg-info → zipoop-0.2.1}/PKG-INFO +3 -1
- {zipoop-0.2.0 → zipoop-0.2.1}/README.md +2 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/pyproject.toml +1 -1
- zipoop-0.2.1/tests/test_eval_subwindow.py +67 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/__init__.py +3 -3
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/evaluation.py +53 -0
- {zipoop-0.2.0 → zipoop-0.2.1/zipoop.egg-info}/PKG-INFO +3 -1
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop.egg-info/SOURCES.txt +1 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/LICENSE +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/setup.cfg +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/tests/test_v4_format.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/tests/test_zipoop.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/cli.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/data/encode-panel_1885.json +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/dataset.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/decoder.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/masks.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/network.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/panel.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/shard.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop/teacher.py +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop.egg-info/dependency_links.txt +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop.egg-info/entry_points.txt +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop.egg-info/requires.txt +0 -0
- {zipoop-0.2.0 → zipoop-0.2.1}/zipoop.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipoop
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Decoder and reader for Zipoop teacher shards (per-window neural compression of ENCODE signal tracks), v3 and v4 archives
|
|
5
5
|
Author: zatumout
|
|
6
6
|
License-Expression: MIT
|
|
@@ -48,6 +48,8 @@ zipoop show /path/to/weights_npz chr21_10027008_10059776
|
|
|
48
48
|
|
|
49
49
|
Lower level: `Dataset.read(window)` gives the parsed `Shard`, `Decoder(shard).decode(start, end, tracks)` decodes any slice or track subset. Evaluation helpers (`window_pearson`, `summarize`, `calibrate`, `restore_real`) are in `zipoop.evaluation`.
|
|
50
50
|
|
|
51
|
+
`zipoop.evaluation.subwindow_metrics(pred, target, valid, subwindow=32768)` is the evaluator frozen in the D5 pipeline: it splits the length axis into contiguous sub-windows (4 x 32,768 bp inside a 131,072 bp segment) and returns `pearson` / `proj` / `nmse` / `total_err` / `eligible` arrays of shape (sub-windows, tracks), with the same clamps and the same eligibility rule (at least 2 observed positions and a non-constant target). The aggregation used by the frozen pipeline is the mean Pearson over eligible pairs and the median `proj` / `nmse`.
|
|
52
|
+
|
|
51
53
|
Rules baked into `load_window` (see `zipoop/teacher.py`): RNA-seq tracks are 0 and valid where unrecorded; other tracks stay missing there. Opening a chromosome file parses its whole zip directory (chr1 about 3.6 s and 0.9 GB), so keep the `Dataset` open; forked DataLoader workers reopen their own handles.
|
|
52
54
|
|
|
53
55
|
## Supported formats
|
|
@@ -28,6 +28,8 @@ zipoop show /path/to/weights_npz chr21_10027008_10059776
|
|
|
28
28
|
|
|
29
29
|
Lower level: `Dataset.read(window)` gives the parsed `Shard`, `Decoder(shard).decode(start, end, tracks)` decodes any slice or track subset. Evaluation helpers (`window_pearson`, `summarize`, `calibrate`, `restore_real`) are in `zipoop.evaluation`.
|
|
30
30
|
|
|
31
|
+
`zipoop.evaluation.subwindow_metrics(pred, target, valid, subwindow=32768)` is the evaluator frozen in the D5 pipeline: it splits the length axis into contiguous sub-windows (4 x 32,768 bp inside a 131,072 bp segment) and returns `pearson` / `proj` / `nmse` / `total_err` / `eligible` arrays of shape (sub-windows, tracks), with the same clamps and the same eligibility rule (at least 2 observed positions and a non-constant target). The aggregation used by the frozen pipeline is the mean Pearson over eligible pairs and the median `proj` / `nmse`.
|
|
32
|
+
|
|
31
33
|
Rules baked into `load_window` (see `zipoop/teacher.py`): RNA-seq tracks are 0 and valid where unrecorded; other tracks stay missing there. Opening a chromosome file parses its whole zip directory (chr1 about 3.6 s and 0.9 GB), so keep the `Dataset` open; forked DataLoader workers reopen their own handles.
|
|
32
34
|
|
|
33
35
|
## Supported formats
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "zipoop"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Decoder and reader for Zipoop teacher shards (per-window neural compression of ENCODE signal tracks), v3 and v4 archives"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Parity tests for zipoop.evaluation.subwindow_metrics against the frozen D5 evaluator."""
|
|
2
|
+
import numpy as np
|
|
3
|
+
import torch
|
|
4
|
+
|
|
5
|
+
from zipoop.evaluation import subwindow_metrics
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def frozen_subwindow_metrics(p, y, m, N, W):
|
|
9
|
+
"""Verbatim copy of the evaluator frozen in zipoop_32k1885_010_128k2rd_D5_frozen_20261017/d5_genome.py."""
|
|
10
|
+
out = {k: [] for k in ("pearson", "proj", "nmse", "total_err", "eligible")}
|
|
11
|
+
for k in range(N):
|
|
12
|
+
s = slice(k * W, (k + 1) * W)
|
|
13
|
+
mf = m[s].float(); n = mf.sum(0).clamp_min(1)
|
|
14
|
+
yc = (y[s] - (y[s] * mf).sum(0) / n) * mf; pc = (p[s] - (p[s] * mf).sum(0) / n) * mf
|
|
15
|
+
vy = yc.square().sum(0); yy = (y[s].square() * mf).sum(0)
|
|
16
|
+
out["pearson"].append((pc * yc).sum(0) / (pc.square().sum(0) * vy).clamp_min(1e-24).sqrt())
|
|
17
|
+
out["proj"].append((p[s] * y[s] * mf).sum(0) / yy.clamp_min(1e-30))
|
|
18
|
+
out["nmse"].append(((p[s] - y[s]).square() * mf).sum(0) / yy.clamp_min(1e-30))
|
|
19
|
+
out["total_err"].append(((p[s] * mf).sum(0) - (y[s] * mf).sum(0)).abs() / (y[s] * mf).sum(0).abs().clamp_min(1e-30))
|
|
20
|
+
out["eligible"].append((n >= 2) & (vy > 1e-12))
|
|
21
|
+
return {k: torch.stack(v).cpu().numpy() for k, v in out.items()}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_matches_frozen_evaluator():
|
|
25
|
+
torch.manual_seed(0)
|
|
26
|
+
L, T, W, N = 4 * 256, 7, 256, 4
|
|
27
|
+
target = torch.randn(L, T)
|
|
28
|
+
pred = target * 0.9 + torch.randn(L, T) * 0.3
|
|
29
|
+
valid = torch.rand(L, T) > 0.2
|
|
30
|
+
valid[:W] = False # first sub-window has no observations
|
|
31
|
+
target[:, 3] = 1.0 # a constant track must be ineligible
|
|
32
|
+
|
|
33
|
+
want = frozen_subwindow_metrics(pred, target, valid, N, W)
|
|
34
|
+
got = subwindow_metrics(pred, target, valid, subwindow=W)
|
|
35
|
+
|
|
36
|
+
assert set(want) == set(got)
|
|
37
|
+
for k in want:
|
|
38
|
+
assert got[k].shape == (N, T), (k, got[k].shape)
|
|
39
|
+
assert np.array_equal(got[k], want[k]) if got[k].dtype == bool else np.allclose(got[k], want[k], rtol=0, atol=0), k
|
|
40
|
+
assert not got["eligible"][0].any()
|
|
41
|
+
assert not got["eligible"][:, 3].any()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_identity_prediction():
|
|
45
|
+
torch.manual_seed(1)
|
|
46
|
+
L, T, W = 2 * 128, 5, 128
|
|
47
|
+
target = torch.randn(L, T)
|
|
48
|
+
valid = torch.ones(L, T, dtype=torch.bool)
|
|
49
|
+
m = subwindow_metrics(target.clone(), target, valid, subwindow=W)
|
|
50
|
+
assert np.allclose(m["pearson"], 1.0)
|
|
51
|
+
assert np.allclose(m["proj"], 1.0)
|
|
52
|
+
assert np.allclose(m["nmse"], 0.0)
|
|
53
|
+
assert np.allclose(m["total_err"], 0.0)
|
|
54
|
+
assert m["eligible"].all()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_accepts_numpy_and_validates_shape():
|
|
58
|
+
t = np.random.RandomState(0).randn(2 * 64, 3).astype(np.float32)
|
|
59
|
+
v = np.ones_like(t, dtype=bool)
|
|
60
|
+
m = subwindow_metrics(t, t, v, subwindow=64)
|
|
61
|
+
assert m["pearson"].shape == (2, 3)
|
|
62
|
+
try:
|
|
63
|
+
subwindow_metrics(t, t[:100], v, subwindow=64)
|
|
64
|
+
except ValueError:
|
|
65
|
+
pass
|
|
66
|
+
else:
|
|
67
|
+
raise AssertionError("shape mismatch must raise")
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Zipoop: decoder and reader for the per-window teacher shards (merged per-chromosome npz)."""
|
|
2
2
|
from .dataset import Dataset, verify
|
|
3
3
|
from .decoder import Decoder
|
|
4
|
-
from .evaluation import calibrate, restore_real, summarize, window_pearson
|
|
4
|
+
from .evaluation import calibrate, restore_real, subwindow_metrics, summarize, window_pearson
|
|
5
5
|
from .panel import panel_tracks, zero_tracks
|
|
6
6
|
from .shard import Shard, read_shard
|
|
7
7
|
from .teacher import TeacherWindow, load_window
|
|
8
8
|
|
|
9
|
-
__version__ = "0.2.
|
|
9
|
+
__version__ = "0.2.1"
|
|
10
10
|
__all__ = ["Dataset", "verify", "Decoder", "Shard", "read_shard", "TeacherWindow", "load_window",
|
|
11
|
-
"panel_tracks", "zero_tracks", "calibrate", "restore_real", "summarize", "window_pearson"]
|
|
11
|
+
"panel_tracks", "zero_tracks", "calibrate", "restore_real", "subwindow_metrics", "summarize", "window_pearson"]
|
|
@@ -61,6 +61,59 @@ def window_pearson(pred, target, valid, window=WINDOW, chunk=256):
|
|
|
61
61
|
return torch.cat(cols, 1)
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
def subwindow_metrics(pred, target, valid, subwindow=WINDOW):
|
|
65
|
+
"""Per (sub-window, track) metrics, the convention of the frozen D5 evaluator.
|
|
66
|
+
|
|
67
|
+
``pred`` and ``target`` are (L, T) signals, ``valid`` the (L, T) observed-position mask; the length
|
|
68
|
+
axis is split into ``L // subwindow`` contiguous blocks (the D5 pipeline uses 4 x 32,768 bp inside a
|
|
69
|
+
131,072 bp segment). Returns a dict of numpy arrays with shape (sub-windows, tracks):
|
|
70
|
+
|
|
71
|
+
``pearson`` masked 1 bp Pearson
|
|
72
|
+
``proj`` projection ratio sum(pred * target) / sum(target ** 2)
|
|
73
|
+
``nmse`` sum((pred - target) ** 2) / sum(target ** 2)
|
|
74
|
+
``total_err`` |sum(pred) - sum(target)| / |sum(target)|
|
|
75
|
+
``eligible`` at least 2 observed positions and a non-constant target inside that sub-window
|
|
76
|
+
|
|
77
|
+
The percentages and clamps (1e-24, 1e-30) are the frozen evaluator's, unchanged.
|
|
78
|
+
"""
|
|
79
|
+
if torch.is_tensor(pred):
|
|
80
|
+
pred = pred.detach()
|
|
81
|
+
else:
|
|
82
|
+
pred = torch.as_tensor(np.asarray(pred))
|
|
83
|
+
if torch.is_tensor(target):
|
|
84
|
+
target = target.detach()
|
|
85
|
+
else:
|
|
86
|
+
target = torch.as_tensor(np.asarray(target))
|
|
87
|
+
if torch.is_tensor(valid):
|
|
88
|
+
valid = valid.detach()
|
|
89
|
+
else:
|
|
90
|
+
valid = torch.as_tensor(np.asarray(valid))
|
|
91
|
+
if pred.shape != target.shape or pred.shape != valid.shape:
|
|
92
|
+
raise ValueError(f"shape mismatch: pred {tuple(pred.shape)}, target {tuple(target.shape)}, valid {tuple(valid.shape)}")
|
|
93
|
+
length, tracks = target.shape
|
|
94
|
+
if not 0 < subwindow <= length or length % subwindow:
|
|
95
|
+
raise ValueError(f"length {length} is not a multiple of subwindow {subwindow}")
|
|
96
|
+
|
|
97
|
+
pred = pred.float()
|
|
98
|
+
target = target.float()
|
|
99
|
+
out = {k: [] for k in ("pearson", "proj", "nmse", "total_err", "eligible")}
|
|
100
|
+
for k in range(length // subwindow):
|
|
101
|
+
s = slice(k * subwindow, (k + 1) * subwindow)
|
|
102
|
+
mf = valid[s].float()
|
|
103
|
+
n = mf.sum(0).clamp_min(1)
|
|
104
|
+
yc = (target[s] - (target[s] * mf).sum(0) / n) * mf
|
|
105
|
+
pc = (pred[s] - (pred[s] * mf).sum(0) / n) * mf
|
|
106
|
+
vy = yc.square().sum(0)
|
|
107
|
+
yy = (target[s].square() * mf).sum(0)
|
|
108
|
+
out["pearson"].append((pc * yc).sum(0) / (pc.square().sum(0) * vy).clamp_min(1e-24).sqrt())
|
|
109
|
+
out["proj"].append((pred[s] * target[s] * mf).sum(0) / yy.clamp_min(1e-30))
|
|
110
|
+
out["nmse"].append(((pred[s] - target[s]).square() * mf).sum(0) / yy.clamp_min(1e-30))
|
|
111
|
+
out["total_err"].append(((pred[s] * mf).sum(0) - (target[s] * mf).sum(0)).abs()
|
|
112
|
+
/ (target[s] * mf).sum(0).abs().clamp_min(1e-30))
|
|
113
|
+
out["eligible"].append((n >= 2) & (vy > 1e-12))
|
|
114
|
+
return {k: torch.stack(v).cpu().numpy() for k, v in out.items()}
|
|
115
|
+
|
|
116
|
+
|
|
64
117
|
def summarize(p, tracks=None):
|
|
65
118
|
"""Mean/median over evaluable pairs, plus per-modality and per-window means."""
|
|
66
119
|
tracks = panel_tracks() if tracks is None else tracks
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipoop
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Decoder and reader for Zipoop teacher shards (per-window neural compression of ENCODE signal tracks), v3 and v4 archives
|
|
5
5
|
Author: zatumout
|
|
6
6
|
License-Expression: MIT
|
|
@@ -48,6 +48,8 @@ zipoop show /path/to/weights_npz chr21_10027008_10059776
|
|
|
48
48
|
|
|
49
49
|
Lower level: `Dataset.read(window)` gives the parsed `Shard`, `Decoder(shard).decode(start, end, tracks)` decodes any slice or track subset. Evaluation helpers (`window_pearson`, `summarize`, `calibrate`, `restore_real`) are in `zipoop.evaluation`.
|
|
50
50
|
|
|
51
|
+
`zipoop.evaluation.subwindow_metrics(pred, target, valid, subwindow=32768)` is the evaluator frozen in the D5 pipeline: it splits the length axis into contiguous sub-windows (4 x 32,768 bp inside a 131,072 bp segment) and returns `pearson` / `proj` / `nmse` / `total_err` / `eligible` arrays of shape (sub-windows, tracks), with the same clamps and the same eligibility rule (at least 2 observed positions and a non-constant target). The aggregation used by the frozen pipeline is the mean Pearson over eligible pairs and the median `proj` / `nmse`.
|
|
52
|
+
|
|
51
53
|
Rules baked into `load_window` (see `zipoop/teacher.py`): RNA-seq tracks are 0 and valid where unrecorded; other tracks stay missing there. Opening a chromosome file parses its whole zip directory (chr1 about 3.6 s and 0.9 GB), so keep the `Dataset` open; forked DataLoader workers reopen their own handles.
|
|
52
54
|
|
|
53
55
|
## Supported formats
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|