• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #ifndef TENSORFLOW_CORE_GRAPPLER_COSTS_GRAPH_PROPERTIES_H_
17 #define TENSORFLOW_CORE_GRAPPLER_COSTS_GRAPH_PROPERTIES_H_
18 
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "tensorflow/core/framework/shape_inference.h"
24 #include "tensorflow/core/grappler/clusters/cluster.h"
25 #include "tensorflow/core/grappler/costs/op_performance_data.pb.h"
26 #include "tensorflow/core/grappler/grappler_item.h"
27 
28 namespace tensorflow {
29 
30 namespace grappler {
31 
32 // Optional attributes that tell about node output information.
33 // We use these side information, if provided, for static shape inference
34 // and VirtualScheduler scheduling.
35 
36 // Switch op attribute as a vector of int that tells which branch the
37 // Switch output is taken on every round of execution.
38 // Used for scheduling ops after Switch correctly (e.g., While loop).
39 ABSL_CONST_INIT const char kOutputSlots[] = "_output_slot_vector";
40 
41 // Example:
42 // Assume a node has two outputs and iterated for three times. Then it has:
43 // _execution_count = 3
44 // _output_sizes_vector = [2, 2, 2]
45 // _output_dtype_vector.size = 6
46 // _output_shape_vector.size = 6
47 
48 // If all the iterations have same output shapes, then
49 // _execution_count = 3
50 // _same_output_for_iterations = true
51 // _output_sizes_vector = [2]
52 // _output_dtype_vector.size = 2
53 // _output_shape_vector.size = 2
54 
55 // How many times this node has been executed.
56 ABSL_CONST_INIT const char kExecutionCount[] = "_execution_count";
57 
58 // Records the output sizes for each round of execution.
59 ABSL_CONST_INIT const char kOutputSizes[] = "_output_sizes_vector";
60 
61 // The node has been scheduled multiple times with outputs that have the same
62 // shape.
63 ABSL_CONST_INIT const char kOutputSame[] = "_same_output_for_iterations";
64 
65 // Outputs DataType vector.
66 ABSL_CONST_INIT const char kOutputTypes[] = "_output_dtype_vector";
67 
68 // Outputs TensorShapeProto vector.
69 ABSL_CONST_INIT const char kOutputShapes[] = "_output_shape_vector";
70 
71 class SymbolicShapeRefiner;
72 class TopoQueue;
73 
74 // Infer OpInfo::TensorProperties for graph nodes inputs/outputs.
75 //
76 // Typical use case, is to infer tensor properties from a graph, before doing
77 // optimization pass. Nodes modified during optimization pass have to be
78 // invalidated, to prevent further incorrect optimizations based on wrong shape
79 // and data type properties.
80 class GraphProperties {
81  public:
82   // The item must outlive the properties
GraphProperties(const GrapplerItem & item)83   explicit GraphProperties(const GrapplerItem& item) : item_(item) {}
84 
85   // Infer the shapes through abstract interpretation. Feed information can be
86   // incorrect so it should be discarded to ensure correctness of the analysis.
87   // However, it can help infer shapes in the fanout of fed nodes (even though
88   // the correctness of these shapes can't be guaranteed), so in some cases
89   // (such as simulation or scheduling) it makes sense of keep these shapes.
90   // aggressive_shape_inference option executes nodes on the host to identify
91   // output values when possible and does other aggressive strategies.
92   // Similar to assuming_valid_feeds, this may cause incorrectness in graph
93   // analyses, but is useful for simulation or scheduling.
94   // If include_input_tensor_values is true, the values of constant tensors
95   // will included in the input properties.
96   // If include_output_tensor_values is true, the values of constant tensors
97   // will be included in the output properties.
98   Status InferStatically(bool assume_valid_feeds,
99                          bool aggressive_shape_inference,
100                          bool include_input_tensor_values,
101                          bool include_output_tensor_values);
InferStatically(bool assume_valid_feeds,bool aggressive_shape_inference,bool include_tensor_values)102   Status InferStatically(bool assume_valid_feeds,
103                          bool aggressive_shape_inference,
104                          bool include_tensor_values) {
105     return InferStatically(
106         assume_valid_feeds,
107         /*aggressive_shape_inference=*/aggressive_shape_inference,
108         /*include_input_tensor_values=*/include_tensor_values,
109         /*include_output_tensor_values=*/include_tensor_values);
110   }
InferStatically(bool assume_valid_feeds)111   Status InferStatically(bool assume_valid_feeds) {
112     return InferStatically(assume_valid_feeds,
113                            /*aggressive_shape_inference=*/false,
114                            /*include_tensor_values=*/true);
115   }
116   // Infer the shape by running the graph on the specified cluster and recording
117   // the shapes of the processed tensors.
118   Status InferDynamically(Cluster* cluster);
119   // Extract the properties from a cost graph. For testing only since there is
120   // no way to ensure that the cost graph match the item.
121   Status InferFromCostGraph(const CostGraphDef& cost_graph);
122 
123   // Stores `item_.graph` with the inferred output shapes to `output_graph_def`.
124   Status AnnotateOutputShapes(GraphDef* output_graph_def,
125                               bool allow_symbolic_shapes) const;
126 
AnnotateOutputShapes(GraphDef * output_graph_def)127   Status AnnotateOutputShapes(GraphDef* output_graph_def) const {
128     return AnnotateOutputShapes(output_graph_def, false);
129   }
130 
131   // Return the properties of node inputs/outputs, including data types and
132   // shapes. Note that the dimensions in the shapes can be negative. We use the
133   // -1 value to denote that we don't know anything about a dimension. We use
134   // values strictly less than -1 to encode symbolic dimensions: although we
135   // don't know the actual value of the symbolic dimension, we know that all the
136   // dimensions denoted by the same negative value are the equal.
137   bool HasInputProperties(const string& node_name) const;
138   bool HasOutputProperties(const string& node_name) const;
139   const std::vector<OpInfo::TensorProperties>& GetInputProperties(
140       const string& node_name) const;
141   const std::vector<OpInfo::TensorProperties>& GetOutputProperties(
142       const string& node_name) const;
143 
144   // Invalidate input/output properties for nodes modified during graph
145   // optimization pass, to prevent potential optimizations, based on incorrect
146   // shape information.
147   void ClearInputProperties(const string& node_name);
148   void ClearOutputProperties(const string& node_name);
149   // Returns true if we have *any* properties.
has_properties()150   bool has_properties() const {
151     return !input_properties_.empty() || !output_properties_.empty();
152   }
153 
CheckShapeIncompatible(const string & node_name)154   bool CheckShapeIncompatible(const string& node_name) const {
155     return incompatible_shape_nodes_.find(node_name) !=
156            incompatible_shape_nodes_.end();
157   }
158 
159  private:
160   // Relaxes shapes <shapes_and_types>, determined from an EnqueueV2 node, into
161   // <*queue_shapes_and_types>.
162   static Status RelaxEnqueueShapesAndMergeTypes(
163       SymbolicShapeRefiner* shape_refiner, const NodeDef* qnode,
164       const std::vector<shape_inference::ShapeAndType>& shapes_and_types,
165       std::vector<shape_inference::ShapeAndType>* queue_shapes_and_types);
166 
167   // Update the shapes of the enqueue node, port them over to the corresponding
168   // queue, and schedule the reprocessing of the queue if needed.
169   static Status UpdateEnqueue(
170       const NodeDef* enqueue_node,
171       const std::unordered_map<const NodeDef*, const NodeDef*>&
172           resource_handles,
173       SymbolicShapeRefiner* shape_refiner, bool* new_shapes);
174 
175   // Update the shapes and types of the Queue node, if not set by Enqueue node.
176   static Status UpdateQueue(const NodeDef* queue_node,
177                             SymbolicShapeRefiner* shape_refiner,
178                             bool* new_shapes);
179 
180   // Update the output shapes of a Merge node, and enqueue its fanout in
181   // new_shapes if needed.
182   Status UpdateMerge(SymbolicShapeRefiner* shape_refiner, const NodeDef* node,
183                      bool* new_shapes) const;
184   // Process the Enter node, and enqueue its fanout in new_shapes if needed.
185   static Status UpdateEnter(SymbolicShapeRefiner* shape_refiner,
186                             const NodeDef* node, bool* new_shapes);
187   // Update the shapes for node 'n'. If output shapes for n have changed,
188   // enqueue its fanout in 'new_shapes'.
189   Status UpdateShapes(SymbolicShapeRefiner* shape_refiner,
190                       const std::unordered_map<const NodeDef*, const NodeDef*>&
191                           resource_handles,
192                       const NodeDef* n, bool* new_shapes) const;
193   // Propagate the shapes for the nodes enqueued in new_shapes and their
194   // transitive fanout until a fixed point is reached.
195   Status PropagateShapes(
196       SymbolicShapeRefiner* shape_refiner, TopoQueue* new_shapes,
197       const std::unordered_map<const NodeDef*, const NodeDef*>&
198           resource_handles,
199       int num_loops) const;
200 
201   // Data members
202   const GrapplerItem& item_;
203   std::unordered_map<string, std::vector<OpInfo::TensorProperties>>
204       input_properties_;
205   std::unordered_map<string, std::vector<OpInfo::TensorProperties>>
206       output_properties_;
207   const std::vector<OpInfo::TensorProperties> missing_properties_;
208 
209   // Nodes with output shape incompatible between shape inference and
210   // annotation.
211   std::unordered_set<string> incompatible_shape_nodes_;
212 };
213 
214 }  // end namespace grappler
215 }  // end namespace tensorflow
216 
217 #endif  // TENSORFLOW_CORE_GRAPPLER_COSTS_GRAPH_PROPERTIES_H_
218