| 388 | } |
| 389 | |
| 390 | Status SymbolicGradientBuilder::ProcessWhileLoop(Node* exit_node, |
| 391 | const Output& summed_grads) { |
| 392 | // TODO(skyewm): detect second-order gradient and return bad status |
| 393 | // TODO(skyewm): handle (or at least detect) nested while loops |
| 394 | |
| 395 | // TODO(skyewm): handle NoGradient in while loop |
| 396 | if (summed_grads == NoGradient()) { |
| 397 | return errors::Unimplemented( |
| 398 | "Missing gradient into while loop not yet implemented"); |
| 399 | } |
| 400 | |
| 401 | DCHECK(exit_node->IsExit()); |
| 402 | WhileContext* while_ctx = exit_node->while_ctx(); |
| 403 | DCHECK(while_ctx != nullptr); |
| 404 | |
| 405 | // Record 'summed_grads' as the backprop input associated with 'exit_node' |
| 406 | std::map<Node*, Output>& backprops = while_backprops_[while_ctx]; |
| 407 | DCHECK(backprops.find(exit_node) == backprops.end()); |
| 408 | backprops[exit_node] = summed_grads; |
| 409 | |
| 410 | // Wait until we have all exit nodes' backprops collected before processing |
| 411 | // the while loop. |
| 412 | // TODO(skyewm): what if not all the exit nodes are reachable? |
| 413 | if (backprops.size() < while_ctx->exit_nodes().size()) return Status::OK(); |
| 414 | |
| 415 | // We've seen all the exit nodes for this loop and have collected all the |
| 416 | // backprops. Create the gradient graph for the while loop. |
| 417 | Scope while_scope = |
| 418 | scope_.NewSubScope(strings::StrCat(while_ctx->frame_name(), "_grad")); |
| 419 | std::vector<Output> dy; |
| 420 | for (Node* n : while_ctx->exit_nodes()) dy.push_back(backprops[n]); |
| 421 | std::vector<Output> dx; |
| 422 | TF_RETURN_IF_ERROR(AddWhileLoopGradient(while_ctx, while_scope, dy, &dx)); |
| 423 | |
| 424 | // Backprop along the in edges to the while loop (i.e. the inputs to the enter |
| 425 | // nodes) |
| 426 | DCHECK_EQ(dx.size(), while_ctx->enter_nodes().size()); |
| 427 | for (int i = 0; i < dx.size(); ++i) { |
| 428 | Node* enter_node = while_ctx->enter_nodes()[i]; |
| 429 | for (const Edge* e : enter_node->in_edges()) { |
| 430 | if (e->IsControlEdge()) continue; |
| 431 | TF_RETURN_IF_ERROR(BackpropAlongEdge(dx[i], {e->src(), e->src_output()})); |
| 432 | } |
| 433 | } |
| 434 | return Status::OK(); |
| 435 | } |
| 436 | |
| 437 | Status SymbolicGradientBuilder::AddGradients() { |
| 438 | // Initialize backprops. |
nothing calls this directly
no test coverage detected