tensorflow/compiler/tf2xla/graph_compiler_util.cc
// Each feed id identifies the positional output of some node, which may consist
// of multiple edges. AddPlaceholdersForFeeds has already replaced each fed
// tensor with a placeholder.  For each feed tensor, replaces all edges so they
// point from a new _Arg node instead. The newly created _Arg nodes are added to
// `arg_nodes`.
Each feed id identifies the positional output of some node, which may consist
of multiple edges. AddPlaceholdersForFeeds has already replaced each fed
tensor with a placeholder.  For each feed tensor, replaces all edges so they
point from a new _Arg node instead. The newly created _Arg nodes are added to
`arg_nodes`.
Each feed id identifies the positional output of some node which may consist of multiple edges . AddPlaceholdersForFeeds has already replaced each fed tensor with a placeholder . For each feed tensor replaces all edges so they point from a new _Arg node instead . The newly created _Arg nodes are added to ` arg_nodes ` .
Status AddArgNodes(Graph* graph, const NodeMap& node_map,
                   const protobuf::RepeatedPtrField<tf2xla::Feed>& feeds,
                   const std::unordered_map<string, string>& feed_remapping,
                   std::unordered_set<const Node*>* arg_nodes) {
  for (int arg_index = 0; arg_index < feeds.size(); ++arg_index) {
    const tf2xla::Feed& feed = feeds[arg_index];
    const int output_index = 0;
    const string key = TensorIdToString(feed.id());
    const auto remap_it = feed_remapping.find(key);
    auto node_it = node_map.find(remap_it->second);
    if (node_it == node_map.end()) {
      absl::string_view name(remap_it->second);
      const auto index = name.find('/');
      if (index > 0) name.remove_prefix(index + 1);
      return errors::InvalidArgument(
          "Node is fed but not needed for fetching: ", name);
    }
    const Node* feed_node = node_it->second;
    Node* arg_node = nullptr;
    TF_RETURN_IF_ERROR(
        NodeBuilder(
            absl::StrCat("_arg_", arg_index),
            FunctionLibraryDefinition::FunctionLibraryDefinition::kArgOp)
            .Attr("T", BaseType(feed_node->output_type(output_index)))
            .Attr("index", arg_index)
            .Attr(kFeedIdAttr, TensorIdToString(feed.id()))
            .Attr(kShapeAttr, TensorShape(feed.shape()))
            .Attr(kDebugNameAttr, feed.name())
            .Finalize(graph, &arg_node));
    arg_nodes->insert(arg_node);
     We must collect the edges first and process them in a second pass, since
     removing the edge from the graph invalidates feed_node->out_edges.
    std::vector<const Edge*> feed_edges;
    for (const Edge* edge : feed_node->out_edges()) {
      if (edge->src_output() == output_index) {
        feed_edges.push_back(edge);
      }
    }
    for (const Edge* edge : feed_edges) {
      graph->AddEdge(arg_node, 0, edge->dst(), edge->dst_input());
      graph->RemoveEdge(edge);
    }
  }
  return Status::OK();
}
Status AddArgNodes ( Graph * graph , const NodeMap & node_map , const protobuf :: RepeatedPtrField < tf2xla :: Feed > & feeds , const std :: unordered_map < string , string > & feed_remapping , std :: unordered_set < const Node * > * arg_nodes ) { for ( int arg_index = 0 ; arg_index < feeds . size ( ) ; ++ arg_index ) { const tf2xla :: Feed & feed = feeds [ arg_index ] ; const int output_index = 0 ; const string key = TensorIdToString ( feed . id ( ) ) ; const auto remap_it = feed_remapping . find ( key ) ; auto node_it = node_map . find ( remap_it -> second ) ; if ( node_it == node_map . end ( ) ) { absl :: string_view name ( remap_it -> second ) ; const auto index = name . find ( ' ' ) ; if ( index > 0 ) name . remove_prefix ( index + 1 ) ; return errors :: InvalidArgument ( " " , name ) ; } const Node * feed_node = node_it -> second ; Node * arg_node = nullptr ; TF_RETURN_IF_ERROR ( NodeBuilder ( absl :: StrCat ( " " , arg_index ) , FunctionLibraryDefinition :: FunctionLibraryDefinition :: kArgOp ) . Attr ( " " , BaseType ( feed_node -> output_type ( output_index ) ) ) . Attr ( " " , arg_index ) . Attr ( kFeedIdAttr , TensorIdToString ( feed . id ( ) ) ) . Attr ( kShapeAttr , TensorShape ( feed . shape ( ) ) ) . Attr ( kDebugNameAttr , feed . name ( ) ) . Finalize ( graph , & arg_node ) ) ; arg_nodes -> insert ( arg_node ) ; std :: vector < const Edge * > feed_edges ; for ( const Edge * edge : feed_node -> out_edges ( ) ) { if ( edge -> src_output ( ) == output_index ) { feed_edges . push_back ( edge ) ; } } for ( const Edge * edge : feed_edges ) { graph -> AddEdge ( arg_node , 0 , edge -> dst ( ) , edge -> dst_input ( ) ) ; graph -> RemoveEdge ( edge ) ; } } return Status :: OK ( ) ; }
Each feed id identifies the positional output of some node, which may consist
of multiple edges.
Each feed id identifies the positional output of some node which may consist of multiple edges .
// All feeds have been replaced by placeholders. // Strip off the aot_feed_#/ prefix. // TODO(toddw): Invoke shape inference in AddPlaceholdersForFeeds and add a // "_shape" attr if we can determine it.  That way the graph will be // initialized with whatever shapes we can infer, while the user can still // explicitly specify or override them. // Collects out-edges from the feed node that have a matching edge index; // these will be replaced with edges from the arg node instead. // // We must collect the edges first and process them in a second pass, since // removing the edge from the graph invalidates feed_node->out_edges.