model.py 2.37 KB
Newer Older
WangYQ's avatar
WangYQ committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import torch as th


class EGES(th.nn.Module):
    def __init__(self, dim, num_nodes, num_brands, num_shops, num_cates):
        super(EGES, self).__init__()
        self.dim = dim
        # embeddings for nodes
        base_embeds = th.nn.Embedding(num_nodes, dim)
        brand_embeds = th.nn.Embedding(num_brands, dim)
        shop_embeds = th.nn.Embedding(num_shops, dim)
        cate_embeds = th.nn.Embedding(num_cates, dim)
        self.embeds = [base_embeds, brand_embeds, shop_embeds, cate_embeds]
        # weights for each node's side information
        self.side_info_weights = th.nn.Embedding(num_nodes, 4)

    def forward(self, srcs, dsts):
        # srcs: sku_id, brand_id, shop_id, cate_id
        srcs = self.query_node_embed(srcs)
        dsts = self.query_node_embed(dsts)
21

WangYQ's avatar
WangYQ committed
22
        return srcs, dsts
23

WangYQ's avatar
WangYQ committed
24
25
    def query_node_embed(self, nodes):
        """
26
        @nodes: tensor of shape (batch_size, num_side_info)
WangYQ's avatar
WangYQ committed
27
28
29
30
31
32
33
34
35
        """
        batch_size = nodes.shape[0]
        # query side info weights, (batch_size, 4)
        side_info_weights = th.exp(self.side_info_weights(nodes[:, 0]))
        # merge all embeddings
        side_info_weighted_embeds_sum = []
        side_info_weights_sum = []
        for i in range(4):
            # weights for i-th side info, (batch_size, ) -> (batch_size, 1)
36
37
38
            i_th_side_info_weights = side_info_weights[:, i].view(
                (batch_size, 1)
            )
WangYQ's avatar
WangYQ committed
39
            # batch of i-th side info embedding * its weight, (batch_size, dim)
40
41
42
            side_info_weighted_embeds_sum.append(
                i_th_side_info_weights * self.embeds[i](nodes[:, i])
            )
WangYQ's avatar
WangYQ committed
43
44
            side_info_weights_sum.append(i_th_side_info_weights)
        # stack: (batch_size, 4, dim), sum: (batch_size, dim)
45
46
47
        side_info_weighted_embeds_sum = th.sum(
            th.stack(side_info_weighted_embeds_sum, axis=1), axis=1
        )
WangYQ's avatar
WangYQ committed
48
        # stack: (batch_size, 4), sum: (batch_size, )
49
50
51
        side_info_weights_sum = th.sum(
            th.stack(side_info_weights_sum, axis=1), axis=1
        )
WangYQ's avatar
WangYQ committed
52
53
54
        # (batch_size, dim)
        H = side_info_weighted_embeds_sum / side_info_weights_sum

55
        return H
WangYQ's avatar
WangYQ committed
56
57
58
59
60

    def loss(self, srcs, dsts, labels):
        dots = th.sigmoid(th.sum(srcs * dsts, axis=1))
        dots = th.clamp(dots, min=1e-7, max=1 - 1e-7)

61
62
63
        return th.mean(
            -(labels * th.log(dots) + (1 - labels) * th.log(1 - dots))
        )