compositional_graph_models/models.py
def forward(self, forest: dgl.DGLGraph) -> torch.Tensor:
        """
        Given a (possibly batched) forest, compute the outputs for each tree.
        """
        num_nodes = forest.num_nodes()
        leaf_mask = (
            forest.ndata[data.FUNCTION_FIELD]
            == self.hparams.function_vocab[data.LEAF_FUNCTION]
        )
        root_mask = (
            forest.ndata[data.FUNCTION_FIELD]
            == self.hparams.function_vocab[data.EQUALITY_FUNCTION]
        )
        internal_mask = ~(leaf_mask | root_mask)
        internal_order = data.typed_topological_nodes_generator(
            forest, node_mask=internal_mask
        )
        predecessor_index = data.tensorize_predecessors(forest)

        # A buffer where the i-th row is the activations output from the i-th node
        # The buffer is repeatedly summed into to allow dense gradient computation;
        # this is valid because each position is summed to exactly once.
        activations = torch.zeros(
            (num_nodes, self.hparams.d_model), device=forest.device
        )

        # A buffer where the i-th row is the memory output from the i-th node.
        memory = torch.zeros(
            (num_nodes, self.memory_size, self.hparams.d_model), device=forest.device
        )

        # Precompute all leaf nodes at once
        tokens = forest.ndata[data.TOKEN_FIELD][leaf_mask]
        token_activations = self.token_embedding(tokens)
        activations = activations.masked_scatter(
            leaf_mask.unsqueeze(1), token_activations
        )

        # Compute all internal nodes under the topological order
        for node_group in internal_order:
            # Look up the type of the first node, since they should all be the same
            function_idx = forest.ndata[data.FUNCTION_FIELD][node_group[0]].item()
            function = self.hparams.function_vocab_inverse[function_idx]

            # Gather inputs, call the module polymorphically, and scatter to buffer
            predecessors = self._compute_predecessors(node_group, predecessor_index)
            input_cell = activations[predecessors]
            input_hidden = memory[predecessors]
            step_activations, step_memory = self._apply_function(function, input_cell, input_hidden)
            activation_scatter = torch_scatter.scatter(
                src=step_activations, index=node_group, dim=0, dim_size=num_nodes
            )
            memory_scatter = torch_scatter.scatter(
                src=step_memory, index=node_group, dim=0, dim_size=num_nodes
            )
            activations = activations + activation_scatter
            memory = memory + memory_scatter

        # Compute all root nodes in 1 step
        root_nodes = torch.where(root_mask)[0]
        root_predecessors = self._compute_predecessors(root_nodes, predecessor_index)
        root_input = activations[root_predecessors]
        return self._compute_output(root_input)

        Given a (possibly batched) forest, compute the outputs for each tree.
        
Given a (possibly batched) forest, compute the outputs for each tree.
Given a ( possibly batched ) forest compute the outputs for each tree .
def forward(self, forest: dgl.DGLGraph) -> torch.Tensor:
        num_nodes = forest.num_nodes()
        leaf_mask = (
            forest.ndata[data.FUNCTION_FIELD]
            == self.hparams.function_vocab[data.LEAF_FUNCTION]
        )
        root_mask = (
            forest.ndata[data.FUNCTION_FIELD]
            == self.hparams.function_vocab[data.EQUALITY_FUNCTION]
        )
        internal_mask = ~(leaf_mask | root_mask)
        internal_order = data.typed_topological_nodes_generator(
            forest, node_mask=internal_mask
        )
        predecessor_index = data.tensorize_predecessors(forest)
        activations = torch.zeros(
            (num_nodes, self.hparams.d_model), device=forest.device
        )
        memory = torch.zeros(
            (num_nodes, self.memory_size, self.hparams.d_model), device=forest.device
        )
        tokens = forest.ndata[data.TOKEN_FIELD][leaf_mask]
        token_activations = self.token_embedding(tokens)
        activations = activations.masked_scatter(
            leaf_mask.unsqueeze(1), token_activations
        )
        for node_group in internal_order:
            function_idx = forest.ndata[data.FUNCTION_FIELD][node_group[0]].item()
            function = self.hparams.function_vocab_inverse[function_idx]
            predecessors = self._compute_predecessors(node_group, predecessor_index)
            input_cell = activations[predecessors]
            input_hidden = memory[predecessors]
            step_activations, step_memory = self._apply_function(function, input_cell, input_hidden)
            activation_scatter = torch_scatter.scatter(
                src=step_activations, index=node_group, dim=0, dim_size=num_nodes
            )
            memory_scatter = torch_scatter.scatter(
                src=step_memory, index=node_group, dim=0, dim_size=num_nodes
            )
            activations = activations + activation_scatter
            memory = memory + memory_scatter
        root_nodes = torch.where(root_mask)[0]
        root_predecessors = self._compute_predecessors(root_nodes, predecessor_index)
        root_input = activations[root_predecessors]
        return self._compute_output(root_input)
def forward ( self , forest : dgl . DGLGraph ) -> torch . Tensor : num_nodes = forest . num_nodes ( ) leaf_mask = ( forest . ndata [ data . FUNCTION_FIELD ] == self . hparams . function_vocab [ data . LEAF_FUNCTION ] ) root_mask = ( forest . ndata [ data . FUNCTION_FIELD ] == self . hparams . function_vocab [ data . EQUALITY_FUNCTION ] ) internal_mask = ~ ( leaf_mask | root_mask ) internal_order = data . typed_topological_nodes_generator ( forest , node_mask = internal_mask ) predecessor_index = data . tensorize_predecessors ( forest ) activations = torch . zeros ( ( num_nodes , self . hparams . d_model ) , device = forest . device ) memory = torch . zeros ( ( num_nodes , self . memory_size , self . hparams . d_model ) , device = forest . device ) tokens = forest . ndata [ data . TOKEN_FIELD ] [ leaf_mask ] token_activations = self . token_embedding ( tokens ) activations = activations . masked_scatter ( leaf_mask . unsqueeze ( 1 ) , token_activations ) for node_group in internal_order : function_idx = forest . ndata [ data . FUNCTION_FIELD ] [ node_group [ 0 ] ] . item ( ) function = self . hparams . function_vocab_inverse [ function_idx ] predecessors = self . _compute_predecessors ( node_group , predecessor_index ) input_cell = activations [ predecessors ] input_hidden = memory [ predecessors ] step_activations , step_memory = self . _apply_function ( function , input_cell , input_hidden ) activation_scatter = torch_scatter . scatter ( src = step_activations , index = node_group , dim = 0 , dim_size = num_nodes ) memory_scatter = torch_scatter . scatter ( src = step_memory , index = node_group , dim = 0 , dim_size = num_nodes ) activations = activations + activation_scatter memory = memory + memory_scatter root_nodes = torch . where ( root_mask ) [ 0 ] root_predecessors = self . _compute_predecessors ( root_nodes , predecessor_index ) root_input = activations [ root_predecessors ] return self . _compute_output ( root_input )
Given a (possibly batched) forest, compute the outputs for each tree.
Given a ( possibly batched ) forest compute the outputs for each tree .
"""
        Given a (possibly batched) forest, compute the outputs for each tree.
        """ # A buffer where the i-th row is the activations output from the i-th node # The buffer is repeatedly summed into to allow dense gradient computation; # this is valid because each position is summed to exactly once. # A buffer where the i-th row is the memory output from the i-th node. # Precompute all leaf nodes at once # Compute all internal nodes under the topological order # Look up the type of the first node, since they should all be the same # Gather inputs, call the module polymorphically, and scatter to buffer # Compute all root nodes in 1 step
self
forest
dgl.DGLGraph