Propagates the shapes in the transitive fan-out of .
| 1987 | |
| 1988 | // Propagates the shapes in the transitive fan-out of <new_shapes>. |
| 1989 | Status GraphProperties::PropagateShapes( |
| 1990 | SymbolicShapeRefiner* shape_refiner, TopoQueue* new_shapes, |
| 1991 | const std::unordered_map<const NodeDef*, const NodeDef*>& resource_handles, |
| 1992 | int num_loops) const { |
| 1993 | // Limit the number of iterations to prevent infinite loops in the presence of |
| 1994 | // incorrect shape functions. The algorithm should converge in at most |
| 1995 | // num_nested_loops^2 * max_rank. We approximate max_rank with the constant 4. |
| 1996 | // The same applies to resources. |
| 1997 | VLOG(1) << "Propagating " << new_shapes->size() << " new shapes through " |
| 1998 | << num_loops << " loops and " << resource_handles.size() |
| 1999 | << " resources" << std::endl; |
| 2000 | |
| 2001 | const int64 max_loop_length = item_.graph.node_size(); |
| 2002 | const int64 max_rank = 4; |
| 2003 | const int64 max_loop_iterations = |
| 2004 | max_rank * max_loop_length * std::max<int64>(1, num_loops * num_loops); |
| 2005 | const int64 num_queues = resource_handles.size(); |
| 2006 | const int64 max_resource_iterations = num_queues * num_queues * max_rank; |
| 2007 | |
| 2008 | int64 num_resource_iterations = 0; |
| 2009 | do { |
| 2010 | int64 num_loop_iterations = 0; |
| 2011 | while (!new_shapes->empty() && |
| 2012 | num_loop_iterations++ < max_loop_iterations) { |
| 2013 | const NodeDef* n = new_shapes->pop(); |
| 2014 | bool updated = false; |
| 2015 | TF_RETURN_IF_ERROR( |
| 2016 | UpdateShapes(shape_refiner, resource_handles, n, &updated)); |
| 2017 | if (updated) { |
| 2018 | for (const auto& fanout : shape_refiner->graph().GetFanouts( |
| 2019 | *n, /*include_controlled_nodes=*/false)) { |
| 2020 | new_shapes->push(fanout.node); |
| 2021 | } |
| 2022 | // Make sure the corresponding queue nodes are (re)processed. |
| 2023 | if (IsEnqueue(*n)) { |
| 2024 | auto it = resource_handles.find(n); |
| 2025 | if (it != resource_handles.end()) { |
| 2026 | new_shapes->push(it->second); |
| 2027 | } |
| 2028 | } |
| 2029 | } |
| 2030 | } |
| 2031 | } while (!new_shapes->empty() && |
| 2032 | num_resource_iterations++ < max_resource_iterations); |
| 2033 | |
| 2034 | if (!new_shapes->empty()) { |
| 2035 | return errors::Internal("Shape inference failed to converge"); |
| 2036 | } |
| 2037 | |
| 2038 | return Status::OK(); |
| 2039 | } |
| 2040 | |
| 2041 | Status GraphProperties::UpdateQueue(const NodeDef* queue_node, |
| 2042 | SymbolicShapeRefiner* shape_refiner, |