| 1375 | } // end namespace |
| 1376 | |
| 1377 | bool RemoveIdentityNodes(Graph* g) { |
| 1378 | VLOG(2) << "Removing identity nodes"; |
| 1379 | bool removed_any = false; |
| 1380 | gtl::InlinedVector<Node*, 8> matches; |
| 1381 | for (Node* n : g->nodes()) { |
| 1382 | if (!n->IsIdentity()) continue; |
| 1383 | if (!GetTheOnlyDataEdge(n->in_edges())) continue; |
| 1384 | |
| 1385 | // Some identity nodes are used as sink nodes to give names to output |
| 1386 | // tensors. These nodes are not going to be executed unless they are in the |
| 1387 | // fetch set. But if they are in the fetch set we don't want to remove them. |
| 1388 | if (n->out_edges().empty()) continue; |
| 1389 | |
| 1390 | matches.push_back(n); |
| 1391 | } |
| 1392 | if (!matches.empty()) { |
| 1393 | for (Node* n : matches) { |
| 1394 | const Edge* in = GetTheOnlyDataEdge(n->in_edges()); |
| 1395 | for (const Edge* out : n->out_edges()) { |
| 1396 | if (out->IsControlEdge()) { |
| 1397 | g->AddControlEdge(in->src(), out->dst()); |
| 1398 | } else { |
| 1399 | g->AddEdge(in->src(), in->src_output(), out->dst(), out->dst_input()); |
| 1400 | } |
| 1401 | } |
| 1402 | VLOG(2) << "Remove Identity: " << n->DebugString(); |
| 1403 | g->RemoveNode(n); |
| 1404 | removed_any = true; |
| 1405 | } |
| 1406 | } |
| 1407 | return removed_any; |
| 1408 | } |
| 1409 | |
| 1410 | bool RemoveListArrayConverter(Graph* g) { |
| 1411 | VLOG(2) << "Removing list array converter"; |