问题描述
我通过使用 PyTorch 矩阵分解将矩阵分解为两个矩阵 P
和 Q
来估计用户-项目矩阵中的评分。我得到了我的损失函数 L(X-PQ)
。
假设 X
的行对应于用户,而 x
是新用户的行,因此新的 X
是 X
与 x
连接。
现在我想最小化 L(X' - P'Q) = L(X - PQ) + L(x - x_pQ)
。因为我已经训练了 P
和 Q
。
我想训练 x_p
这是新用户的行,但保持 Q
固定。
所以我的问题是,在 PyTorch 中有没有办法用固定的 MatrixFactorization
为 P
训练 Q
模型?
我正在使用的代码:
class MatrixFactorizationWithBiasXavier(nn.Module):
def __init__(self,num_people,num_partners,bias=(-0.01,0.01),emb_size=100):
super(MatrixFactorizationWithBiasXavier,self).__init__()
self.person_emb = nn.Embedding(num_people,emb_size)
self.person_bias = nn.Embedding(num_people,1)
self.partner_emb = nn.Embedding(num_partners,emb_size)
self.parnter_bias = nn.Embedding(num_partners,1)
torch.nn.init.xavier_uniform_(self.person_emb.weight)
torch.nn.init.xavier_uniform_(self.partner_emb.weight)
self.person_bias.weight.data.uniform_(bias[0],bias[1])
self.parnter_bias.weight.data.uniform_(bias[0],bias[1])
def forward(self,u,v):
u = self.person_emb(u)
v = self.partner_emb(v)
bias_u = self.person_bias(u).squeeze()
bias_v = self.parnter_bias(v).squeeze()
# calculate dot product
# u*v is a element wise vector multiplication
return torch.sigmoid((u*v).sum(1) + bias_u + bias_v)
def test(model,df_test,verbose=False):
model.eval()
# .to(dev) puts code on either gpu or cpu.
people = torch.LongTensor(df_test.id.values).to(dev)
partners = torch.LongTensor(df_test.pid.values).to(dev)
decision = torch.FloatTensor(df_test.decision.values).to(dev)
y_hat = model(people,partners)
loss = F.mse_loss(y_hat,decision)
if verbose:
print('test loss %.3f ' % loss.item())
return loss.item()
def train(model,df_train,epochs=100,learning_rate=0.01,weight_decay=1e-5,verbose=False):
optimizer = torch.optim.Adam(model.parameters(),lr=learning_rate,weight_decay=weight_decay)
model.train()
for epoch in range(epochs):
# From numpy to PyTorch tensors.
# .to(dev) puts code on either gpu or cpu.
people = torch.LongTensor(df_train.id.values).to(dev)
partners = torch.LongTensor(df_train.pid.values).to(dev)
decision = torch.FloatTensor(df_train.decision.values).to(dev)
# calls forward method of the model
y_hat = model(people,partners)
# Using mean squared errors loss function
loss = F.mse_loss(y_hat,decision)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if verbose and epoch % 100 == 0:
print(loss.item())
解决方法
找到了解决办法。 原来我可以在我的嵌入(伙伴 emb,那是我的 Q)上注册一个钩子(我想保持固定),这样它就会说它的梯度为零。
mask = torch.zeros_like(mf_model.partner_emb.weight)
mf_model.partner_emb.weight.register_hook(lambda grad: grad*mask)