Add typed-channel PPR sampler - #709
Conversation
9724f59 to
81812c7
Compare
fc410ab to
2b85456
Compare
81812c7 to
41a65fd
Compare
2b85456 to
ecb394c
Compare
41a65fd to
b826832
Compare
0047b2f to
016517b
Compare
f6fc7a8 to
65d131c
Compare
016517b to
60a0cea
Compare
65d131c to
44307b8
Compare
ff2d3ea to
d0f9cea
Compare
4d70c04 to
a3751bd
Compare
33c8dde to
1b0ea2a
Compare
6fbb8c9 to
ce171bb
Compare
1b0ea2a to
ed7387c
Compare
ed7387c to
457c30b
Compare
ce171bb to
52fcfbd
Compare
2c09892 to
7b305fc
Compare
d2467d9 to
2b9ff1d
Compare
7b305fc to
b1487ff
Compare
2b9ff1d to
a105107
Compare
b1487ff to
b5b0bb0
Compare
a105107 to
98421e0
Compare
3e093f5 to
930569f
Compare
f2dcecb to
ebc7ac7
Compare
kmontemayor2-sc
left a comment
There was a problem hiding this comment.
Thanks Matt! Took a first pass here :)
| traversal channels defined by canonical edge-type allowlists. Keys | ||
| may be either a single canonical edge type | ||
| ``(src_type, relation, dst_type)`` or a tuple of canonical edge | ||
| types. Each key defines one traversal channel whose PPR state may |
There was a problem hiding this comment.
BTW any reason we chose the "typed channel" moniker vs "meta path" which I think I've seen to describe this "sequence of edge types" elsewhere?
There was a problem hiding this comment.
A meta path implies an ordered sequence of edge types usually to my understanding. In this case, the channels don't necessarily have an ordering -- they are just edges that we are permitted to traverse across for that forward push operation. As a result I've named them differently here.
| Quotas may sum above ``max_ppr_nodes`` to give sparse or | ||
| overlapping channels room to fill the sequence. |
There was a problem hiding this comment.
Sorry what does this mean? Can we give examples?
There was a problem hiding this comment.
Added examples, this is saying quotas are candidate budgets, not guaranteed output counts. A channel may find fewer candidates than its quota, and multiple channels may find the same node, so the merged/deduped result can be smaller than the sum of quotas. We still cap final output at max_ppr_nodes, but allowing quotas to sum above that cap gives each channel room to contribute enough candidates before the global merge.
b0b2581 to
3e3d741
Compare
b8bca9e to
41b08d4
Compare
3e3d741 to
b0ef2fe
Compare
kmontemayor2-sc
left a comment
There was a problem hiding this comment.
Hi Matt, thanks for breaking up the PRs.
Does this comment make any sense to you? https://github.com/Snapchat/GiGL/pull/709/changes#r3677995032
I wonder if we want to think about the semantics here a bit more
| def test_typed_ppr_sampler_loader_outputs_channel_attrs(self) -> None: | ||
| """Verify typed PPR runs end-to-end through the loader.""" | ||
| mp.spawn(fn=_run_typed_ppr_loader_shape_check, args=()) | ||
|
|
There was a problem hiding this comment.
Should this test be in this PR?
| # ID; each inner list contains the integer edge-type IDs that channel may | ||
| # traverse from that node type. | ||
| TypedPPRChannelTraversalMap = list[list[int]] | ||
| # All typed-channel traversal maps, ordered to match quota order. |
There was a problem hiding this comment.
What does "quota order" mean here?
| async def _compute_typed_ppr_scores( | ||
| self, | ||
| seed_nodes: torch.Tensor, | ||
| seed_node_type: NodeType, | ||
| typed_ppr_channel_quotas: list[int], | ||
| ) -> HeteroPPRResult: | ||
| """Run one PPR state per typed channel and extract the merged result. | ||
|
|
||
| Each channel receives the same seed nodes but a different edge-type | ||
| traversal allowlist. Fetch frontiers are unioned across active channels | ||
| per iteration so shared graph neighborhoods are fetched once and reused | ||
| by every channel that requested them. After convergence, C++ applies | ||
| channel quotas, residual top-up, and cross-channel deduplication in one | ||
| extraction step. | ||
|
|
||
| Args: | ||
| seed_nodes: Global node IDs for the seed batch. | ||
| seed_node_type: Heterogeneous node type for ``seed_nodes``. | ||
| typed_ppr_channel_quotas: Per-channel candidate quotas, aligned | ||
| with ``self._typed_ppr_channel_to_node_type_id_to_edge_type_ids``. | ||
|
|
||
| Returns: | ||
| Heterogeneous PPR extraction output with typed edge-attribute | ||
| feature vectors. | ||
| """ |
There was a problem hiding this comment.
btw I was sort of hoping these changes could be in a separate, non-api focussed PR.
(e.g. we'd throw if the typed_channel gets provided when we have the API but not logic behind it).
There was a problem hiding this comment.
Sure, I'll migrate this to the other code which focuses on the C++/sampling logic changes.
| // which channel states still need pushResiduals(), and the unioned frontier to | ||
| // fetch once for all channels that requested it. | ||
| struct TypedPPRQueueDrainResult { | ||
| // Channels whose drainQueue() returned a value this iteration. |
There was a problem hiding this comment.
typed channel state vector, aligned with channelQuotas and the Python typed_channel_quotas insertion order
Hmmm, do we ever need to worry about cross process serialization here? We had some issues with mangled order right? Was that just with proto?
8e4520e to
b326797
Compare
b326797 to
eb2ffe6
Compare
Summary
Adds the Python/API layer for typed-channel PPR sampling.
This PR is stacked on #724, which contains the C++ typed PPR drain/extraction implementation. This layer exposes those C++ APIs through pybind/stubs, adds the sampler option, and wires typed PPR execution into
DistPPRNeighborSampler.Motivation
For heterogeneous graphs, edge types often carry meaningful relation information. A single collapsed PPR traversal can tell us that a neighbor is relevant, but it loses which typed relation paths contributed to that relevance.
Typed-channel PPR preserves that structure by running PPR over configured edge-type traversal channels and emitting channel-aware edge attributes. Downstream models can consume the best calibrated PPR score, per-channel calibrated scores, and per-channel presence indicators.
What Changed
Adds
typed_channel_quotastoPPRSamplerOptions.("user", "views", "item").Adds typed-channel parsing, validation, and traversal-map construction.
max_ppr_nodesso sparse channels can still help fill the final sequence.Wires per-channel PPR execution into the distributed sampler.
PPRForwardPushstate per typed channel.Exposes typed PPR outputs through pybind and Python stubs.
[best_score, channel_scores..., channel_presence_bits...].Tests
Added focused Python coverage for: