Esempio n. 1
0
    def forward(self, graph: dgl.DGLHeteroGraph, feat: tuple, dst_node_transformation_weight: nn.Parameter,
                src_node_transformation_weight: nn.Parameter, src_nodes_attention_weight: nn.Parameter):
        r"""Compute graph attention network layer.
        Parameters
        ----------
        graph : specific relational DGLHeteroGraph
        feat : pair of torch.Tensor
            The pair contains two tensors of shape (N_{in}, D_{in_{src}})` and (N_{out}, D_{in_{dst}}).
        dst_node_transformation_weight: Parameter (input_dst_dim, n_heads * hidden_dim)
        src_node_transformation_weight: Parameter (input_src_dim, n_heads * hidden_dim)
        src_nodes_attention_weight: Parameter (n_heads, 2 * hidden_dim)
        Returns
        -------
        torch.Tensor, shape (N, H, D_out)` where H is the number of heads, and D_out is size of output feature.
        """
        graph = graph.local_var()
        # Tensor, (N_src, input_src_dim)
        feat_src = self.dropout(feat[0])
        # Tensor, (N_dst, input_dst_dim)
        feat_dst = self.dropout(feat[1])
        # Tensor, (N_src, n_heads, hidden_dim) -> (N_src, input_src_dim) * (input_src_dim, n_heads * hidden_dim)
        feat_src = torch.matmul(feat_src, src_node_transformation_weight).view(-1, self._num_heads, self._out_feats)
        # Tensor, (N_dst, n_heads, hidden_dim) -> (N_dst, input_dst_dim) * (input_dst_dim, n_heads * hidden_dim)
        feat_dst = torch.matmul(feat_dst, dst_node_transformation_weight).view(-1, self._num_heads, self._out_feats)

        # first decompose the weight vector into [a_l || a_r], then
        # a^T [Wh_i || Wh_j] = a_l Wh_i + a_r Wh_j, This implementation is much efficient
        # Tensor, (N_dst, n_heads, 1),   (N_dst, n_heads, hidden_dim) * (n_heads, hidden_dim)
        e_dst = (feat_dst * src_nodes_attention_weight[:, :self._out_feats]).sum(dim=-1, keepdim=True)
        # Tensor, (N_src, n_heads, 1),   (N_src, n_heads, hidden_dim) * (n_heads, hidden_dim)
        e_src = (feat_src * src_nodes_attention_weight[:, self._out_feats:]).sum(dim=-1, keepdim=True)
        # (N_src, n_heads, hidden_dim), (N_src, n_heads, 1)
        graph.srcdata.update({'ft': feat_src, 'e_src': e_src})
        # (N_dst, n_heads, 1)
        graph.dstdata.update({'e_dst': e_dst})
        # compute edge attention, e_src and e_dst are a_src * Wh_src and a_dst * Wh_dst respectively.
        graph.apply_edges(fn.u_add_v('e_src', 'e_dst', 'e'))
        # shape (edges_num, heads, 1)
        e = self.leaky_relu(graph.edata.pop('e'))

        # compute softmax
        graph.edata['a'] = edge_softmax(graph, e)

        graph.update_all(fn.u_mul_e('ft', 'a', 'msg'), fn.sum('msg', 'ft'))
        # (N_dst, n_heads * hidden_dim),   (N_dst, n_heads, hidden_dim) reshape
        dst_features = graph.dstdata.pop('ft').reshape(-1, self._num_heads * self._out_feats)

        dst_features = F.relu(dst_features)

        return dst_features
Esempio n. 2
0
    def _propagate_user_to_item(self, block: DGLHeteroGraph) -> th.Tensor:
        with block.local_scope():
            for etype in self._rating_set:
                block.apply_edges(lambda edges: self._compute_message_user_to_item(edges, etype), etype=etype)
                block.update_all(dgl_fn.copy_e("m", f"m_{etype}"), dgl_fn.mean(f"m_{etype}", f"h_{etype}"), etype=etype)
            item_features: th.Tensor = block.dstnodes["item"].data["item_features"]
            all_feature_on_item = [item_features]
            for rating in self._rating_set:
                feature_name = f"h_{rating}"
                if feature_name in block.dstnodes["item"].data:
                    all_feature_on_item.append(block.dstnodes["item"].data[feature_name])
                else:
                    all_feature_on_item.append(th.zeros(
                        item_features.shape[0], self._embedding_dim,
                        dtype=item_features.dtype, device=item_features.device))

            return self._agg_activation(self._item_aggregate_layer(th.cat(all_feature_on_item, dim=1)))
Esempio n. 3
0
    def _propagate_item_to_user(self, block: DGLHeteroGraph) -> th.Tensor:
        with block.local_scope():
            block.srcnodes["item"].data["item_id_embedding"] = \
                self._item_id_embedding_layer(block.srcnodes["item"].data[dgl.NID])
            for etype in [f"rev-{rating}" for rating in self._rating_set]:
                block.apply_edges(lambda edges: self._compute_message_item_to_user(edges, etype), etype=etype)
                block.update_all(dgl_fn.copy_e("m", f"m_{etype}"), dgl_fn.mean(f"m_{etype}", f"h_{etype}"), etype=etype)
            user_feature = block.dstnodes["user"].data["user_features"]
            all_features_on_user = [user_feature]
            for rating in self._rating_set:
                feature_name = f"h_rev-{rating}"
                if feature_name in block.dstnodes["user"].data:
                    all_features_on_user.append(block.dstnodes["user"].data[feature_name])
                else:
                    all_features_on_user.append(th.zeros(
                        user_feature.shape[0], self._embedding_dim,
                        dtype=user_feature.dtype, device=user_feature.device))

            return self._agg_activation(self._user_aggregate_layer(th.cat(all_features_on_user, dim=1)))
Esempio n. 4
0
 def forward(self, decode_graph: dgl.DGLHeteroGraph, node_representations: Tensor):
     with decode_graph.local_scope():
         decode_graph.ndata["h"] = node_representations
         decode_graph.apply_edges(dgl.function.u_dot_v("h", "h", "logits"))
         return decode_graph.edata["logits"]
Esempio n. 5
0
 def forward(self,g: dgl.DGLHeteroGraph,h,etype='interact'):
     with g.local_scope():
         g.nodes['user'].data['h']=self.dropout(h['user'])
         g.nodes['item'].data['h'] = self.dropout(h['item'])
         g.apply_edges(self.apply_edges,etype=etype)
         return g.edges[etype].data['score']*5