| 235 | } |
| 236 | |
| 237 | Status ShapeRefiner::AddNode(const Node* node) { |
| 238 | // For each 'input' of this node, fetch the corresponding shape |
| 239 | // from 'input's InferenceContext, and store into a vector |
| 240 | // indexed by 'node's input. |
| 241 | std::vector<const Node*> input_nodes(node->num_inputs()); |
| 242 | std::vector<ShapeHandle> input_shapes(node->num_inputs()); |
| 243 | std::vector<std::unique_ptr<std::vector<ShapeAndType>>> |
| 244 | input_handle_shapes_and_types(node->num_inputs()); |
| 245 | std::vector<bool> inputs_missing_context(node->num_inputs()); |
| 246 | for (const Edge* e : node->in_edges()) { |
| 247 | if (e->IsControlEdge()) continue; |
| 248 | |
| 249 | if (e->dst_input() < 0) { |
| 250 | return tensorflow::errors::Internal( |
| 251 | "Index ", e->dst_input(), " is negative but not a control edge."); |
| 252 | } |
| 253 | |
| 254 | const Node* input = e->src(); |
| 255 | auto it = node_to_context_.find(input); |
| 256 | if (it == node_to_context_.end()) { |
| 257 | // v1 control flow adds loops to the graph; we have to break them |
| 258 | // somewhere, so we'll ignore this input and leave its shape undefined. |
| 259 | input_nodes[e->dst_input()] = input; |
| 260 | // We don't have a context yet. We'll make one below and use that to |
| 261 | // generate an unknown shape. An uninitialized ShapeHandle is already an |
| 262 | // unknown shape, but there are debug checks that each input was |
| 263 | // explicitly set and satisfying them isn't very costly. |
| 264 | inputs_missing_context[e->dst_input()] = true; |
| 265 | continue; |
| 266 | } |
| 267 | |
| 268 | InferenceContext* c = it->second->get_context(); |
| 269 | input_nodes[e->dst_input()] = input; |
| 270 | input_shapes[e->dst_input()] = c->output(e->src_output()); |
| 271 | |
| 272 | const auto* in_v = c->output_handle_shapes_and_types(e->src_output()); |
| 273 | if (in_v != nullptr) { |
| 274 | DataType input_type = e->src()->output_type(e->src_output()); |
| 275 | DCHECK(input_type == DT_RESOURCE || input_type == DT_VARIANT); |
| 276 | input_handle_shapes_and_types[e->dst_input()].reset( |
| 277 | new std::vector<ShapeAndType>(*in_v)); |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | // Get the shape function for this node |
| 282 | const OpRegistrationData* op_reg_data; |
| 283 | TF_RETURN_IF_ERROR(ops_registry_->LookUp(node->type_string(), &op_reg_data)); |
| 284 | if (op_reg_data->shape_inference_fn == nullptr && |
| 285 | require_shape_inference_fns_) { |
| 286 | return errors::InvalidArgument( |
| 287 | "No shape inference function exists for op '", node->type_string(), |
| 288 | "', did you forget to define it?"); |
| 289 | } |
| 290 | |
| 291 | // This needs to be filled in with real data in a second pass. |
| 292 | std::vector<const Tensor*> input_tensors(node->num_inputs(), nullptr); |
| 293 | std::vector<ShapeHandle> input_tensors_as_shapes; |
| 294 | |