【问题标题】:Pytorch C++ (libtorch) outputs different results if I change shape如果我改变形状,Pytorch C++ (libtorch) 会输出不同的结果
【发布时间】:2020-08-19 19:27:39
【问题描述】:

所以我现在正在学习神经网络,我注意到我的网络中有一些非常奇怪的东西。 我有一个像这样创建的输入层

convN1 = register_module("convN1", torch::nn::Conv2d(torch::nn::Conv2dOptions(4, 256, 3).padding(1)));

还有一个输出层,它是一个 tanh 函数。

所以它期待一个torch::Tensor的形状 {/batchSize/, 4, /sideLength/, /sideLength/} 将输出一个只有 1 个浮点值的张量。

为了进行测试,我创建了一个形状为 {4, 15, 15} 的自定义张量。

真正奇怪的部分是下面发生的事情

auto inputTensor = torch::zeros({ 1, 4, 15, 15});
inputTensor[0] = customTensor;
std::cout << network->forward(inputTensor); // Outputs something like 0.94142

inputTensor = torch::zeros({ 32, 4, 15, 15});
inputTensor[0] = customTensor;
std::cout << network->forward(inputTensor); // Outputs something like 0.1234 then 0.8543 31 times

那么,为什么 customTensor 从我的网络中获得 2 个不同的值只是因为批量大小发生了变化?我是否不了解张量如何工作的某些部分?

附:我做了检查,上面的代码块是在 eval 模式下运行的。

编辑:既然有人问过这里,那就更深入地看看我的网络

convN1 = register_module("convN1", torch::nn::Conv2d(torch::nn::Conv2dOptions(4, 256, 3).padding(1)));
batchNorm1 = register_module("batchNorm1", torch::nn::BatchNorm2d(torch::nn::BatchNormOptions(256)));

m_residualBatch1 = register_module(batch1Name, torch::nn::BatchNorm2d(torch::nn::BatchNormOptions(256)));
m_residualBatch2 = register_module(batch2Name, torch::nn::BatchNorm2d(torch::nn::BatchNormOptions(256)));
m_residualConv1 = register_module(conv1Name, torch::nn::Conv2d(torch::nn::Conv2dOptions(256, 256, 3).padding(1)));
m_residualConv2 = register_module(conv2Name, torch::nn::Conv2d(torch::nn::Conv2dOptions(256, 256, 3).padding(1)));

valueN1 = register_module("valueN1", torch::nn::Conv2d(256, 2, 1));
batchNorm3 = register_module("batchNorm3", torch::nn::BatchNorm2d(torch::nn::BatchNormOptions(2)));
valueN2 = register_module("valueN2", torch::nn::Linear(2 * BOARD_LENGTH, 64));
valueN3 = register_module("valueN3", torch::nn::Linear(64, 1));

而它的转发方式是这样的

torch::Tensor Net::forwadValue(torch::Tensor x)
{
    x = convN1->forward(x);
    x = batchNorm1->forward(x);
    x = torch::relu(x);

    torch::Tensor residualCopy = x.clone();
    x = m_residualConv1->forward(x);
    x = m_residualBatch1->forward(x);
    x = torch::relu(x);
    x = m_residualConv2->forward(x);
    x = m_residualBatch2->forward(x);
    x += residualCopy;
    x = torch::relu(x);

    x = valueN1->forward(x);
    x = batchNorm3->forward(x)
    x = torch::relu(x);
    x = valueN2->forward(x.reshape({ x.sizes()[0], 30 }))
    x = torch::relu(x);
    x = valueN3->forward(x)
    return torch::tanh(x);
}

【问题讨论】:

  • 当你申请toTensor()时是否会发生同样的情况,例如std::cout &lt;&lt; network-&gt;forward(inputTensor).toTensor()?
  • 您能否提供有关网络的更多信息?仅使用您提供的卷积,输出将具有形状 {batchSize, 256, 15, 15},然后应用 tanh 会保留尺寸,这不会产生单个值。还要验证customTensor 在第一次调用后没有改变,您可能会在网络中就地修改它。
  • @SzymonMaszke 我的库似乎没有用于 torch::Tensor 类的 toTensor() 函数。 @MichaelJungo 整个网络非常复杂,但我更深入地了解了它的构建方式和调用方式。我还验证了自定义张量在调用之间没有改变。这是因为我实际上创建了两次张量,我只是简化了它以粘贴到 stackoverflow 上。
  • 看起来一切都很好。我已经尝试运行它,并且在 eval 模式下运行它时,它会产生与预期完全相同的输出,尽管我需要更改第一个线性的重塑,因为该点的输出形状为 {batchSize, 2, 15, 15},这意味着它必须是x.reshape({ x.sizes()[0], 2 * 15 * 15 })。如果您只使用这些模块,我唯一能看到的是 BatchNorm2d 没有设置为 eval(可能它没有注册为模块),您可以使用 egnetwork-&gt;batchNorm1-&gt;is_training() 单独检查它们。

标签: c++ neural-network pytorch reshape libtorch


【解决方案1】:

谢谢@MichaelJungo,事实证明你是对的,我的 BatchNorm2d 没有设置为 eval 模式。一开始我不清楚注册模块是如何工作的(在某种程度上仍然如此),所以我重载了 ::train() 函数以手动将我的所有模块设置为必要的模式。

在其中我忘记将我的一个 BatchNorm 模块设置为正确的模式,这样做让一切保持一致,非常感谢!

【讨论】:

    猜你喜欢
    • 2020-12-09
    • 2021-10-30
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2014-02-28
    • 2019-11-16
    • 2022-10-13
    • 1970-01-01
    相关资源
    最近更新 更多