Skip to content

Commit ab441bc

Browse files
anna-grimAnna Grimclaude
authored
Cleanup unused code (#791)
* fix: forward use_anisotropy through ProposalGraph and the pipeline ProposalGraph.__init__ accepted use_anisotropy via **kwargs but never passed it to FragmentsGraph, and ProofreadPipeline.load_graph did not forward GraphConfig.use_anisotropy either. The flag was therefore silently ignored and SWC coordinates were always scaled by the anisotropy on load, which is wrong for SWCs already in world coordinates such as pipeline outputs. Callers reading voxel-space SWCs must now pass use_anisotropy=True (the default) explicitly in their GraphConfig to keep scaling. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: sparse search progress bar counted unsearched fragments SparseSearchDataset.estimate_iterations returned every branching node in the graph, but the dataset only visits fragments longer than min_search_size. The tqdm total was therefore inflated (45k vs 28k visited on one whole-brain graph) and the ETA pessimistic. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor: deduplicate Dense/Sparse search datasets Move patch-loader construction, search_mode, and default step_size into class attributes handled by SearchDataset.__init__, and define the patch + rooted-subgraph input once as get_patch_and_subgraph (renamed from get_patch_and_arborist). The base class now defaults prefetch to 64. Co-Authored-By: Claude <noreply@anthropic.com> * refactor: drop superseded models, split io_util out of util, add DatasetConfig - Remove the old vision_models.py and gnn_models.py and promote new_vision_models.py / new_gnn_models.py to those names. - Move file, zip, GCS and S3 I/O from utils/util.py into utils/io_util.py and update callers. - Add DatasetConfig (brain_id, segmentation_id, img_path, fragments_path) and give ProposalsConfig a name so every config can be saved. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Anna Grim <anna.grim@alleninstitute.org> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent c9f1956 commit ab441bc

18 files changed

Lines changed: 1527 additions & 2219 deletions

‎src/neuron_proofreader/configs.py‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from neuron_proofreader.machine_learning.image_augmentation import (
1919
ImageTransforms,
2020
)
21-
from neuron_proofreader.utils import util
21+
from neuron_proofreader.utils import io_util
2222

2323

2424
class Config(ABC):
@@ -52,7 +52,31 @@ def save(self, output_dir):
5252
Path to directory to save JSON file.
5353
"""
5454
path = os.path.join(output_dir, f"{self.name}.json")
55-
util.write_json(path, self.to_dict())
55+
io_util.write_json(path, self.to_dict())
56+
57+
58+
@dataclass
59+
class DatasetConfig(Config):
60+
"""
61+
Configuration class for the dataset that is proofread.
62+
63+
Attributes
64+
----------
65+
brain_id : str
66+
Unique identifier of the whole-brain dataset.
67+
fragments_path : str
68+
Path to the directory (local or cloud) containing fragment SWC files.
69+
img_path : str
70+
Path to the whole-brain image.
71+
segmentation_id : str
72+
Unique identifier of the segmentation that fragments come from.
73+
"""
74+
75+
brain_id: str = None
76+
fragments_path: str = None
77+
img_path: str = None
78+
name: str = "dataset_config"
79+
segmentation_id: str = None
5680

5781

5882
@dataclass
@@ -237,6 +261,7 @@ class ProposalsConfig(Config):
237261
allow_nonleaf_proposals: bool = False
238262
max_proposals_per_leaf: int = 3
239263
min_size_with_proposals: float = 0
264+
name: str = "proposals_config"
240265
trim_endpoints_bool: bool = True
241266
search_radius: float = 25
242267
search_scaling_factor: float = 1.5

‎src/neuron_proofreader/fragments_graph.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from arborist.skeleton_graph import SkeletonGraph
1717
from arborist.utils.graph_loading import GraphLoader
18-
from neuron_proofreader.utils import geometry_util, img_util, util
18+
from neuron_proofreader.utils import geometry_util, img_util, io_util
1919

2020

2121
class FragmentsGraph(SkeletonGraph):
@@ -226,8 +226,8 @@ def clip_to_bbox(self, metadata_path):
226226
"""
227227
Clips skeletons to the bounding box defined in a metadata JSON file.
228228
"""
229-
if util.check_gcs_file_exists(metadata_path):
230-
metadata = util.read_json(metadata_path)
229+
if io_util.check_gcs_file_exists(metadata_path):
230+
metadata = io_util.read_json(metadata_path)
231231
origin = metadata["chunk_origin"][::-1]
232232
shape = metadata["chunk_shape"][::-1]
233233
nodes = list()

‎src/neuron_proofreader/machine_learning/image_dataloader.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from neuron_proofreader.machine_learning.image_augmentation import (
1818
ImageTransforms,
1919
)
20-
from neuron_proofreader.utils import geometry_util, img_util, util
20+
from neuron_proofreader.utils import geometry_util, img_util, io_util
2121

2222

2323
class TensorStoreImage:
@@ -56,7 +56,7 @@ def __init__(self, img_path):
5656
Path to image.
5757
"""
5858
# Load image
59-
bucket_name, inner_path = util.parse_cloud_path(img_path)
59+
bucket_name, inner_path = io_util.parse_cloud_path(img_path)
6060
self.img_path = img_path
6161
self.img = ts.open(
6262
{

‎src/neuron_proofreader/machine_learning/train.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import torch.nn as nn
2727
import torch.optim as optim
2828

29-
from neuron_proofreader.utils import img_util, ml_util, util
29+
from neuron_proofreader.utils import img_util, io_util, ml_util
3030

3131

3232
class Trainer:
@@ -115,7 +115,7 @@ def __init__(
115115
if exp_name is None:
116116
exp_name = "session-" + datetime.today().strftime("%Y%m%d_%H%M")
117117
log_dir = os.path.join(output_dir, exp_name)
118-
util.mkdir(log_dir)
118+
io_util.mkdir(log_dir)
119119

120120
# Instance attributes
121121
self.best_f1 = 0
@@ -206,7 +206,7 @@ def _run_epoch(self, dataloader, epoch, train):
206206
else:
207207
self.model.eval()
208208
if self.n_mips > 0:
209-
util.mkdir(self.mips_dir, True)
209+
io_util.mkdir(self.mips_dir, True)
210210
n = len(dataloader.dataset)
211211
self._mip_idxs = set(random.sample(range(n), min(self.n_mips, n)))
212212
if self.n_mistake_mips > 0:
@@ -387,7 +387,7 @@ def _flush_mistake_mips(self, epoch):
387387
Saves the buffered mistake MIPs for this epoch to disk.
388388
"""
389389
epoch_dir = os.path.join(self.mistake_mips_dir, f"epoch_{epoch:03d}")
390-
util.mkdir(epoch_dir)
390+
io_util.mkdir(epoch_dir)
391391
for i, (img, outcome) in enumerate(self._mistake_buf):
392392
path = os.path.join(epoch_dir, f"{outcome}_{i:02d}.png")
393393
img_util.plot_image_and_segmentation_mips(img[0], 2 * img[1], path)

‎src/neuron_proofreader/merge_proofreading/merge_datamodules.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from neuron_proofreader.fragments_graph import FragmentsGraph
4242
from arborist.data.augmentation import GraphTransforms
4343
from arborist.utils.swc_loading import Reader
44-
from neuron_proofreader.utils import ml_util, util
44+
from neuron_proofreader.utils import io_util, ml_util, util
4545
from neuron_proofreader.utils.graph_util import subgraph_to_tree_sample
4646

4747

@@ -407,7 +407,7 @@ def save_config(self, path):
407407
}
408408
for bd in self.datasets
409409
]
410-
util.write_json(path, config)
410+
io_util.write_json(path, config)
411411

412412
# --- Dataset Interface ---
413413
def __len__(self):
@@ -704,8 +704,8 @@ def create_dataset_collection(
704704
img_config.set_val_mode()
705705

706706
# Load image prefixes
707-
bucket, root_prefix = util.parse_cloud_path(sites_root_path)
708-
img_prefixes = util.read_json(img_prefixes_path)
707+
bucket, root_prefix = io_util.parse_cloud_path(sites_root_path)
708+
img_prefixes = io_util.read_json(img_prefixes_path)
709709

710710
# Iterate over brains
711711
datasets = list()
@@ -750,6 +750,6 @@ def create_dataset_collection(
750750

751751
def get_segmentation_id(sites_path, brain_id):
752752
brain_sites_path = os.path.join(sites_path, brain_id)
753-
subprefixes = util.list_gcs_subprefixes(brain_sites_path)
753+
subprefixes = io_util.list_gcs_subprefixes(brain_sites_path)
754754
assert len(subprefixes) == 1
755755
return subprefixes[0].split("/")[-2]

‎src/neuron_proofreader/merge_proofreading/merge_inference.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
SparseSearchDataset,
4040
multimodal_collate,
4141
)
42-
from neuron_proofreader.utils import img_util, util
42+
from neuron_proofreader.utils import img_util, io_util, util
4343

4444

4545
class MergeProofreader(ABC):
@@ -372,7 +372,7 @@ def save_parameters(self):
372372
"search_mode": self.dataset.search_mode,
373373
"subgraph_radius": self.dataset.subgraph_radius,
374374
}
375-
util.write_json(json_path, parameters)
375+
io_util.write_json(json_path, parameters)
376376

377377
def save_predictions(self):
378378
nodes = np.array(self.visited_sites, dtype=int)

‎src/neuron_proofreader/merge_proofreading/search_datasets.py‎

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
def multimodal_collate(batch):
3333
"""
3434
Collate a batch of (node, img_patch, tree_sample) tuples produced by
35-
get_patch_and_arborist.
35+
get_patch_and_subgraph.
3636
3737
Returns
3838
-------
@@ -48,13 +48,18 @@ def multimodal_collate(batch):
4848
# --- Datasets ---
4949
class SearchDataset(IterableDataset, ABC):
5050

51+
search_mode = None
52+
patch_loader_cls = None
53+
default_step_size = None
54+
5155
def __init__(
5256
self,
5357
graph,
5458
img_config,
5559
modality="image",
5660
min_search_size=0,
57-
prefetch=32,
61+
prefetch=64,
62+
step_size=None,
5863
subgraph_radius=100,
5964
):
6065
# Call parent class
@@ -64,13 +69,15 @@ def __init__(
6469
self.graph = graph
6570
self.modality = modality
6671
self.min_size = min_search_size
72+
self.patch_loader = self.patch_loader_cls(graph, img_config)
6773
self.patch_shape = img_config.patch_shape
6874
self.prefetch = prefetch
75+
self.step_size = step_size or self.default_step_size
6976
self.subgraph_radius = subgraph_radius
7077

7178
# Input getter
7279
if modality != "image":
73-
self.get_input = self.get_patch_and_arborist
80+
self.get_input = self.get_patch_and_subgraph
7481
else:
7582
self.get_input = self.get_patch
7683
self.collate_fn = multimodal_collate if modality != "image" else None
@@ -136,6 +143,11 @@ def generate_component_sites(self, root):
136143
"""
137144
pass
138145

146+
def get_patch_and_subgraph(self, *args):
147+
for node, patch in self.get_patch(*args):
148+
subgraph = self.graph.rooted_subgraph(node, self.subgraph_radius)
149+
yield node, patch, subgraph_to_tree_sample(subgraph, 0)
150+
139151
# --- Helpers ---
140152
def __getattr__(self, name):
141153
return getattr(self.graph, name)
@@ -214,31 +226,9 @@ def _is_near_leaf_slow(self, node, threshold=32):
214226
class DenseSearchDataset(SearchDataset):
215227

216228
max_batch_span = 512
217-
218-
def __init__(
219-
self,
220-
graph,
221-
img_config,
222-
modality="image",
223-
min_search_size=0,
224-
prefetch=64,
225-
step_size=40,
226-
subgraph_radius=100,
227-
):
228-
# Call parent class
229-
super().__init__(
230-
graph,
231-
img_config,
232-
modality=modality,
233-
min_search_size=min_search_size,
234-
prefetch=prefetch,
235-
subgraph_radius=subgraph_radius,
236-
)
237-
238-
# Instance attributes
239-
self.patch_loader = DetectionBatchLoader(self.graph, img_config)
240-
self.search_mode = "dense"
241-
self.step_size = step_size
229+
search_mode = "dense"
230+
patch_loader_cls = DetectionBatchLoader
231+
default_step_size = 40
242232

243233
def generate_component_sites(self, root):
244234
"""
@@ -289,16 +279,6 @@ def get_patch(self, nodes, img, offset):
289279
s = img_util.get_slices(center, self.patch_shape)
290280
yield node, img[(slice(0, 2), *s)]
291281

292-
def get_patch_and_arborist(self, nodes, img, offset):
293-
img = torch.from_numpy(img).float()
294-
voxels = np.array([self.node_voxel(i) for i in nodes], dtype=int)
295-
for node, center in zip(nodes, voxels - offset):
296-
s = img_util.get_slices(center, self.patch_shape)
297-
patch = img[(slice(0, 2), *s)]
298-
subgraph = self.graph.rooted_subgraph(node, self.subgraph_radius)
299-
tree_sample = subgraph_to_tree_sample(subgraph, 0)
300-
yield node, patch, tree_sample
301-
302282
# --- Helpers ---
303283
def estimate_iterations(self):
304284
"""
@@ -319,29 +299,9 @@ def estimate_iterations(self):
319299

320300
class SparseSearchDataset(SearchDataset):
321301

322-
def __init__(
323-
self,
324-
graph,
325-
img_config,
326-
modality="image",
327-
min_search_size=0,
328-
prefetch=64,
329-
step_size=10,
330-
subgraph_radius=100,
331-
):
332-
# Call parent class
333-
super().__init__(
334-
graph,
335-
img_config,
336-
modality=modality,
337-
min_search_size=min_search_size,
338-
prefetch=prefetch,
339-
subgraph_radius=subgraph_radius,
340-
)
341-
342-
# Instance attributes
343-
self.patch_loader = DetectionPatchLoader(self.graph, img_config)
344-
self.search_mode = "sparse"
302+
search_mode = "sparse"
303+
patch_loader_cls = DetectionPatchLoader
304+
default_step_size = 10
345305

346306
def estimate_iterations(self):
347307
# Only fragments above min_search_size are searched
@@ -358,9 +318,3 @@ def generate_component_sites(self, root):
358318

359319
def get_patch(self, node, img):
360320
yield node, torch.from_numpy(img).float()
361-
362-
def get_patch_and_arborist(self, node, img):
363-
patch = torch.from_numpy(img).float()
364-
subgraph = self.graph.rooted_subgraph(node, self.subgraph_radius)
365-
tree_sample = subgraph_to_tree_sample(subgraph, 0)
366-
yield node, patch, tree_sample

0 commit comments

Comments
 (0)