Pytorch C ++ (libtorch) выводит разные результаты, если я меняю форму

Итак, я изучаю нейронные сети прямо сейчас, и я заметил что-то действительно очень странное в своей сети. У меня есть входной слой, созданный вот так

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 получает два разных значения из моей сети только из-за того, что размер пакета изменился? Я не понимаю некоторых частей того, как работают тензоры?

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);
}

person user1289479    schedule 05.05.2020    source источник
comment
То же самое происходит, когда вы применяете toTensor(), например std::cout << network->forward(inputTensor).toTensor()?   -  person Szymon Maszke    schedule 05.05.2020
comment
Не могли бы вы предоставить дополнительную информацию о сети? Только с предоставленной вами сверткой выходные данные будут иметь форму {batchSize, 256, 15, 15}, а применение tanh впоследствии сохраняет размеры, что не приводит к единственному значению. Также убедитесь, что customTensor не изменился после первого вызова, вы потенциально можете изменить его на месте в сети.   -  person Michael Jungo    schedule 05.05.2020
comment
@ SzymonMaszke, похоже, в моей библиотеке нет функции toTensor () для класса torch :: Tensor. @MichaelJungo Вся сеть довольно сложна, но я добавил более подробный взгляд на то, как она устроена и как она называется. Я также убедился, что пользовательский тензор не менялся между вызовами. Это потому, что я фактически дважды создавал тензор, я просто упростил его для вставки в stackoverflow.   -  person user1289479    schedule 05.05.2020
comment
Все выглядит прекрасно. Я пробовал запустить его, и он дает точно такой же результат, как и ожидалось, при запуске в режиме eval, хотя мне нужно было изменить изменение формы для первой линейной, поскольку результат в этой точке имеет форму {batchSize, 2, 15, 15}, что означает это должно быть x.reshape({ x.sizes()[0], 2 * 15 * 15 }). Если вы используете только эти модули, единственное, что я вижу, это то, что для BatchNorm2d не было установлено значение eval (возможно, он не был зарегистрирован как модуль), вы можете проверить их индивидуально, например, с помощью network->batchNorm1->is_training().   -  person Michael Jungo    schedule 05.05.2020


Ответы (1)


СПАСИБО, @MichaelJungo, оказывается, ты был прав в том, что один из моих BatchNorm2d не был установлен в режим оценки. Мне было непонятно, как вначале работала регистрация модулей (в какой-то степени все еще), поэтому я перегрузил функцию :: train (), чтобы вручную установить все мои модули в необходимый режим.

В нем я забыл установить один из моих модулей BatchNorm в правильный режим, это сделало все согласованным, спасибо большое!

person user1289479    schedule 05.05.2020