如果我改变形状,Pytorch C++ (libtorch) 输出不同的结果
Pytorch C++ (libtorch) outputs different results if I change shape
所以我现在正在学习神经网络,我注意到我的网络中有一些非常奇怪的东西。
我有一个这样创建的输入层
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 个不同的值只是因为 batchsize 已经改变了?我是不是不了解张量工作原理的某些部分?
P.S。我确实检查过,上面的代码块是在 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);
}
谢谢@MichaelJungo 原来你是对的,我的 BatchNorm2d 之一没有设置为 eval 模式。我不清楚注册模块在一开始是如何工作的(在一定程度上仍然如此)所以我重载了 ::train() 函数以手动将我的所有模块设置为必要的模式。
在其中我忘记将我的一个 BatchNorm 模块设置为正确的模式,这样做使它保持一致,非常感谢!
所以我现在正在学习神经网络,我注意到我的网络中有一些非常奇怪的东西。 我有一个这样创建的输入层
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 个不同的值只是因为 batchsize 已经改变了?我是不是不了解张量工作原理的某些部分?
P.S。我确实检查过,上面的代码块是在 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);
}
谢谢@MichaelJungo 原来你是对的,我的 BatchNorm2d 之一没有设置为 eval 模式。我不清楚注册模块在一开始是如何工作的(在一定程度上仍然如此)所以我重载了 ::train() 函数以手动将我的所有模块设置为必要的模式。
在其中我忘记将我的一个 BatchNorm 模块设置为正确的模式,这样做使它保持一致,非常感谢!