19d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 29d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 39d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerLicensed under the Apache License, Version 2.0 (the "License"); 49d57702513001bfded19e72c76a986cce56d5f00Benoit Steineryou may not use this file except in compliance with the License. 59d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerYou may obtain a copy of the License at 69d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 79d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner http://www.apache.org/licenses/LICENSE-2.0 89d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 99d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerUnless required by applicable law or agreed to in writing, software 109d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerdistributed under the License is distributed on an "AS IS" BASIS, 119d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerSee the License for the specific language governing permissions and 139d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerlimitations under the License. 149d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner==============================================================================*/ 159d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 16c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include <unordered_set> 17c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower 1850efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower#include "tensorflow/core/framework/attr_value.pb.h" 19be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner#include "tensorflow/core/framework/op.h" 20c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/framework/types.h" 21c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/grappler/op_types.h" 22c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/grappler/utils.h" 23be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner#include "tensorflow/core/lib/core/status.h" 249d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 259d57702513001bfded19e72c76a986cce56d5f00Benoit Steinernamespace tensorflow { 269d57702513001bfded19e72c76a986cce56d5f00Benoit Steinernamespace grappler { 279d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 2828ee7877a9df4e66f81d31d48b067091726c71abA. Unique TensorFlowerbool IsAdd(const NodeDef& node) { 29481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower if (node.op() == "AddV2" || node.op() == "Add") { 30481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower DataType type = node.attr().at("T").type(); 31481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower return type != DT_STRING; 32481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower } 33481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower return false; 3428ee7877a9df4e66f81d31d48b067091726c71abA. Unique TensorFlower} 351ffb45e7112addad325084084b93897918ed9a54Yao Zhang 36cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAddN(const NodeDef& node) { return node.op() == "AddN"; } 37136494d3295a23e3ed0612773f224243915463b7Benoit Steiner 38d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsAll(const NodeDef& node) { return node.op() == "All"; } 39d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 40ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsAngle(const NodeDef& node) { return node.op() == "Angle"; } 41ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 42d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsAny(const NodeDef& node) { return node.op() == "Any"; } 43d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 44634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlowerbool IsAnyDiv(const NodeDef& node) { 45634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower return node.op() == "RealDiv" || node.op() == "Div" || 46634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower node.op() == "FloorDiv" || node.op() == "TruncateDiv"; 47634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower} 48634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower 49ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsApproximateEqual(const NodeDef& node) { 50ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang return node.op() == "ApproximateEqual"; 51ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang} 52ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 53cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAvgPoolGrad(const NodeDef& node) { return node.op() == "AvgPoolGrad"; } 541ffb45e7112addad325084084b93897918ed9a54Yao Zhang 55cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAssert(const NodeDef& node) { return node.op() == "Assert"; } 561ffb45e7112addad325084084b93897918ed9a54Yao Zhang 57ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsAtan2(const NodeDef& node) { return node.op() == "Atan2"; } 58ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 5932ee432d9674567e80771b070e68e7f565d4fd2cYao Zhangbool IsBetainc(const NodeDef& node) { return node.op() == "Betainc"; } 6032ee432d9674567e80771b070e68e7f565d4fd2cYao Zhang 61b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlowerbool IsBiasAdd(const NodeDef& node) { 62b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower return node.op() == "BiasAdd" || node.op() == "BiasAddV1"; 63b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower} 64b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower 65cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsBiasAddGrad(const NodeDef& node) { return node.op() == "BiasAddGrad"; } 6665044bc25981e4e060ad5c34d9a520a0561775c3Yao Zhang 67ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsBitcast(const NodeDef& node) { return node.op() == "Bitcast"; } 68ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 69fe613b051b5732f06af586f7b4f0ca28121f1eccYao Zhangbool IsCast(const NodeDef& node) { return node.op() == "Cast"; } 70fe613b051b5732f06af586f7b4f0ca28121f1eccYao Zhang 71ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsComplex(const NodeDef& node) { return node.op() == "Complex"; } 72ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 73ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsComplexAbs(const NodeDef& node) { return node.op() == "ComplexAbs"; } 74ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 75cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConcatOffset(const NodeDef& node) { return node.op() == "ConcatOffset"; } 761a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner 77cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConstant(const NodeDef& node) { return node.op() == "Const"; } 78cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower 79ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsConj(const NodeDef& node) { return node.op() == "Conj"; } 80ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 81cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConv2D(const NodeDef& node) { return node.op() == "Conv2D"; } 821ffb45e7112addad325084084b93897918ed9a54Yao Zhang 831ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsConv2DBackpropFilter(const NodeDef& node) { 84cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "Conv2DBackpropFilter"; 851ffb45e7112addad325084084b93897918ed9a54Yao Zhang} 861ffb45e7112addad325084084b93897918ed9a54Yao Zhang 871ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsConv2DBackpropInput(const NodeDef& node) { 88cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "Conv2DBackpropInput"; 891ffb45e7112addad325084084b93897918ed9a54Yao Zhang} 901ffb45e7112addad325084084b93897918ed9a54Yao Zhang 916ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNative(const NodeDef& node) { 92cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "DepthwiseConv2dNative"; 936ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang} 946ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang 956ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNativeBackpropFilter(const NodeDef& node) { 96cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "DepthwiseConv2dNativeBackpropFilter"; 976ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang} 986ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang 996ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNativeBackpropInput(const NodeDef& node) { 100cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "DepthwiseConv2dNativeBackpropInput"; 1016ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang} 1026ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang 1037bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhoubool IsDequeueOp(const NodeDef& node) { 1049ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner const auto& op = node.op(); 1059ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner return op == "QueueDequeueManyV2" || op == "QueueDequeueMany" || 1069ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner op == "QueueDequeueV2" || op == "QueueDequeue" || 1079ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner op == "QueueDequeueUpToV2" || op == "QueueDequeueUpTo"; 1087bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhou} 1097bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhou 110634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlowerbool IsDiv(const NodeDef& node) { return node.op() == "Div"; } 111634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower 112bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsEluGrad(const NodeDef& node) { return node.op() == "EluGrad"; } 113bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 114c247826219dd2541c6aba4578a03a171375d9290Benoit Steinerbool IsEnter(const NodeDef& node) { 115c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner const auto& op = node.op(); 116c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner return op == "Enter" || op == "RefEnter"; 117c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner} 118c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner 119ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsEqual(const NodeDef& node) { return node.op() == "Equal"; } 120ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 121c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhangbool IsExit(const NodeDef& node) { 122c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang const auto& op = node.op(); 123c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang return op == "Exit" || op == "RefExit"; 124c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang} 125c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang 1264b66819917856d5534cecffc02ed495e59fe5953Yao Zhangbool IsFill(const NodeDef& node) { return node.op() == "Fill"; } 1274b66819917856d5534cecffc02ed495e59fe5953Yao Zhang 128ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsFloorDiv(const NodeDef& node) { return node.op() == "FloorDiv"; } 129ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 130cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsFloorMod(const NodeDef& node) { return node.op() == "FloorMod"; } 1311ffb45e7112addad325084084b93897918ed9a54Yao Zhang 132a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhangbool IsFusedBatchNormGrad(const NodeDef& node) { 133a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhang const auto& op = node.op(); 134a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhang return op == "FusedBatchNormGrad" || op == "FusedBatchNormGradV2"; 1351ffb45e7112addad325084084b93897918ed9a54Yao Zhang} 1361ffb45e7112addad325084084b93897918ed9a54Yao Zhang 137ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsGreater(const NodeDef& node) { return node.op() == "Greater"; } 138ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 139ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsGreaterEqual(const NodeDef& node) { return node.op() == "GreaterEqual"; } 140ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 141d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsHistogramSummary(const NodeDef& node) { 142d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang return node.op() == "HistogramSummary"; 143d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang} 144d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 14593c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steinerbool IsIdentity(const NodeDef& node) { 14693c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner const auto& op = node.op(); 147bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner return op == "Identity" || op == "RefIdentity"; 14893c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner} 14993c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner 1501d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhangbool IsIdentityN(const NodeDef& node) { 1511d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang const auto& op = node.op(); 1521d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang return op == "IdentityN"; 1531d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang} 1541d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang 155ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsIgamma(const NodeDef& node) { return node.op() == "Igamma"; } 156ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 157ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsIgammac(const NodeDef& node) { return node.op() == "Igammac"; } 158ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 159ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsImag(const NodeDef& node) { return node.op() == "Imag"; } 160ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 161bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsInvGrad(const NodeDef& node) { return node.op() == "InvGrad"; } 162bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 163ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLess(const NodeDef& node) { return node.op() == "Less"; } 164ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 165ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLessEqual(const NodeDef& node) { return node.op() == "LessEqual"; } 166ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 167ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalAnd(const NodeDef& node) { return node.op() == "LogicalAnd"; } 168ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 169ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalNot(const NodeDef& node) { return node.op() == "LogicalNot"; } 170ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 171ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalOr(const NodeDef& node) { return node.op() == "LogicalOr"; } 172ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 17359ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlowerbool IsMatMul(const NodeDef& node) { 174634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower const auto& op = node.op(); 17559ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower return op == "MatMul" || op == "BatchMatMul" || op == "QuantizedMatMul" || 17659ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower op == "SparseMatMul"; 17759ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower} 17859ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower 179d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMax(const NodeDef& node) { return node.op() == "Max"; } 180d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 181ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMaximum(const NodeDef& node) { return node.op() == "Maximum"; } 182ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 183d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMean(const NodeDef& node) { return node.op() == "Mean"; } 184d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 1851a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steinerbool IsMerge(const NodeDef& node) { 186634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower const auto& op = node.op(); 18768eba33d21f692f6d9fe606d27f99387cac4dd18Benoit Steiner return op == "Merge" || op == "RefMerge"; 1881a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner} 1891a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner 190d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMin(const NodeDef& node) { return node.op() == "Min"; } 191d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 192ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMinimum(const NodeDef& node) { return node.op() == "Minimum"; } 193ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 194e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsMirrorPad(const NodeDef& node) { return node.op() == "MirrorPad"; } 195e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang 196e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsMirrorPadGrad(const NodeDef& node) { 197e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang return node.op() == "MirrorPadGrad"; 198e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang} 199e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang 200ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMod(const NodeDef& node) { return node.op() == "Mod"; } 201ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 202cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsMul(const NodeDef& node) { return node.op() == "Mul"; } 2031ffb45e7112addad325084084b93897918ed9a54Yao Zhang 204cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsNoOp(const NodeDef& node) { return node.op() == "NoOp"; } 2058f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower 206ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsNotEqual(const NodeDef& node) { return node.op() == "NotEqual"; } 207ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 2081fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steinerbool IsNextIteration(const NodeDef& node) { 2091fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner const auto& op = node.op(); 2101fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner return op == "NextIteration" || op == "RefNextIteration"; 2111fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner} 2121fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner 213e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsPad(const NodeDef& node) { 214e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang const auto& op = node.op(); 215e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang return op == "Pad" || op == "PadV2"; 216e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang} 2171ffb45e7112addad325084084b93897918ed9a54Yao Zhang 2189d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerbool IsPlaceholder(const NodeDef& node) { 219634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower const auto& op = node.op(); 220b09932d749cdd8a9a78180820091dac924d18b8dBenoit Steiner return op == "Placeholder" || op == "PlaceholderV2" || 221b09932d749cdd8a9a78180820091dac924d18b8dBenoit Steiner op == "PlaceholderWithDefault"; 2229d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner} 2239d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner 224ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsPolygamma(const NodeDef& node) { return node.op() == "Polygamma"; } 225ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 226ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsPow(const NodeDef& node) { return node.op() == "Pow"; } 227ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 228d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsProd(const NodeDef& node) { return node.op() == "Prod"; } 229d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang 230ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsReal(const NodeDef& node) { return node.op() == "Real"; } 231ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 232cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsRealDiv(const NodeDef& node) { return node.op() == "RealDiv"; } 2331ffb45e7112addad325084084b93897918ed9a54Yao Zhang 234bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsReciprocalGrad(const NodeDef& node) { 235bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang return node.op() == "ReciprocalGrad"; 236bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang} 2371ffb45e7112addad325084084b93897918ed9a54Yao Zhang 238cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlowerbool IsRecv(const NodeDef& node) { 239cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower return node.op() == "_Recv" || node.op() == "_HostRecv"; 240cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower} 2418f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower 2429ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steinerbool IsReduction(const NodeDef& node) { 2439ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner const auto& op = node.op(); 2449ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner return op == "Sum" || op == "Prod" || op == "Min" || op == "Max" || 2459ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner op == "Mean" || op == "Any" || op == "All"; 2469ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner} 2479ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner 248bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsReluGrad(const NodeDef& node) { return node.op() == "ReluGrad"; } 249bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 250bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsRelu6Grad(const NodeDef& node) { return node.op() == "Relu6Grad"; } 251bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 25259d37536717f08dd6e462ed785ee0e912ff344f5Benoit Steinerbool IsReshape(const NodeDef& node) { return (node.op() == "Reshape"); } 25359d37536717f08dd6e462ed785ee0e912ff344f5Benoit Steiner 25438445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhoubool IsRestore(const NodeDef& node) { 25538445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou return (node.op() == "Restore" || node.op() == "RestoreV2" || 25638445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou node.op() == "RestoreSlice"); 25738445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou} 25838445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou 2597989a3aa026f93c1f45e1baf4ac37ad2a79156f9A. Unique TensorFlowerbool IsReverseV2(const NodeDef& node) { return node.op() == "ReverseV2"; } 2607989a3aa026f93c1f45e1baf4ac37ad2a79156f9A. Unique TensorFlower 261bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsRsqrtGrad(const NodeDef& node) { return node.op() == "RsqrtGrad"; } 262bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 26332ee432d9674567e80771b070e68e7f565d4fd2cYao Zhangbool IsSelect(const NodeDef& node) { return node.op() == "Select"; } 26432ee432d9674567e80771b070e68e7f565d4fd2cYao Zhang 265bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSeluGrad(const NodeDef& node) { return node.op() == "SeluGrad"; } 266bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 267cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlowerbool IsSend(const NodeDef& node) { 268cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower return node.op() == "_Send" || node.op() == "_HostSend"; 269cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower} 2708f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower 271ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhangbool IsShape(const NodeDef& node) { return node.op() == "Shape"; } 272ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhang 273ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhangbool IsShapeN(const NodeDef& node) { return node.op() == "ShapeN"; } 274ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhang 275bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSigmoidGrad(const NodeDef& node) { return node.op() == "SigmoidGrad"; } 276bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 277cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSlice(const NodeDef& node) { return node.op() == "Slice"; } 2781ffb45e7112addad325084084b93897918ed9a54Yao Zhang 279bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSoftplusGrad(const NodeDef& node) { return node.op() == "SoftplusGrad"; } 280bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 281bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSoftsignGrad(const NodeDef& node) { return node.op() == "SoftsignGrad"; } 282bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 2836c5ccadd434f2e6ed9634031bac2682c3dfe5216Yao Zhangbool IsSplit(const NodeDef& node) { return node.op() == "Split"; } 2846c5ccadd434f2e6ed9634031bac2682c3dfe5216Yao Zhang 285fa96f2595fa073a6bc943dfabea6852d41a706a3Yao Zhangbool IsSplitV(const NodeDef& node) { return node.op() == "SplitV"; } 286fa96f2595fa073a6bc943dfabea6852d41a706a3Yao Zhang 287bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSqrtGrad(const NodeDef& node) { return node.op() == "SqrtGrad"; } 288bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 2891ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsSquaredDifference(const NodeDef& node) { 290cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower return node.op() == "SquaredDifference"; 2911ffb45e7112addad325084084b93897918ed9a54Yao Zhang} 2921ffb45e7112addad325084084b93897918ed9a54Yao Zhang 293cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSqueeze(const NodeDef& node) { return node.op() == "Squeeze"; } 2941ffb45e7112addad325084084b93897918ed9a54Yao Zhang 295bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steinerbool IsStopGradient(const NodeDef& node) { 296bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner const auto& op = node.op(); 297bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner return op == "StopGradient" || op == "PreventGradient"; 298bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner} 299bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner 300834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhangbool IsStridedSlice(const NodeDef& node) { return node.op() == "StridedSlice"; } 301834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang 302834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhangbool IsStridedSliceGrad(const NodeDef& node) { 303834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang return node.op() == "StridedSliceGrad"; 304834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang} 305834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang 306cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSub(const NodeDef& node) { return node.op() == "Sub"; } 3071ffb45e7112addad325084084b93897918ed9a54Yao Zhang 308cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSum(const NodeDef& node) { return node.op() == "Sum"; } 3091ffb45e7112addad325084084b93897918ed9a54Yao Zhang 31093c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steinerbool IsSwitch(const NodeDef& node) { 31193c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner const auto& op = node.op(); 31268eba33d21f692f6d9fe606d27f99387cac4dd18Benoit Steiner return op == "Switch" || op == "RefSwitch"; 31393c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner} 31493c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner 315bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsTanhGrad(const NodeDef& node) { return node.op() == "TanhGrad"; } 316bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang 31758a77fad5539454e674629d45df569af35453b02Yao Zhangbool IsTile(const NodeDef& node) { return node.op() == "Tile"; } 31858a77fad5539454e674629d45df569af35453b02Yao Zhang 319cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsTranspose(const NodeDef& node) { return node.op() == "Transpose"; } 32065044bc25981e4e060ad5c34d9a520a0561775c3Yao Zhang 321ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsTruncateDiv(const NodeDef& node) { return node.op() == "TruncateDiv"; } 322ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 323ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsTruncateMod(const NodeDef& node) { return node.op() == "TruncateMod"; } 324ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 3254254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steinerbool IsVariable(const NodeDef& node) { 326cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower const auto& op = node.op(); 3276fede95a1bbf11349a1c44fd1b85ac326cb43915Benoit Steiner return op == "Variable" || op == "VariableV2" || op == "AutoReloadVariable" || 32838445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou op == "VarHandleOp" || op == "ReadVariableOp"; 3294254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steiner} 3304254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steiner 331ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsZeta(const NodeDef& node) { return node.op() == "Zeta"; } 332ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang 33350efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlowernamespace { 33450efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlowerbool GetBoolAttr(const NodeDef& node, const string& name) { 33550efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower return node.attr().count(name) > 0 && node.attr().at(name).b(); 33650efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower} 33750efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower} // namespace 33850efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower 3392f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steinerbool IsPersistent(const NodeDef& node) { 3402f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner return IsConstant(node) || IsVariable(node); 3412f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner} 3422f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner 343be4295e796437d18ffb7242942c963a8857e5003Benoit Steinerbool IsFreeOfSideEffect(const NodeDef& node) { 344be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner // Placeholders must be preserved to keep the graph feedable. 345be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner if (IsPlaceholder(node)) { 346be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return false; 347be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner } 348be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner const OpDef* op_def = nullptr; 349be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner Status status = OpRegistry::Global()->LookUpOpDef(node.op(), &op_def); 350be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner if (!status.ok()) { 351be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return false; 352be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner } 353be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner if (op_def->is_stateful()) { 354be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return false; 355be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner } 356be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner // Nodes such as Assign or AssignAdd modify one of their inputs. 357be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner for (const auto& input : op_def->input_arg()) { 358be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner if (input.is_ref()) { 359be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return false; 360be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner } 361be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner } 36250efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower // Some nodes do in-place updates on regular tensor inputs. 36350efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower if (GetBoolAttr(node, "in_place") || GetBoolAttr(node, "inplace")) { 36450efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower return false; 36550efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower } 366be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return true; 367be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner} 368be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner 369be4295e796437d18ffb7242942c963a8857e5003Benoit Steinerbool ModifiesFrameInfo(const NodeDef& node) { 370be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner return IsEnter(node) || IsExit(node) || IsNextIteration(node); 371be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner} 372be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner 373c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#define OPDEF_PROPERTY_HELPER(PROPERTY_CAP, PROPERTY) \ 374c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower bool Is##PROPERTY_CAP(const NodeDef& node) { \ 375c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower if (node.op() == "Add") { \ 376c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower /* Workaround for "Add" not being marked is_commutative and */ \ 377c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower /* is_aggregate. (See cl/173915048). */ \ 378c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower const auto type = GetDataTypeFromAttr(node, "T"); \ 379c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower return type != DT_INVALID && type != DT_STRING; \ 380c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower } \ 381c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower const OpDef* op_def = nullptr; \ 382c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower Status status = OpRegistry::Global()->LookUpOpDef(node.op(), &op_def); \ 383c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower return status.ok() && op_def->is_##PROPERTY(); \ 384c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower } 385c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower 386c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerOPDEF_PROPERTY_HELPER(Aggregate, aggregate) 387c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerOPDEF_PROPERTY_HELPER(Commutative, commutative) 388c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower 389c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerbool IsInvolution(const NodeDef& node) { 390c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower const std::unordered_set<string> involution_ops{ 391c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower "Conj", "Reciprocal", "Invert", "Neg", "LogicalNot"}; 392c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower return involution_ops.count(node.op()) > 0; 393c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower} 394c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower 395c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerbool IsValuePreserving(const NodeDef& node) { 396c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower if (NumNonControlInputs(node) == 1 && IsAggregate(node)) { 397c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower return true; 398c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower } 399c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower const std::unordered_set<string> value_preserving_ops{ 400c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower "Transpose", "Reshape", "Identity", "InvertPermutation", 401c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower "Reverse", "StopGradient", "PreventGradient", "CheckNumerics", 402c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower "ExpandDims", "Squeeze"}; 403c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower return value_preserving_ops.count(node.op()) > 0; 404c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower} 405c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower 406fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlowerbool HasOpDef(const NodeDef& node) { 407fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower const OpDef* op_def = nullptr; 408fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower return OpRegistry::Global()->LookUpOpDef(node.op(), &op_def).ok(); 409fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower} 410fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower 411c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower} // namespace grappler 4129d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner} // end namespace tensorflow 413