Phase-Technologies's picture
Initial release: Two-tower recommendation models + hyper-detailed model card
b52fc83 verified
Raw History Blame Contribute Delete
1.34 kB
import torch, torch.nn as nn, torch.nn.functional as nnf
mlp = lambda i, h, o: nn.Sequential(nn.Linear(i, h), nn.ReLU(), nn.Linear(h, o))
class ItemTower(nn.Module):
def __init__(s, item_in=389, out=128):
super().__init__(); s.net = mlp(item_in, 256, out)
def forward(s, x): return nnf.normalize(s.net(x), dim=-1)
class UserTower(nn.Module):
def __init__(s, item_in=389, aff=15, demo=4, out=128):
super().__init__(); s.net = mlp(item_in + aff + demo, 256, out)
def forward(s, aff, hist, demo):
return nnf.normalize(s.net(torch.cat([aff, hist, demo], -1)), dim=-1)
class TwoTower(nn.Module):
def __init__(s):
super().__init__()
s.user, s.item = UserTower(), ItemTower()
s.log_scale = nn.Parameter(torch.tensor(2.64)) # learned temperature
def loss(s, aff, hist, demo, pid, nid, w, F):
u = s.user(aff, hist, demo) # B x 128
ids = torch.cat([pid, nid])
lg = (u @ s.item(F[ids]).T) * s.log_scale.exp() # B x 2B: in-batch + logged skips
dup = ids[None] == pid[:, None] # same post = not a negative
r = torch.arange(len(u)); dup[r, r] = False
ce = nnf.cross_entropy(lg.masked_fill(dup, -1e4), r, reduction="none")
return (ce * w).sum() / w.sum()