处理神经网络模型中的负值

我有一个简单的 nn 模型,结构如下:

class TestRNN(nn.Module):    def __init__(self, batch_size, n_steps, n_inputs, n_neurons, n_outputs):        super(TestRNN, self).__init__()        ...        self.basic_rnn = nn.RNN(self.n_inputs, self.n_neurons)        self.FC = nn.Linear(self.n_neurons, self.n_outputs)    def forward(self, X):        ...        lstm_out, self.hidden = self.basic_rnn(X, self.hidden)        out = self.FC(self.hidden)        return out.view(-1, self.n_outputs)

我使用 criterion = nn.CrossEntropyLoss() 来计算误差。操作顺序大致如下:

# 获取输入x, y = data# 前向传播 + 反向传播 + 优化outputs = model(x)loss = criterion(outputs, y)

我的训练数据 x 已经过归一化,数据看起来像这样:

tensor([[[7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [2.6164e-02, 2.6164e-02, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 1.3108e-05],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [9.5062e-01, 3.1036e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [0.0000e+00, 1.3717e-05, 3.2659e-07,  ..., 0.0000e+00,          0.0000e+00, 3.2659e-07]],        [[5.1934e-01, 5.4041e-01, 6.8083e-06,  ..., 0.0000e+00,          0.0000e+00, 6.8083e-06],         [5.2340e-01, 6.0007e-01, 2.7062e-06,  ..., 0.0000e+00,          0.0000e+00, 2.7062e-06],         [8.1923e-01, 5.7346e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00]],        [[7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0714e-01, 7.0708e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 7.0407e-06],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00]],        ...,        [[7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.1852e-01, 2.3411e-02, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0775e-01, 7.0646e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 3.9888e-06],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00]],        [[5.9611e-01, 5.8796e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0710e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.7538e-01, 2.4842e-01, 1.7787e-06,  ..., 0.0000e+00,          0.0000e+00, 1.7787e-06],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00]],        [[5.2433e-01, 5.2433e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [1.3155e-01, 1.3155e-01, 0.0000e+00,  ..., 8.6691e-02,          9.7871e-01, 0.0000e+00],         [7.4412e-01, 6.6311e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 0.0000e+00],         [7.0711e-01, 7.0711e-01, 0.0000e+00,  ..., 0.0000e+00,          0.0000e+00, 9.6093e-07]]])

而典型的 output 和传递给损失函数的 y 看起来像这样:

tensor([[-0.0513],        [-0.0445],        [-0.0514],        [-0.0579],        [-0.0539],        [-0.0323],        [-0.0521],        [-0.0294],        [-0.0372],        [-0.0518],        [-0.0516],        [-0.0501],        [-0.0312],        [-0.0496],        [-0.0436],        [-0.0514],        [-0.0518],        [-0.0465],        [-0.0530],        [-0.0471],        [-0.0344],        [-0.0502],        [-0.0536],        [-0.0594],        [-0.0356],        [-0.0371],        [-0.0513],        [-0.0528],        [-0.0621],        [-0.0404],        [-0.0403],        [-0.0562],        [-0.0510],        [-0.0580],        [-0.0516],        [-0.0556],        [-0.0063],        [-0.0459],        [-0.0494],        [-0.0460],        [-0.0631],        [-0.0525],        [-0.0454],        [-0.0509],        [-0.0522],        [-0.0426],        [-0.0527],        [-0.0423],        [-0.0572],        [-0.0308],        [-0.0452],        [-0.0555],        [-0.0479],        [-0.0513],        [-0.0514],        [-0.0498],        [-0.0514],        [-0.0471],        [-0.0505],        [-0.0467],        [-0.0485],        [-0.0520],        [-0.0517],        [-0.0442]], device='cuda:0', grad_fn=<ViewBackward>)tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], device='cuda:0')

当应用损失函数时,我在运行 CUDA_LAUNCH_BLOCKING=1 时得到了以下错误:

/opt/conda/conda-bld/pytorch_1549628766161/work/aten/src/THCUNN/ClassNLLCriterion.cu:105: void cunn_ClassNLLCriterion_updateOutput_kernel(Dtype *, Dtype *, Dtype *, long *, Dtype *, int, int, int, int, long) [with Dtype = float, Acctype = float]: block: [0,0,0], thread: [7,0,0] Assertion `t >= 0 && t < n_classes` failed./opt/conda/conda-bld/pytorch_1549628766161/work/aten/src/THCUNN/ClassNLLCriterion.cu:105: void cunn_ClassNLLCriterion_updateOutput_kernel(Dtype *, Dtype *, Dtype *, long *, Dtype *, int, int, int, int, long) [with Dtype = float, Acctype = float]: block: [0,0,0], thread: [20,0,0] Assertion `t >= 0 && t < n_classes` failed.THCudaCheck FAIL file=/opt/conda/conda-bld/pytorch_1549628766161/work/aten/src/THCUNN/generic/ClassNLLCriterion.cu line=111 error=59 : device-side assert triggered

模型输出负值导致了上述错误,我该如何解决这个问题?


回答:

TL;DR

你有两个选择:

  1. outputs 的第二维度大小改为 2 而不是 1。
  2. 使用 nn.BCEWithLogitsLoss 代替 nn.CrossEntropyLoss

我认为问题不在于负数,而在于 outputs 的形状。

观察你的数组 y,我发现你有两个不同的类别(可能更多,但我们假设是两个)。这意味着 outputs 的最后一个维度应该为 2。原因是 outputs 需要为两个不同的类别各提供一个“分数”(参见 文档)。这个分数可以是负数、零或正数。但你的 outputs 的形状是 [64,1],而不是所需的 [64,2]

nn.CrossEntropyLoss() 对象的一个步骤将是将这些分数转换为两个类别的概率分布。这是通过 softmax 操作完成的。然而,在进行二元分类(即只有两个类别的分类,如我们当前的情况)时,还有一个选择:只为一个类别提供分数,使用 sigmoid 函数将其转换为该类别的概率,然后对其执行“1-p”操作以获得另一个类别的概率。这个选项意味着 outputs 只需要为两个类别中的一个提供分数,就像你当前的情况一样。要选择这个选项,你需要将 nn.CrossEntropyLoss 更改为 nn.BCEWithLogitsLoss。然后你可以像目前一样传递 outputsy(请注意,outputs 的形状需要与 y 的形状完全一致,因此在你的例子中,你需要传递 outputs[:,0] 而不是 outputs。此外,你需要将 y 转换为浮点数:y.float()。因此调用应为 criterion(outputs[:,0], y.float())

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注