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
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?
There was a problem hiding this comment.
I'd prefer to keep this here, since this requires E2E (including API) changes to work and this branches out of the CPP PR. I plan to squash this in to the CPP PR and merge them together anyway.
| # 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?
There was a problem hiding this comment.
Discussed offline, we've reframed quota to be a decimal between 0 and 1 per channel for how much of the final sequence length they should be responsible for populating
| 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?
e239141 to
eb2ffe6
Compare
a91cce7 to
006f24e
Compare
eb2ffe6 to
c04b7cf
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 and extraction implementation. This layer exposes typed-channel PPR through sampler options and wires it into
DistPPRNeighborSampler.Motivation
A collapsed heterogeneous PPR traversal can identify relevant neighbors, but it loses which relation paths contributed to that relevance. Typed-channel PPR keeps that information by running PPR over configured edge-type channels and emitting channel-aware edge attributes.
Downstream consumers can use:
What Changed
Keeps
max_ppr_nodesas the per-seed PPR sequence cap.Adds
typed_channel_ratiostoPPRSamplerOptions.("user", "views", "item").(0, 1]and must sum to1.0.Converts typed-channel ratios to integer channel target counts during sampler construction.
max_ppr_nodes=200and ratios{views: 0.6, likes/shares: 0.4}targets 120 and 80 nodes.max_ppr_nodescap.Adds typed-channel parsing, validation, and traversal-map construction.
Wires typed PPR execution into the distributed sampler.
PPRForwardPushstate per typed channel.Emits typed PPR edge attributes with shape
[N, 1 + 2 * num_channels]:num_channelscolumns: per-channel scoresnum_channelscolumns: per-channel presence bitsTests
Added focused Python coverage for: