gather_hop_inputs ¶
gather_hop_inputs(
saved: Mapping[int, Tensor],
hop: Hop,
) -> torch.Tensor
Build one hop's input from the layer activations you saved.
Without skip edges, each layer reads only the layer directly
below it, so one module's output is the next module's input.
A skip edge breaks that chain: its source sits two or more
layers below its target. kpnn2 still applies every edge into
a layer with one module, the one built from that layer's hop
(PackedLinear.from_hop(hop) or
MaskedLinear(hop.to_mask())). That module therefore needs
every layer its target's parents sit in, at once and as one
tensor. This function builds that tensor. It does no
arithmetic; it only arranges tensors you already have.
Take A and B feeding H, H feeding C, and
the skip A -> C. Layer 0 is [A, B], layer 1 is
[H], and the hop into C reads both, so its input is
the three columns [A, B, H]: whole layers, laid side by
side in depth order. B is among them although there is
no edge B -> C. The hop says which layers to read, in
which order, and how many units wide each must be. Without
skip edges, every hop reads a single layer, and that layer
is the input as it stands.
Precisely, a hop's source columns are whole source layers
laid side by side, so the tensor feeding PackedLinear or
MaskedLinear on that hop is those layers concatenated.
Call it between hops, keeping every layer you produce in
saved; a forgotten layer raises rather than dropping the
edges that read it. Inputs are never modified, and a
single-source hop returns the saved tensor itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
mapping of int to torch.Tensor
|
Layer depth to that layer's activation, as far as
|
required |
|
Hop
|
The hop about to be applied, one entry of |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
The hop's source axis, shape
|
Raises:
| Type | Description |
|---|---|
Kpnn2Error
|
If |
See Also
scatter_hop_outputs : Split the concatenated axis this
returns back onto source layers.
PackedLinear : Applies the hop to the tensor returned here.
PackedLinear.transpose : Tied decode of that hop; feed its
output to scatter_hop_outputs when the hop reads
several layers.
MaskedLinear : Dense hatch via hop.to_mask().
Hop : The record that fixes the source layers and the
concatenated column order this follows.
align_inputs : Column index that puts named features in the
order layer 0 expects.
Notes
Nothing here is graph-aware: this holds no weights, does not
inject values into the previous layer, and does not pick
skip sources by name. Columns that are not edges stay in the
concatenated tensor; PackedLinear never reads them, and
MaskedLinear(hop.to_mask()) zeros them. In the
[A, B, H] example above, the A -> C weight is the
packed pair whose source column is A.
An AdjacencySpec has no hops and is not accepted; in
that layout every edge is already a packed index pair.
Examples:
The hop into C reads layers 0 and 1, so its input is
two columns wide:
>>> import pandas as pd
>>> import torch
>>> import kpnn2
>>> edgelist = pd.DataFrame(
... {
... "source": ["A", "H", "A"],
... "target": ["H", "C", "C"],
... }
... )
>>> spec = kpnn2.parse_layered(edgelist)
>>> saved = {
... 0: torch.tensor([[2.0]]),
... 1: torch.tensor([[5.0]]),
... }
>>> x = kpnn2.gather_hop_inputs(
... saved,
... spec.hops[1],
... )
>>> x.tolist()
[[2.0, 5.0]]
Forgetting to store a layer raises instead of silently dropping the edges that read it:
>>> kpnn2.gather_hop_inputs(
... {1: torch.tensor([[5.0]])},
... spec.hops[1],
... )
Traceback (most recent call last):
...
Kpnn2Error: saved is missing layer 0. ...