| 662 | } |
| 663 | |
| 664 | Status ShapeRefiner::RunShapeFn(const Node* node, |
| 665 | const OpRegistrationData* op_reg_data, |
| 666 | ExtendedInferenceContext* ec) { |
| 667 | // This will be filled in with real data in a second pass. |
| 668 | std::vector<const Tensor*> input_tensors(node->num_inputs(), nullptr); |
| 669 | std::vector<Tensor> real_tensors(node->num_inputs()); |
| 670 | std::vector<bool> attempted_materialization(node->num_inputs()); |
| 671 | std::vector<bool> attempted_tensor_as_shape_conversion(node->num_inputs()); |
| 672 | std::vector<ShapeHandle> input_tensors_as_shapes; |
| 673 | |
| 674 | auto* c = ec->get_context(); |
| 675 | |
| 676 | c->set_input_tensors(input_tensors); |
| 677 | c->set_input_tensors_as_shapes(input_tensors_as_shapes); |
| 678 | |
| 679 | // Run the shape inference function, and return if there was an error. |
| 680 | // Capture as lambda, because we might need to re-run inference later on. |
| 681 | auto run_inference_lambda = [&]() { |
| 682 | if (function_library_ && IsFunctionCall(*function_library_, *node)) { |
| 683 | bool disable_shape_inference; |
| 684 | if (!GetNodeAttr(AttrSlice(node->def()), "_disable_call_shape_inference", |
| 685 | &disable_shape_inference) |
| 686 | .ok() || |
| 687 | !disable_shape_inference) { |
| 688 | // Special inference logic for user-defined functions. |
| 689 | NameAttrList function; |
| 690 | TF_RETURN_IF_ERROR( |
| 691 | NameAndAttrsFromFunctionCall(node->def(), &function)); |
| 692 | const FunctionDef* function_def = |
| 693 | function_library_->Find(function.name()); |
| 694 | if (function_def != nullptr) { |
| 695 | // The constant Tensor map we have for the outside context is not |
| 696 | // valid inside the function. We need to push a new clean map while |
| 697 | // performing inference on the function body. |
| 698 | auto const_tensor_map_copy = const_tensor_map_; |
| 699 | const_tensor_map_.clear(); |
| 700 | Status function_inference_status = |
| 701 | InferShapesForFunction(function_def, AttrSlice(&function.attr()), |
| 702 | keep_nested_shape_inferences_, ec); |
| 703 | const_tensor_map_ = const_tensor_map_copy; |
| 704 | return function_inference_status; |
| 705 | } |
| 706 | } |
| 707 | } |
| 708 | |
| 709 | if (op_reg_data->shape_inference_fn) { |
| 710 | TF_RETURN_IF_ERROR(c->Run(op_reg_data->shape_inference_fn)); |
| 711 | } else { |
| 712 | TF_RETURN_IF_ERROR(c->Run(shape_inference::UnknownShape)); |
| 713 | } |
| 714 | return Status::OK(); |
| 715 | }; |
| 716 | TF_RETURN_IF_ERROR(run_inference_lambda()); |
| 717 | |
| 718 | // We must run the shape function repeatedly, in case users write |
| 719 | // shape functions where they only conditionally call input_tensor() |
| 720 | // based on the values of another input tensor. |
| 721 | bool rerun_shape_fn; |
nothing calls this directly
no test coverage detected