shenweichen / DeepCTR-Torch

【PyTorch】Easy-to-use,Modular and Extendible package of deep-learning based CTR models.
https://deepctr-torch.readthedocs.io/en/latest/index.html
Apache License 2.0
3.02k stars 705 forks source link

one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [6725, 1]] is at version 2; expected version 1 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True) #90

Closed zhangsuzerain closed 4 years ago

zzr0427 commented 4 years ago

感觉是add_regularization_loss的方式不对,把basemodel.py的fit函数里的total_loss = loss # + self.reg_loss + self.aux_loss后面的范数损失注释掉代码即正确运行,顺便后面total_loss.backward(retain_graph=False)也可以改成False了。

对比了一个DeepCTR里tensorflow的实现,regularizers是在build函数里通过add_weight增加的,所以范数损失是在forward的时候计算的。而pytorch版本中,add_regularization_loss在init的时候就已经加上了,每个epoch的reg_loss都依赖最初的weight,一旦backward修改了weight,就会报错

wwwangzhch commented 4 years ago

感觉是add_regularization_loss的方式不对,把basemodel.py的fit函数里的total_loss = loss # + self.reg_loss + self.aux_loss后面的范数损失注释掉代码即正确运行,顺便后面total_loss.backward(retain_graph=False)也可以改成False了。

对比了一个DeepCTR里tensorflow的实现,regularizers是在build函数里通过add_weight增加的,所以范数损失是在forward的时候计算的。而pytorch版本中,add_regularization_loss在init的时候就已经加上了,每个epoch的reg_loss都依赖最初的weight,一旦backward修改了weight,就会报错

按你说的方法可以跑通,但是发现从第一个epoch开始就出现训练集误差越来越低,val上却越来越高的情况,不知道你遇到没。模型DeepFM,数据集criteo

WadasZhao commented 4 years ago

感觉是add_regularization_loss的方式不对,把basemodel.py的fit函数里的total_loss = loss # + self.reg_loss + self.aux_loss后面的范数损失注释掉代码即正确运行,顺便后面total_loss.backward(retain_graph=False)也可以改成False了。 对比了一个DeepCTR里tensorflow的实现,regularizers是在build函数里通过add_weight增加的,所以范数损失是在forward的时候计算的。而pytorch版本中,add_regularization_loss在init的时候就已经加上了,每个epoch的reg_loss都依赖最初的weight,一旦backward修改了weight,就会报错

按你说的方法可以跑通,但是发现从第一个epoch开始就出现训练集误差越来越低,val上却越来越高的情况,不知道你遇到没。模型DeepFM,数据集criteo

这个情况解决了吗,我也有类似的问题。

selous123 commented 4 years ago

刚开始接触推荐系统,不知道推荐系统中的参数正则是否和cv中实现相同, 下面的修改是默认为两者的参数正则是相同的。

修改basemodel.py文件

  1. “训练集误差越来越低,val上却越来越高的情况,” 这应该是模型过拟合,在损失中加入参数正则就是为了解决这个问题

  2. “如何在模型训练中加入参数正则” a. 把计算reg_loss部分从init函数移动到fit函数里面

    
    def fit()
    ...
    loss = loss_func(y_pred, y.squeeze(), reduction='sum')

self.add_regularization_loss( self.embedding_dict.parameters(), self.l2_reg_embedding) self.add_regularization_loss( self.linear_model.parameters(), self.l2_reg_linear)

total_loss = loss + self.reg_loss + self.aux_loss ...


b. 修改add_regularization_loss的实现

self.reg_loss = self.reg_loss + reg_loss

self.reg_loss = reg_loss



上面的#实现会把历史的 reg_loss 也添加到 self.reg_loss 中,导致代码报错。
ZhangYuef commented 4 years ago

刚开始接触推荐系统,不知道推荐系统中的参数正则是否和cv中实现相同, 下面的修改是默认为两者的参数正则是相同的。

修改basemodel.py文件

  1. “训练集误差越来越低,val上却越来越高的情况,” 这应该是模型过拟合,在损失中加入参数正则就是为了解决这个问题
  2. “如何在模型训练中加入参数正则” a. 把计算reg_loss部分从init函数移动到fit函数里面
def fit()
...
loss = loss_func(y_pred, y.squeeze(), reduction='sum')

self.add_regularization_loss(
       self.embedding_dict.parameters(), self.l2_reg_embedding)
self.add_regularization_loss(
       self.linear_model.parameters(), self.l2_reg_linear)

total_loss = loss + self.reg_loss + self.aux_loss
...

b. 修改add_regularization_loss的实现

#self.reg_loss = self.reg_loss + reg_loss
self.reg_loss = reg_loss

上面的#实现会把历史的 reg_loss 也添加到 self.reg_loss 中,导致代码报错。

@selous123 谢谢分享!想请教下和cv一样的参数正则是什么意思?能不能稍微讲解下cv里面正则参数和推荐算法里的正则参数的区别?

我们这里的regularization loss不需要包含历史的reg_loss么?

selous123 commented 4 years ago

L2参数正则:

total_loss = loss + \labmda * l2_norm(w)

只需要计算当前模型weight的l2范数(reg_loss)即可。

关于推荐系统中的正则: 我刚接触推荐系统, 所以不太明白为什么要加历史的 reg_loss。我认为可能是代码的问题。

ZhangYuef commented 4 years ago

L2参数正则:

total_loss = loss + \labmda * l2_norm(w)

只需要计算当前模型weight的l2范数(reg_loss)即可。

关于推荐系统中的正则: 我刚接触推荐系统, 所以不太明白为什么要加历史的 reg_loss。我认为可能是代码的问题。

我倾向于正则这种方法在cv领域和在推荐领域的定义是一样的,也就是用法和实现应该是一致的,不该有基本概念上的冲突。

这里的l2范数 code link 之所以会加入历史reg_loss其实是想用到momentum的想法,每次加入的是衰减后(乘以weight_decay)的历史reg_loss.

selous123 commented 4 years ago

首先我同意你的观点:两者的定义应该是一样的, 不应该存在基础概念的冲突。其次,

  1. 在 计算 reg-loss 的时候加入momentum的想法? 代码可以改成如下:把历史的reg_loss从计算图中拿出来,不然求导过程会出问题
    reg_loss = weight_decay * reg_loss
    self.reg_loss = self.reg_loss.item() + reg_loss

存疑点: a. 指数加权平均(momentum)的公式应该是: self.reg = \beta reg + (1-\beta)self.reg beta一般取值为0.9。 而代码中默认传入的参数weight_decay是1e-5,这只是一个scale的参数 所以如果需要加入momentum是否是应该需要加入新的参数 \beta

self.reg_loss = (1-\beta) * self.reg_loss.item() + beta * reg_loss

b. 对于在reg_loss上加momentum是否会使结果变好? 正则化项L1,L2以及weight decay在SGD,Adam中的理解

ZhangYuef commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?)

p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。

环境如下:

WadasZhao commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?)

p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。

环境如下:

  • python 3.7
  • torch 1.4
  • deepctr_torch 0.21 master
  • cpu / CUDA 10.1

可是加了正则还是会出现过拟合现象。训练集auc 和 loss在降低,但是验证集确在上升,从第一个epoch开始就是这样。模型DeepFM,数据集Criteo45M。

ZhangYuef commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?) p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。 环境如下:

  • python 3.7
  • torch 1.4
  • deepctr_torch 0.21 master
  • cpu / CUDA 10.1

可是加了正则还是会出现过拟合现象。训练集auc 和 loss在降低,但是验证集确在上升,从第一个epoch开始就是这样。模型DeepFM,数据集Criteo45M。

@WadasZhao 是在完整的Criteo45M数据集上面测试的么?

WadasZhao commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?) p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。 环境如下:

  • python 3.7
  • torch 1.4
  • deepctr_torch 0.21 master
  • cpu / CUDA 10.1

可是加了正则还是会出现过拟合现象。训练集auc 和 loss在降低,但是验证集确在上升,从第一个epoch开始就是这样。模型DeepFM,数据集Criteo45M。

@WadasZhao 是在完整的Criteo45M数据集上面测试的么?

是的,4500万。是这样的,第一个epoch还行,看不出来是否过拟合,从第二个epoch开始,训练集loss大幅度下降,val不降反升。

WadasZhao commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?) p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。 环境如下:

  • python 3.7
  • torch 1.4
  • deepctr_torch 0.21 master
  • cpu / CUDA 10.1

可是加了正则还是会出现过拟合现象。训练集auc 和 loss在降低,但是验证集确在上升,从第一个epoch开始就是这样。模型DeepFM,数据集Criteo45M。

@WadasZhao 是在完整的Criteo45M数据集上面测试的么?

是的,4500万。是这样的,第一个epoch还行,看不出来是否过拟合,从第二个epoch开始,训练集loss大幅度下降,val不降反升。

经过测试。正则化确实有问题,第一个epoch内每个bactch_size 能够正常更新,第二个epoch一开始第一个batch的loss就急剧下降,val的loss急剧上升,呈现过拟合趋势。 解决办法:去掉模型中的所有正则化参数,用optim内部的weight_decay来代替。

wwwangzhch commented 4 years ago

@selous123 我这里说的momentum可能不是十分准确,原代码里面的想法应该只是把正则化项(reg_loss)约束到了一个数量级(weight_decay)(?) p.s 我刚刚又跑了下examples/run_classification_criteo.py发现梯度反向传播没有报错。 环境如下:

  • python 3.7
  • torch 1.4
  • deepctr_torch 0.21 master
  • cpu / CUDA 10.1

可是加了正则还是会出现过拟合现象。训练集auc 和 loss在降低,但是验证集确在上升,从第一个epoch开始就是这样。模型DeepFM,数据集Criteo45M。

@WadasZhao 是在完整的Criteo45M数据集上面测试的么?

是的,4500万。是这样的,第一个epoch还行,看不出来是否过拟合,从第二个epoch开始,训练集loss大幅度下降,val不降反升。

经过测试。正则化确实有问题,第一个epoch内每个bactch_size 能够正常更新,第二个epoch一开始第一个batch的loss就急剧下降,val的loss急剧上升,呈现过拟合趋势。 解决办法:去掉模型中的所有正则化参数,用optim内部的weight_decay来代替。

可以直接这么转换吗?印象中pytorch里optim的weight_decay会对bias也正则化?

shenweichen commented 4 years ago

没来得及看前面的讨论,不过如果是Criteo完整数据集,训练1个epoch就足够了,后面是会发生过拟合的

shenweichen commented 4 years ago

we have solved this issue in new version , please use pip install -U deepctr-torch to upgrade.