首页 > 解决方案 > 使用更大的批量训练矩阵分解问题时损失更高

问题描述

首先,我要感谢任何考虑阅读此问题的人,如果我的问题如此固执,以及我的英语很差,我很抱歉。

所以目前我正在研究一个推荐系统问题,我的方法是使用矩阵分解和使用 BPR ( arXiv:1205.2618 ) 的隐式反馈。不知何故,我发现当我使用大批量(在本例中为 4096)训练我的模型(BPRMF)时,与使用较小批量(1024)时相比,BPR 损失更差。我在几个时代的训练日志

我注意到更高的批量大小导致更快的训练时间,因为它可以更有效地利用 GPU 内存,但更高的损失可能是我不太愿意交易的东西。据我所知,大批量为梯度下降步骤带来了更多信息,以便采取更好的步骤,因此它应该有助于收敛,通常大批量的问题在于内存和资源,而不是损失。

我对此进行了一些研究,并看到大批量训练导致泛化能力差,而这里又是另一个,但就我而言,它在训练时丢失了。

我最好的猜测是,使用大批量大小,然后取损失的平均值使梯度流向用户和项目嵌入的平均值(1 /批量大小)系数降低,使得在训练时难以逃脱局部最大值。这是这种情况下的答案吗?(但是,我看到最近的研究表明局部最小值不一定是坏的,所以......)

真的很感谢有人帮我回答为什么大批量最终会出现异常结果。

旁注:可能是另一个愚蠢的问题,但正如您在下面的代码中看到的那样,您可以看到 l2 损失没有按批量大小标准化,所以当我将批量大小乘以 4 时,我希望它至少翻倍或四倍,但在上面的日志中似乎并非如此。

这是我的代码

from typing import Tuple

import torch
from torch.nn.parameter import Parameter
import torch.nn.functional as F

from .PretrainedModel import PretrainedModel


class BPRMFModel(PretrainedModel):
    def __init__(self, n_users: int, n_items: int, u_embed: int, l2:float,
                 dataset: str, u_i_pretrained_dir, use_pretrained = 0, **kwargs) -> None:
        super().__init__(n_users=n_users, n_items=n_items, u_embed=u_embed, dataset=dataset,
                         u_i_pretrained_dir=u_i_pretrained_dir, use_pretrained=use_pretrained, 
                         **kwargs)

        self.l2 = l2
        self.reset_parameters()
        self.items_e = Parameter(self._items_e)
        self.users_e = Parameter(self._users_e)
        

    def forward(self, u: torch.Tensor, i: torch.Tensor) -> torch.Tensor:
        u = F.embedding(u, self.users_e)
        i = F.embedding(i, self.items_e)
        return torch.matmul(u, i.T)

    def CF_loss(self, u: torch.Tensor, i_pos: torch.Tensor, i_neg: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        #u, i_pos, i_neg shape is [batch_size,]

        u = F.embedding(u, self.users_e)
        i_pos = F.embedding(i_pos, self.items_e)
        i_neg = F.embedding(i_neg, self.items_e)
        pos_scores = torch.einsum("ij,ij->i", u, i_pos)
        neg_scores = torch.einsum("ij,ij->i", u, i_neg)

        # loss = torch.mean(
        #     F.softplus(-(pos_scores - neg_scores))
        # )
        loss = torch.neg(
            torch.mean(
                F.logsigmoid(pos_scores - neg_scores)
            )
        )

        l2_loss = (
            u.pow(2).sum() +
            i_pos.pow(2).sum() +
            i_neg.pow(2).sum()
        )
        
        return loss, self.l2 * l2_loss
    def get_users_rating_for_each_items(self, u: torch.Tensor, i: torch.Tensor) -> torch.Tensor:
        return self(u, i)
    def save_pretrained(self):
        self._items_e = self.items_e.data
        self._users_e = self.users_e.data
        return super().save_pretrained()

PretrainedModel 只是帮助我保存和加载模型权重的基类

真的很感激任何能忍受我到此为止的人。

标签: deep-learningpytorchrecommendation-engine

解决方案


推荐阅读