TensorFlow Добавление градиента C ++ для пользовательских операций - PullRequest
1 голос
/ 25 февраля 2020

В настоящее время я работаю над проектом, в котором мне нужно добавить пользовательскую функцию потерь в API C ++ tenorflow (1.13.1). Эта функция опирается на некоторые внешние библиотеки, поэтому моя идея заключалась в том, чтобы добавить эту функцию потерь в качестве пользовательской операции. Я пытался следовать этому руководству https://www.tensorflow.org/guide/create_op, но самая важная часть о добавлении градиента в C ++ отсутствует. Итак, вот что я сделал до сих пор:

Я начал с регистрации двух новых операций в nn_ops.cc, одного для функции потерь MyLoss и другого для вычисления градиента MyLossGrad. На следующем шаге я реализовал обе операции в myloss_op.cc, следуя руководству по тензорному потоку.

Моя проблема сейчас: как реализовать соответствующий градиент? Я зарегистрировал его в nn_grad.cc и передал предсказания и метки целей на MyLoss op:

Status MyLossGrad(const Scope& scope, const Operation& op,
                  const std::vector<Output>& grad_inputs,
                  std::vector<Output>* grad_outputs) {     

  auto y_pred = op.input(0);   // Predictions passed to MyLoss Op
  auto y_true = op.input(1);   // Target labels passed to MyLoss Op

  auto my_loss = op.output(0);   // Calculated Loss from my MyLoss Op

  // Do I need these?
  auto grad_loss = grad_inputs[0];  
  auto grad_grad = grad_inputs[1];

  // Calculate and pass gradient
  auto dx = internal::MyLossGrad(scope, y_pred , y_true);
  grad_outputs->push_back(dx);
  grad_outputs->push_back(NoGradient());    

  return scope.status();   
}
REGISTER_GRADIENT_OP("MyLoss", MyLossGrad);

Intuition

Это та часть, где я ' Я не уверен, как продолжить. Если я правильно понял, мне нужно рассчитать два градиента, так как у меня есть два входа:

  1. dL / dx -> Моя функция потерь дифференцирована относительно. мои прогнозы
  2. dL / dy -> Моя функция потерь дифференцирована по сравнению с метки цели

Затем оба градиента передаются в grad_outputs. Насколько я понимаю, градиент dL / dy не нужен, поэтому вместо него я передаю NoGradient.

Вопросы:

  • Верна ли моя интуиция сверху?
  • Для чего используются другие параметры?
  • Что такое grad_inputs? Некоторые другие Ops умножают это с их градиентами? Это необходимо для обратного распространения?

Я не знаю, имеет ли это значение, но эта операция предназначена для использования только в качестве функции потерь, а не в качестве внутреннего узла графа.

Вот небольшой фрагмент, как я использую операционную систему и обучаю свою сеть:

// Build Network:
auto input_x = Placeholder(t_scope.NewSubScope("Input_X"), DT_FLOAT, Placeholder::Shape({bs, x, y, z, c}));
auto input_y = Placeholder(t_scope.NewSubScope("Input_Y"), DT_FLOAT, Placeholder::Shape({bs, x, y, z, c}));

TensorShape filter_size({3, 3, 3, 1, 5});
c_var = Variable(layer_scope.WithOpName("c_var"), filter_size, DT_FLOAT);
c_assign = Assign(layer_scope.WithOpName("c_assign"), c_var , RandomNormal(layer_scope, {3, 3, 3, 1, 5}, DT_FLOAT));   
auto conv = Conv3D(t_scope.NewSubScope("Conv"), input_x, c_var, gtl::ArraySlice<int>{1, 1, 1, 1, 1}, "SAME"); 


// Build Optimization Graph: 
auto loss = MyLoss(t_scope.NewSubScope("MyLoss"), conv, input_y);

vector<Output> grad_outputs;
TF_CHECK_OK(AddSymbolicGradients(t_scope, {loss}, {c_var}, &grad_outputs));

auto m_var = Variable(t_scope, m_shapes[i], DT_FLOAT);
auto v_var = Variable(t_scope, m_shapes[i], DT_FLOAT);
auto m_assign = Assign(t_scope, m_var, Input::Initializer(0.f, filter_size)));
auto v_assign = Assign(t_scope, v_var, Input::Initializer(0.f, filter_size)));    
auto adam = ApplyAdam(t_scope, c_var, m_var, v_var, 0.f, 0.f, 0.001f, 0.9f, 0.999f, 0.00000001f, {grad_outputs[0]});
out_grads.push_back(adam.operation);

// Initialize: 
auto t_session = unique_ptr<ClientSession>(new ClientSession(t_scope));
TF_CHECK_OK(t_session->Run({c_assign, m_assign, v_assign}, nullptr));

// Train:
std::vector<Tensor> outputs;
TF_CHECK_OK(t_session->Run(
                    {{input_x, x_tensor}, {input_y, y_tensor}},
                    {loss}, out_grads, &outputs));
...