EM-R50 (Synaptic Polarity Detection)¶
A synapse is an essential structure that allows electric or chemical signals to be passed between neurons. Identification of synapses is important for reconstructing the wiring diagram of the brain. Signal flows in one direction at a synapse, so each synapse usually consists of a pre-synaptic and a post-synaptic region.
This section covers two benchmarks:
CREMI — synaptic cleft detection on the CREMI Challenge dataset (adult Drosophila melanogaster brain tissue, 2016).
EM-R50 — synaptic polarity detection on the dataset released by Lin et al. in 2020 (Layer II/III primary visual cortex of an adult rat). This predicts pre-synaptic and post-synaptic masks separately.
This tutorial covers synaptic polarity detection — predicting separated pre-synaptic and post-synaptic masks so the signal flow between neurons can be traced. The dataset was released by Lin et al. (2020) from Layer II/III of the primary visual cortex of an adult rat.
Unlike the cleft-detection task, polarity detection requires distinguishing individual synapses and assigning a side (pre / post) to each. The model outputs three channels — pre-synaptic, post-synaptic, and synaptic (union) — and a connected-components post-processor groups them into per-synapse instances.
Note
A dedicated EM-R50 tutorial config does not yet ship under
tutorials/in the modern (v2/v3) PyTC layout. The decoder and target-generation building blocks are present (polarity2instancedecoder;seg_to_polaritytarget), but a canonical end-to-end YAML is a follow-up. The recipe below shows how to assemble one from the existing CREMI cleft-detection config (tutorials/syn_cremi.yaml) plus the polarity-specific pieces.
Goal¶
The intended pipeline:
Model output 3 channels — pre-synaptic, post-synaptic, and synaptic-union.
Target generation
seg_to_polarityover instance labels; setexclusive=trueif pre / post should never overlap (uses softmax) orfalsefor the standard non-exclusive BCE setup (channels predicted independently with sigmoid).Loss
WeightedBCEWithLogitsLosswith rejection sampling on the foreground (synapses are sparse), orWeightedCEfor the exclusive variant.Decoder
polarity2instance— connected-components on the synaptic-union channel, then voting on pre / post per instance.Metric an IoU-based F1 score on instance-matched pairs.
1 - Get the data¶
mkdir -p datasets/jwr15 && cd datasets/jwr15
wget http://rhoana.rc.fas.harvard.edu/dataset/jwr15_synapse.zip
unzip jwr15_synapse.zip
2 - Building a v2 config (template)¶
Start from tutorials/syn_cremi.yaml and apply three changes:
(a) Switch the model output to 3 channels and use a non-exclusive
BCE loss (or WeightedCE if you prefer exclusive masks):
default:
model:
out_channels: 3
loss:
losses:
- function: WeightedBCEWithLogitsLoss
weight: 1.0
kwargs: {reduction: mean}
pred_slice: "0:3"
target_slice: "0:3"
(b) Drive target generation through the polarity helper. In your
data.label_transform block, generate the 3-channel polarity
target from instance labels by post-processing your label volume
through connectomics.data.processing.target.seg_to_polarity
(invoke from a small data-preparation script ahead of training, or
add it as a custom processing step). Disable the cleft binary path
that ships in syn_cremi.yaml.
Add the polarity decoder under
decoding.steps:
decoding:
steps:
- name: polarity2instance
kwargs:
# default: non-exclusive (independent BCE channels);
# set true if you trained with WeightedCE / softmax.
exclusive: false
The rest of the CREMI config (RSUNet, anisotropic 18 × 256 × 256 patches, sliding-window inference, EMA, augmentation profile) carries over.
Tip
Synapses are sparse, so add rejection sampling to focus training on patches that contain foreground:
data: dataloader: reject_sampling: size_thres: 1000 p: 0.95This is what
syn_cremi.yamlalready does for cleft detection; keep it for polarity training.
3 - Run training¶
Once your config is assembled (e.g. saved as
tutorials/syn_em_r50.yaml):
conda activate pytc
python scripts/main.py --config tutorials/syn_em_r50.yaml
4 - Inference, decoding, evaluation¶
python scripts/main.py --config tutorials/syn_em_r50.yaml \
--mode test \
--checkpoint outputs/<exp>/<timestamp>/checkpoints/last.ckpt
The decoding stage runs polarity2instance, which converts the
3-channel probability map into per-synapse instance masks with a
recorded side (pre vs. post). For programmatic use:
from connectomics.decoding import polarity2instance
# volume: (3, D, H, W) prediction, channels = [pre, post, syn]
instances = polarity2instance(volume)
The exclusive=True variant interprets the channels as a softmax
output over {background, pre, post} and uses a different connected-
component path; pass exclusive=True to polarity2instance if
your model was trained with WeightedCE.
5 - Reference behavior¶
Training loss is dominated by the synaptic-union channel early on; the pre / post channels improve as the model learns spatial directionality, typically after the first cosine decay phase. Rejection sampling plus higher foreground weights is essential — without it, pre and post collapse to all-zeros.
Inference is identical to the CREMI flow (same RSUNet, same sliding window). The decoder runs in CPU and is fast.
Reporting the published EM-R50 F1 is computed against the Lin et al. 2020 evaluation script. Comparable code lives in the upstream paper repo; contact the maintainers if you intend to benchmark formally.