Repository navigation
GATv2 attention extraction + attention_by_group, tutorial section 3.1 - #40
Merged
Merged
Conversation
- GCNLayers.forward / GraphEncoder.forward: return_attention_weights flag (default path unchanged; non-GAT raises NotImplementedError). - Loader batches carry n_id; create_inference_loader takes a per-loader num_neighbors override (cached splitter never mutated). - CellinaGCNModule.get_attention: spatial-encoder-only pass with the same input as inference(). - CellinaGCN.get_attention_weights: exact per-layer (n_obs, n_obs) CSR, A[i, j] = alpha(j -> i), seed-only masking, duplicate / sampling checks. - CellinaGCN.attention_by_group: log2(attention share / neighbour share) per receiver x sender group. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
New markdown + heatmap cell using CellinaGCN.attention_by_group and a short read-out of the executed result. Whole notebook re-executed on GPU. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #40 +/- ##
==========================================
+ Coverage 90.10% 90.73% +0.63%
==========================================
Files 10 10
Lines 1394 1489 +95
==========================================
+ Hits 1256 1351 +95
Misses 138 138 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extracts the learned GATv2 attention coefficients from
CellinaGCNand summarises them by cell group. The rebuttal-branch design is re-applied to currentmainfrom scratch.API
CellinaGCN.get_attention_weights(adata=None, indices=None, batch_size=512, num_neighbors=None, key_added=None, allow_sampling=False) -> dict[int, csr_matrix](n_obs, n_obs)float32 CSR per GAT layer, keyed by 0-based layer index. Rows not inindicesare all-zero.[-1] * n_layers, and only edges into seed cells are kept (dst_local < batch_size). Each cell is a seed exactly once, so every edge is written exactly once, and annnz == entriescheck guards this.allow_sampling=True.num_neighborsmust have one entry per layer, andindicesmust be unique integers.key_addedwritesadata.obsp[f"{key_added}_l{i}"]. By defaultadatais never mutated.CellinaGCN.attention_by_group(groupby, layer=-1, normalize=True, **kwargs) -> DataFramelog2(mean attention share / mean neighbour share), averaged over receiver cells that have neighbours.normalize=Falsereturns the mean attention share instead, whose rows sum to 1.kwargsare forwarded toget_attention_weights. This reproduces the statistic in the rebuttal notebookapplication/05_analyse_attention.ipynb.CellinaGCNModule.get_attention(...)runs only the spatial encoder, with the same spatial input asinference():log1p(x_spatial)if given, elselog1p(x).GCNLayers.forwardandGraphEncoder.forwardgainreturn_attention_weights=False. The default path and return signatures are unchanged, and non-GAT convolutions raiseNotImplementedError.n_id.create_inference_loader/_make_neighbor_loaderaccept a per-loadernum_neighborsoverride. The cached splitter is never mutated.Orientation
A[i, j] = alpha(j -> i): the row is the destination (the attending cell) and the column is the source (its neighbour). Rows sum to 1 for cells that have neighbours. The splitter symmetrises the connectivity graph, so the sparsity pattern equals the connectivity pattern minus self-loops.Aitself is still asymmetric.Deliberately dropped relative to the rebuttal implementation
give_mean/condition_on_intrinsic/_build_spatial_input/z_encodercall inget_attention:mainhas nocondition_on_intrinsic, so the GCN input never depends onz. Extraction is deterministic without these, and the extra encoder pass would only cost time.mainsymmetrises the graph in the splitter, so the attention pattern equals the connectivity pattern and the caveat no longer applies.inference()rewrite:main'sinference()(count/library encoders on seed rows only) is left untouched.get_attentionmirrors its spatial input directly.Tests (
tests/test_cellina_gcn.py)key_addedbehaviour (no mutation by default).allow_sampling=True, and rejects a wrong-lengthnum_neighbors.indices: full shape is kept, rows match the full run, and duplicate / boolean indices are rejected.attention_by_group:normalize=Falserows sum to 1layer=-1==layer=n_layers-1Tutorial
docs/tutorial_gat.ipynbgains section 3.1 What the GAT attends to: one explanatory markdown cell, an enrichment heatmap, and a short read-out. The whole notebook was re-executed end to end on GPU with this branch.🤖 Generated with Claude Code