From 5250b2e620674eeb2fe1214028a16961a3e33343 Mon Sep 17 00:00:00 2001 From: Thai Nguyen Date: Sun, 31 Jan 2021 22:24:50 -0800 Subject: [PATCH] Add document about alllowed TensorFlow ops in TFLite PiperOrigin-RevId: 354870341 Change-Id: Ib10eb841f86fe9211b041b9f91450534cefa0aee --- .../delegates/flex/allowlisted_flex_ops.cc | 9 + tensorflow/lite/g3doc/_book.yaml | 2 + .../lite/g3doc/guide/op_select_allowlist.md | 752 ++++++++++++++++++ tensorflow/lite/g3doc/guide/ops_select.md | 12 +- 4 files changed, 768 insertions(+), 7 deletions(-) create mode 100644 tensorflow/lite/g3doc/guide/op_select_allowlist.md diff --git a/tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc b/tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc index 2683679be5d..77c8da50f66 100644 --- a/tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc +++ b/tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc @@ -23,6 +23,7 @@ namespace tflite { namespace flex { const std::set& GetFlexAllowlist() { + // LINT.IfChange static const std::set* allowlisted_flex_ops = new std::set({ // go/keep-sorted start @@ -705,6 +706,8 @@ const std::set& GetFlexAllowlist() { "_VarHandlesOp", // go/keep-sorted end }); + // LINT.ThenChange(//tensorflow/lite/g3doc/guide/op_select_allowlist.md) + return *allowlisted_flex_ops; // Prevent lint error about this function being too long. This function // is a set of ops, and making it shorter won't help readbility. @@ -713,6 +716,7 @@ const std::set& GetFlexAllowlist() { // Allow the tf.text ops if they are registered in the global op registry. bool IsAllowedTFTextOpForFlex(const std::string& op_name) { + // LINT.IfChange static const std::set* tftext_flex_ops = new std::set({ "CaseFoldUTF8", @@ -733,12 +737,15 @@ bool IsAllowedTFTextOpForFlex(const std::string& op_name) { "WhitespaceTokenizeWithOffsets", "WordpieceTokenizeWithOffsets", }); + // LINT.ThenChange(//tensorflow/lite/g3doc/guide/op_select_allowlist.md) + if (tftext_flex_ops->count(op_name) == 0) return false; return tensorflow::OpRegistry::Global()->LookUp(op_name) != nullptr; } // Allow the sentencepiece ops if they are registered in the global op registry. bool IsAllowedSentencePieceOpForFlex(const std::string& op_name) { + // LINT.IfChange static const std::set* sentencepiece_flex_ops = new std::set({ "SentencepieceGetPieceSize", @@ -748,6 +755,8 @@ bool IsAllowedSentencePieceOpForFlex(const std::string& op_name) { "SentencepieceEncodeSparse", "SentencepieceDecode", }); + // LINT.ThenChange(//tensorflow/lite/g3doc/guide/op_select_allowlist.md) + if (sentencepiece_flex_ops->count(op_name) == 0) return false; return tensorflow::OpRegistry::Global()->LookUp(op_name) != nullptr; } diff --git a/tensorflow/lite/g3doc/_book.yaml b/tensorflow/lite/g3doc/_book.yaml index 89644d4324d..a0f40ee6767 100644 --- a/tensorflow/lite/g3doc/_book.yaml +++ b/tensorflow/lite/g3doc/_book.yaml @@ -106,6 +106,8 @@ upper_tabs: - title: "Operator versions" path: /lite/guide/ops_version status: experimental + - title: "Select operators Allowlist" + path: /lite/guide/op_select_allowlist - heading: "Run Inference with metadata" - title: "Overview" diff --git a/tensorflow/lite/g3doc/guide/op_select_allowlist.md b/tensorflow/lite/g3doc/guide/op_select_allowlist.md new file mode 100644 index 00000000000..2de1c364bec --- /dev/null +++ b/tensorflow/lite/g3doc/guide/op_select_allowlist.md @@ -0,0 +1,752 @@ +# Supported Select TensorFlow operators + +Caution: The operators list is updated frequently. + +## TensorFlow core operators + +The following is an exhaustive list of TensorFlow core operations that are +supported by TensorFlow Lite runtime with the Select TensorFlow Ops feature. + +* `raw_ops.Abort` +* `raw_ops.Abs` +* `raw_ops.Add` +* `raw_ops.AddN` +* `raw_ops.AddV2` +* `raw_ops.AdjustContrast` +* `raw_ops.AdjustContrastv2` +* `raw_ops.AdjustHue` +* `raw_ops.AdjustSaturation` +* `raw_ops.All` +* `raw_ops.Angle` +* `raw_ops.Any` +* `raw_ops.ApplyAdaMax` +* `raw_ops.ApplyAdadelta` +* `raw_ops.ApplyAdagrad` +* `raw_ops.ApplyAdagradDA` +* `raw_ops.ApplyAdagradV2` +* `raw_ops.ApplyAdam` +* `raw_ops.ApplyAddSign` +* `raw_ops.ApplyCenteredRMSProp` +* `raw_ops.ApplyFtrl` +* `raw_ops.ApplyFtrlV2` +* `raw_ops.ApplyGradientDescent` +* `raw_ops.ApplyMomentum` +* `raw_ops.ApplyPowerSign` +* `raw_ops.ApplyProximalAdagrad` +* `raw_ops.ApplyProximalGradientDescent` +* `raw_ops.ApplyRMSProp` +* `raw_ops.ApproximateEqual` +* `raw_ops.ArgMax` +* `raw_ops.ArgMin` +* `raw_ops.Assert` +* `raw_ops.Assign` +* `raw_ops.AssignAdd` +* `raw_ops.AssignAddVariableOp` +* `raw_ops.AssignSub` +* `raw_ops.AssignSubVariableOp` +* `raw_ops.AssignVariableOp` +* `raw_ops.Atan` +* `raw_ops.Atan2` +* `raw_ops.AudioSpectrogram` +* `raw_ops.AvgPool` +* `raw_ops.AvgPool3D` +* `raw_ops.AvgPool3DGrad` +* `raw_ops.AvgPoolGrad` +* `raw_ops.BatchCholesky` +* `raw_ops.BatchMatMul` +* `raw_ops.BatchMatMulV2` +* `raw_ops.BatchMatrixDiag` +* `raw_ops.BatchMatrixDiagPart` +* `raw_ops.BatchMatrixInverse` +* `raw_ops.BatchMatrixSetDiag` +* `raw_ops.BatchMatrixTriangularSolve` +* `raw_ops.BatchNormWithGlobalNormalization` +* `raw_ops.BatchNormWithGlobalNormalizationGrad` +* `raw_ops.BatchToSpace` +* `raw_ops.BatchToSpaceND` +* `raw_ops.BiasAdd` +* `raw_ops.BiasAddGrad` +* `raw_ops.BiasAddV1` +* `raw_ops.Bincount` +* `raw_ops.Bitcast` +* `raw_ops.BitwiseAnd` +* `raw_ops.BitwiseOr` +* `raw_ops.BitwiseXor` +* `raw_ops.BoostedTreesBucketize` +* `raw_ops.BoostedTreesCreateQuantileStreamResource` +* `raw_ops.BoostedTreesFlushQuantileSummaries` +* `raw_ops.BoostedTreesMakeQuantileSummaries` +* `raw_ops.BoostedTreesQuantileStreamResourceAddSummaries` +* `raw_ops.BoostedTreesQuantileStreamResourceDeserialize` +* `raw_ops.BoostedTreesQuantileStreamResourceFlush` +* `raw_ops.BoostedTreesQuantileStreamResourceGetBucketBoundaries` +* `raw_ops.BoostedTreesQuantileStreamResourceHandleOp` +* `raw_ops.BroadcastArgs` +* `raw_ops.BroadcastGradientArgs` +* `raw_ops.BroadcastTo` +* `raw_ops.Bucketize` +* `raw_ops.CTCBeamSearchDecoder` +* `raw_ops.CTCGreedyDecoder` +* `raw_ops.Cast` +* `raw_ops.Ceil` +* `raw_ops.CheckNumerics` +* `raw_ops.CheckNumericsV2` +* `raw_ops.Cholesky` +* `raw_ops.CombinedNonMaxSuppression` +* `raw_ops.Complex` +* `raw_ops.ComplexAbs` +* `raw_ops.Concat` +* `raw_ops.ConcatOffset` +* `raw_ops.ConcatV2` +* `raw_ops.Conj` +* `raw_ops.ConjugateTranspose` +* `raw_ops.Const` +* `raw_ops.ControlTrigger` +* `raw_ops.Conv2D` +* `raw_ops.Conv2DBackpropFilter` +* `raw_ops.Conv2DBackpropInput` +* `raw_ops.Conv3D` +* `raw_ops.Conv3DBackpropFilter` +* `raw_ops.Conv3DBackpropFilterV2` +* `raw_ops.Conv3DBackpropInput` +* `raw_ops.Conv3DBackpropInputV2` +* `raw_ops.Cos` +* `raw_ops.Cosh` +* `raw_ops.CropAndResize` +* `raw_ops.CropAndResizeGradBoxes` +* `raw_ops.CropAndResizeGradImage` +* `raw_ops.Cumprod` +* `raw_ops.Cumsum` +* `raw_ops.CumulativeLogsumexp` +* `raw_ops.DataFormatDimMap` +* `raw_ops.DataFormatVecPermute` +* `raw_ops.DebugGradientIdentity` +* `raw_ops.DebugGradientRefIdentity` +* `raw_ops.DecodeAndCropJpeg` +* `raw_ops.DecodeBase64` +* `raw_ops.DecodeBmp` +* `raw_ops.DecodeGif` +* `raw_ops.DecodeImage` +* `raw_ops.DecodeJpeg` +* `raw_ops.DecodePng` +* `raw_ops.DecodeRaw` +* `raw_ops.DecodeWav` +* `raw_ops.DeepCopy` +* `raw_ops.DeleteSessionTensor` +* `raw_ops.DenseBincount` +* `raw_ops.DenseToDenseSetOperation` +* `raw_ops.DenseToSparseSetOperation` +* `raw_ops.DepthToSpace` +* `raw_ops.DepthwiseConv2dNative` +* `raw_ops.Dequantize` +* `raw_ops.DestroyResourceOp` +* `raw_ops.DestroyTemporaryVariable` +* `raw_ops.Diag` +* `raw_ops.DiagPart` +* `raw_ops.Dilation2D` +* `raw_ops.Dilation2DBackpropFilter` +* `raw_ops.Dilation2DBackpropInput` +* `raw_ops.Div` +* `raw_ops.DivNoNan` +* `raw_ops.DynamicPartition` +* `raw_ops.DynamicStitch` +* `raw_ops.Einsum` +* `raw_ops.Elu` +* `raw_ops.EluGrad` +* `raw_ops.Empty` +* `raw_ops.EmptyTensorList` +* `raw_ops.EmptyTensorMap` +* `raw_ops.EncodeBase64` +* `raw_ops.EncodeJpeg` +* `raw_ops.EncodeJpegVariableQuality` +* `raw_ops.EncodePng` +* `raw_ops.EncodeWav` +* `raw_ops.EnsureShape` +* `raw_ops.Enter` +* `raw_ops.Equal` +* `raw_ops.Erf` +* `raw_ops.Exit` +* `raw_ops.Exp` +* `raw_ops.ExpandDims` +* `raw_ops.ExtractImagePatches` +* `raw_ops.FFT` +* `raw_ops.FFT2D` +* `raw_ops.FFT3D` +* `raw_ops.FIFOQueue` +* `raw_ops.FIFOQueueV2` +* `raw_ops.FakeQuantWithMinMaxArgs` +* `raw_ops.FakeQuantWithMinMaxArgsGradient` +* `raw_ops.FakeQuantWithMinMaxVars` +* `raw_ops.FakeQuantWithMinMaxVarsGradient` +* `raw_ops.FakeQuantWithMinMaxVarsPerChannel` +* `raw_ops.FakeQuantWithMinMaxVarsPerChannelGradient` +* `raw_ops.FakeQueue` +* `raw_ops.Fill` +* `raw_ops.Fingerprint` +* `raw_ops.Floor` +* `raw_ops.FloorDiv` +* `raw_ops.FloorMod` +* `raw_ops.FusedBatchNorm` +* `raw_ops.FusedBatchNormGrad` +* `raw_ops.FusedBatchNormGradV2` +* `raw_ops.FusedBatchNormGradV3` +* `raw_ops.FusedBatchNormV2` +* `raw_ops.FusedBatchNormV3` +* `raw_ops.FusedPadConv2D` +* `raw_ops.FusedResizeAndPadConv2D` +* `raw_ops.Gather` +* `raw_ops.GatherNd` +* `raw_ops.GatherV2` +* `raw_ops.GetSessionHandle` +* `raw_ops.GetSessionHandleV2` +* `raw_ops.GetSessionTensor` +* `raw_ops.Greater` +* `raw_ops.GreaterEqual` +* `raw_ops.HistogramSummary` +* `raw_ops.IFFT` +* `raw_ops.IFFT2D` +* `raw_ops.IFFT3D` +* `raw_ops.IRFFT` +* `raw_ops.IRFFT2D` +* `raw_ops.IRFFT3D` +* `raw_ops.Identity` +* `raw_ops.IdentityN` +* `raw_ops.Imag` +* `raw_ops.ImageProjectiveTransformV2` +* `raw_ops.ImageProjectiveTransformV3` +* `raw_ops.ImmutableConst` +* `raw_ops.InTopK` +* `raw_ops.InTopKV2` +* `raw_ops.InplaceAdd` +* `raw_ops.InplaceSub` +* `raw_ops.InplaceUpdate` +* `raw_ops.Inv` +* `raw_ops.InvGrad` +* `raw_ops.Invert` +* `raw_ops.InvertPermutation` +* `raw_ops.IsBoostedTreesQuantileStreamResourceInitialized` +* `raw_ops.IsFinite` +* `raw_ops.IsNan` +* `raw_ops.IsVariableInitialized` +* `raw_ops.LRN` +* `raw_ops.LeakyRelu` +* `raw_ops.LeakyReluGrad` +* `raw_ops.LeftShift` +* `raw_ops.Less` +* `raw_ops.LessEqual` +* `raw_ops.LinSpace` +* `raw_ops.ListDiff` +* `raw_ops.Log` +* `raw_ops.LogSoftmax` +* `raw_ops.LogicalAnd` +* `raw_ops.LogicalNot` +* `raw_ops.LogicalOr` +* `raw_ops.LoopCond` +* `raw_ops.MatMul` +* `raw_ops.MatrixDiag` +* `raw_ops.MatrixDiagPart` +* `raw_ops.MatrixDiagPartV2` +* `raw_ops.MatrixDiagPartV3` +* `raw_ops.MatrixDiagV2` +* `raw_ops.MatrixDiagV3` +* `raw_ops.MatrixInverse` +* `raw_ops.MatrixSetDiag` +* `raw_ops.MatrixSetDiagV2` +* `raw_ops.MatrixSetDiagV3` +* `raw_ops.MatrixTriangularSolve` +* `raw_ops.Max` +* `raw_ops.MaxPool` +* `raw_ops.MaxPool3D` +* `raw_ops.MaxPool3DGrad` +* `raw_ops.MaxPool3DGradGrad` +* `raw_ops.MaxPoolGrad` +* `raw_ops.MaxPoolGradGrad` +* `raw_ops.MaxPoolGradGradV2` +* `raw_ops.MaxPoolGradV2` +* `raw_ops.MaxPoolGradWithArgmax` +* `raw_ops.MaxPoolV2` +* `raw_ops.MaxPoolWithArgmax` +* `raw_ops.Maximum` +* `raw_ops.Mean` +* `raw_ops.Merge` +* `raw_ops.MergeSummary` +* `raw_ops.MergeV2Checkpoints` +* `raw_ops.Mfcc` +* `raw_ops.Min` +* `raw_ops.Minimum` +* `raw_ops.MirrorPad` +* `raw_ops.MirrorPadGrad` +* `raw_ops.Mul` +* `raw_ops.MulNoNan` +* `raw_ops.Multinomial` +* `raw_ops.Neg` +* `raw_ops.NextIteration` +* `raw_ops.NoOp` +* `raw_ops.NonMaxSuppression` +* `raw_ops.NonMaxSuppressionV2` +* `raw_ops.NonMaxSuppressionV3` +* `raw_ops.NonMaxSuppressionV4` +* `raw_ops.NonMaxSuppressionV5` +* `raw_ops.NonMaxSuppressionWithOverlaps` +* `raw_ops.NotEqual` +* `raw_ops.OneHot` +* `raw_ops.OnesLike` +* `raw_ops.Pack` +* `raw_ops.Pad` +* `raw_ops.PadV2` +* `raw_ops.PaddingFIFOQueue` +* `raw_ops.PaddingFIFOQueueV2` +* `raw_ops.ParallelConcat` +* `raw_ops.ParallelDynamicStitch` +* `raw_ops.ParseExample` +* `raw_ops.ParseExampleV2` +* `raw_ops.ParseSequenceExample` +* `raw_ops.ParseSequenceExampleV2` +* `raw_ops.ParseSingleExample` +* `raw_ops.ParseSingleSequenceExample` +* `raw_ops.Placeholder` +* `raw_ops.PlaceholderV2` +* `raw_ops.PlaceholderWithDefault` +* `raw_ops.PopulationCount` +* `raw_ops.Pow` +* `raw_ops.PreventGradient` +* `raw_ops.Print` +* `raw_ops.PrintV2` +* `raw_ops.Prod` +* `raw_ops.QuantizeDownAndShrinkRange` +* `raw_ops.QuantizeV2` +* `raw_ops.QuantizedAdd` +* `raw_ops.QuantizedAvgPool` +* `raw_ops.QuantizedBatchNormWithGlobalNormalization` +* `raw_ops.QuantizedBiasAdd` +* `raw_ops.QuantizedConcat` +* `raw_ops.QuantizedConv2D` +* `raw_ops.QuantizedInstanceNorm` +* `raw_ops.QuantizedMatMul` +* `raw_ops.QuantizedMaxPool` +* `raw_ops.QuantizedMul` +* `raw_ops.QuantizedRelu` +* `raw_ops.QuantizedRelu6` +* `raw_ops.QuantizedReshape` +* `raw_ops.QuantizedResizeBilinear` +* `raw_ops.QueueClose` +* `raw_ops.QueueCloseV2` +* `raw_ops.QueueDequeue` +* `raw_ops.QueueDequeueMany` +* `raw_ops.QueueDequeueManyV2` +* `raw_ops.QueueDequeueUpTo` +* `raw_ops.QueueDequeueUpToV2` +* `raw_ops.QueueDequeueV2` +* `raw_ops.QueueEnqueue` +* `raw_ops.QueueEnqueueMany` +* `raw_ops.QueueEnqueueManyV2` +* `raw_ops.QueueEnqueueV2` +* `raw_ops.QueueIsClosed` +* `raw_ops.QueueIsClosedV2` +* `raw_ops.QueueSize` +* `raw_ops.QueueSizeV2` +* `raw_ops.RFFT` +* `raw_ops.RFFT2D` +* `raw_ops.RFFT3D` +* `raw_ops.RaggedBincount` +* `raw_ops.RaggedGather` +* `raw_ops.RaggedRange` +* `raw_ops.RaggedTensorToSparse` +* `raw_ops.RaggedTensorToTensor` +* `raw_ops.RandomGamma` +* `raw_ops.RandomPoisson` +* `raw_ops.RandomPoissonV2` +* `raw_ops.RandomStandardNormal` +* `raw_ops.RandomUniform` +* `raw_ops.RandomUniformInt` +* `raw_ops.Range` +* `raw_ops.Rank` +* `raw_ops.ReadVariableOp` +* `raw_ops.Real` +* `raw_ops.RealDiv` +* `raw_ops.Reciprocal` +* `raw_ops.ReciprocalGrad` +* `raw_ops.Recv` +* `raw_ops.ReduceJoin` +* `raw_ops.RefEnter` +* `raw_ops.RefExit` +* `raw_ops.RefIdentity` +* `raw_ops.RefMerge` +* `raw_ops.RefNextIteration` +* `raw_ops.RefSelect` +* `raw_ops.RefSwitch` +* `raw_ops.RegexFullMatch` +* `raw_ops.RegexReplace` +* `raw_ops.Relu` +* `raw_ops.Relu6` +* `raw_ops.Relu6Grad` +* `raw_ops.ReluGrad` +* `raw_ops.RemoteCall` +* `raw_ops.RequantizationRange` +* `raw_ops.Requantize` +* `raw_ops.Reshape` +* `raw_ops.ResizeBilinear` +* `raw_ops.ResizeBilinearGrad` +* `raw_ops.ResizeNearestNeighbor` +* `raw_ops.ResizeNearestNeighborGrad` +* `raw_ops.ResourceApplyAdaMax` +* `raw_ops.ResourceApplyAdadelta` +* `raw_ops.ResourceApplyAdagrad` +* `raw_ops.ResourceApplyAdagradDA` +* `raw_ops.ResourceApplyAdagradV2` +* `raw_ops.ResourceApplyAdam` +* `raw_ops.ResourceApplyAdamWithAmsgrad` +* `raw_ops.ResourceApplyAddSign` +* `raw_ops.ResourceApplyCenteredRMSProp` +* `raw_ops.ResourceApplyFtrl` +* `raw_ops.ResourceApplyFtrlV2` +* `raw_ops.ResourceApplyGradientDescent` +* `raw_ops.ResourceApplyKerasMomentum` +* `raw_ops.ResourceApplyMomentum` +* `raw_ops.ResourceApplyPowerSign` +* `raw_ops.ResourceApplyProximalAdagrad` +* `raw_ops.ResourceApplyProximalGradientDescent` +* `raw_ops.ResourceApplyRMSProp` +* `raw_ops.ResourceGather` +* `raw_ops.ResourceGatherNd` +* `raw_ops.ResourceScatterAdd` +* `raw_ops.ResourceScatterDiv` +* `raw_ops.ResourceScatterMax` +* `raw_ops.ResourceScatterMin` +* `raw_ops.ResourceScatterMul` +* `raw_ops.ResourceScatterNdAdd` +* `raw_ops.ResourceScatterNdMax` +* `raw_ops.ResourceScatterNdMin` +* `raw_ops.ResourceScatterNdSub` +* `raw_ops.ResourceScatterNdUpdate` +* `raw_ops.ResourceScatterSub` +* `raw_ops.ResourceScatterUpdate` +* `raw_ops.ResourceSparseApplyAdadelta` +* `raw_ops.ResourceSparseApplyAdagrad` +* `raw_ops.ResourceSparseApplyAdagradDA` +* `raw_ops.ResourceSparseApplyAdagradV2` +* `raw_ops.ResourceSparseApplyCenteredRMSProp` +* `raw_ops.ResourceSparseApplyFtrl` +* `raw_ops.ResourceSparseApplyFtrlV2` +* `raw_ops.ResourceSparseApplyKerasMomentum` +* `raw_ops.ResourceSparseApplyMomentum` +* `raw_ops.ResourceSparseApplyProximalAdagrad` +* `raw_ops.ResourceSparseApplyProximalGradientDescent` +* `raw_ops.ResourceSparseApplyRMSProp` +* `raw_ops.ResourceStridedSliceAssign` +* `raw_ops.Restore` +* `raw_ops.RestoreSlice` +* `raw_ops.RestoreV2` +* `raw_ops.Reverse` +* `raw_ops.ReverseSequence` +* `raw_ops.ReverseV2` +* `raw_ops.RightShift` +* `raw_ops.Roll` +* `raw_ops.Round` +* `raw_ops.Rsqrt` +* `raw_ops.RsqrtGrad` +* `raw_ops.SampleDistortedBoundingBox` +* `raw_ops.SampleDistortedBoundingBoxV2` +* `raw_ops.Save` +* `raw_ops.SaveSlices` +* `raw_ops.SaveV2` +* `raw_ops.ScalarSummary` +* `raw_ops.ScatterNd` +* `raw_ops.ScatterNdAdd` +* `raw_ops.ScatterNdMax` +* `raw_ops.ScatterNdMin` +* `raw_ops.ScatterNdNonAliasingAdd` +* `raw_ops.ScatterNdSub` +* `raw_ops.ScatterNdUpdate` +* `raw_ops.SegmentMax` +* `raw_ops.SegmentMean` +* `raw_ops.SegmentMin` +* `raw_ops.SegmentProd` +* `raw_ops.SegmentSum` +* `raw_ops.Select` +* `raw_ops.SelectV2` +* `raw_ops.Selu` +* `raw_ops.SeluGrad` +* `raw_ops.Send` +* `raw_ops.Shape` +* `raw_ops.ShapeN` +* `raw_ops.ShardedFilename` +* `raw_ops.ShardedFilespec` +* `raw_ops.Sigmoid` +* `raw_ops.SigmoidGrad` +* `raw_ops.Sign` +* `raw_ops.Sin` +* `raw_ops.Sinh` +* `raw_ops.Size` +* `raw_ops.Slice` +* `raw_ops.Softmax` +* `raw_ops.SoftmaxCrossEntropyWithLogits` +* `raw_ops.Softplus` +* `raw_ops.SoftplusGrad` +* `raw_ops.Softsign` +* `raw_ops.SoftsignGrad` +* `raw_ops.SpaceToBatch` +* `raw_ops.SpaceToBatchND` +* `raw_ops.SpaceToDepth` +* `raw_ops.SparseApplyAdadelta` +* `raw_ops.SparseApplyAdagrad` +* `raw_ops.SparseApplyAdagradDA` +* `raw_ops.SparseApplyAdagradV2` +* `raw_ops.SparseApplyCenteredRMSProp` +* `raw_ops.SparseApplyFtrl` +* `raw_ops.SparseApplyFtrlV2` +* `raw_ops.SparseApplyMomentum` +* `raw_ops.SparseApplyProximalAdagrad` +* `raw_ops.SparseApplyProximalGradientDescent` +* `raw_ops.SparseApplyRMSProp` +* `raw_ops.SparseBincount` +* `raw_ops.SparseCross` +* `raw_ops.SparseCrossHashed` +* `raw_ops.SparseCrossV2` +* `raw_ops.SparseFillEmptyRows` +* `raw_ops.SparseFillEmptyRowsGrad` +* `raw_ops.SparseReshape` +* `raw_ops.SparseSegmentMean` +* `raw_ops.SparseSegmentMeanGrad` +* `raw_ops.SparseSegmentMeanWithNumSegments` +* `raw_ops.SparseSegmentSqrtN` +* `raw_ops.SparseSegmentSqrtNGrad` +* `raw_ops.SparseSegmentSqrtNWithNumSegments` +* `raw_ops.SparseSegmentSum` +* `raw_ops.SparseSegmentSumWithNumSegments` +* `raw_ops.SparseToDense` +* `raw_ops.SparseToSparseSetOperation` +* `raw_ops.Split` +* `raw_ops.SplitV` +* `raw_ops.Sqrt` +* `raw_ops.SqrtGrad` +* `raw_ops.Square` +* `raw_ops.SquaredDifference` +* `raw_ops.Squeeze` +* `raw_ops.Stack` +* `raw_ops.StackClose` +* `raw_ops.StackCloseV2` +* `raw_ops.StackPop` +* `raw_ops.StackPopV2` +* `raw_ops.StackPush` +* `raw_ops.StackPushV2` +* `raw_ops.StackV2` +* `raw_ops.StatelessMultinomial` +* `raw_ops.StatelessRandomGammaV2` +* `raw_ops.StatelessRandomGetKeyCounterAlg` +* `raw_ops.StatelessRandomNormal` +* `raw_ops.StatelessRandomNormalV2` +* `raw_ops.StatelessRandomPoisson` +* `raw_ops.StatelessRandomUniform` +* `raw_ops.StatelessRandomUniformFullInt` +* `raw_ops.StatelessRandomUniformFullIntV2` +* `raw_ops.StatelessRandomUniformInt` +* `raw_ops.StatelessRandomUniformIntV2` +* `raw_ops.StatelessRandomUniformV2` +* `raw_ops.StatelessSampleDistortedBoundingBox` +* `raw_ops.StatelessTruncatedNormal` +* `raw_ops.StatelessTruncatedNormalV2` +* `raw_ops.StaticRegexFullMatch` +* `raw_ops.StaticRegexReplace` +* `raw_ops.StopGradient` +* `raw_ops.StridedSlice` +* `raw_ops.StridedSliceAssign` +* `raw_ops.StridedSliceGrad` +* `raw_ops.StringJoin` +* `raw_ops.StringLength` +* `raw_ops.StringLower` +* `raw_ops.StringSplit` +* `raw_ops.StringSplitV2` +* `raw_ops.StringStrip` +* `raw_ops.StringToHashBucket` +* `raw_ops.StringToHashBucketFast` +* `raw_ops.StringToHashBucketStrong` +* `raw_ops.Sub` +* `raw_ops.Substr` +* `raw_ops.Sum` +* `raw_ops.Switch` +* `raw_ops.SymbolicGradient` +* `raw_ops.Tan` +* `raw_ops.Tanh` +* `raw_ops.TanhGrad` +* `raw_ops.TemporaryVariable` +* `raw_ops.TensorArray` +* `raw_ops.TensorArrayClose` +* `raw_ops.TensorArrayCloseV2` +* `raw_ops.TensorArrayCloseV3` +* `raw_ops.TensorArrayConcat` +* `raw_ops.TensorArrayConcatV2` +* `raw_ops.TensorArrayConcatV3` +* `raw_ops.TensorArrayGather` +* `raw_ops.TensorArrayGatherV2` +* `raw_ops.TensorArrayGatherV3` +* `raw_ops.TensorArrayGrad` +* `raw_ops.TensorArrayGradV2` +* `raw_ops.TensorArrayGradV3` +* `raw_ops.TensorArrayGradWithShape` +* `raw_ops.TensorArrayPack` +* `raw_ops.TensorArrayRead` +* `raw_ops.TensorArrayReadV2` +* `raw_ops.TensorArrayReadV3` +* `raw_ops.TensorArrayScatter` +* `raw_ops.TensorArrayScatterV2` +* `raw_ops.TensorArrayScatterV3` +* `raw_ops.TensorArraySize` +* `raw_ops.TensorArraySizeV2` +* `raw_ops.TensorArraySizeV3` +* `raw_ops.TensorArraySplit` +* `raw_ops.TensorArraySplitV2` +* `raw_ops.TensorArraySplitV3` +* `raw_ops.TensorArrayUnpack` +* `raw_ops.TensorArrayV2` +* `raw_ops.TensorArrayV3` +* `raw_ops.TensorArrayWrite` +* `raw_ops.TensorArrayWriteV2` +* `raw_ops.TensorArrayWriteV3` +* `raw_ops.TensorListConcat` +* `raw_ops.TensorListConcatLists` +* `raw_ops.TensorListConcatV2` +* `raw_ops.TensorListElementShape` +* `raw_ops.TensorListFromTensor` +* `raw_ops.TensorListGather` +* `raw_ops.TensorListGetItem` +* `raw_ops.TensorListLength` +* `raw_ops.TensorListPopBack` +* `raw_ops.TensorListPushBack` +* `raw_ops.TensorListPushBackBatch` +* `raw_ops.TensorListReserve` +* `raw_ops.TensorListResize` +* `raw_ops.TensorListScatter` +* `raw_ops.TensorListScatterIntoExistingList` +* `raw_ops.TensorListScatterV2` +* `raw_ops.TensorListSetItem` +* `raw_ops.TensorListSplit` +* `raw_ops.TensorListStack` +* `raw_ops.TensorMapErase` +* `raw_ops.TensorMapHasKey` +* `raw_ops.TensorMapInsert` +* `raw_ops.TensorMapLookup` +* `raw_ops.TensorMapSize` +* `raw_ops.TensorMapStackKeys` +* `raw_ops.TensorScatterAdd` +* `raw_ops.TensorScatterMax` +* `raw_ops.TensorScatterMin` +* `raw_ops.TensorScatterSub` +* `raw_ops.TensorScatterUpdate` +* `raw_ops.TensorStridedSliceUpdate` +* `raw_ops.Tile` +* `raw_ops.TileGrad` +* `raw_ops.Timestamp` +* `raw_ops.TopK` +* `raw_ops.TopKV2` +* `raw_ops.Transpose` +* `raw_ops.TruncateDiv` +* `raw_ops.TruncatedNormal` +* `raw_ops.UnicodeDecode` +* `raw_ops.UnicodeDecodeWithOffsets` +* `raw_ops.UnicodeEncode` +* `raw_ops.UnicodeTranscode` +* `raw_ops.Unique` +* `raw_ops.UniqueV2` +* `raw_ops.UniqueWithCounts` +* `raw_ops.UniqueWithCountsV2` +* `raw_ops.Unpack` +* `raw_ops.UnsortedSegmentMax` +* `raw_ops.UnsortedSegmentMin` +* `raw_ops.UnsortedSegmentProd` +* `raw_ops.UnsortedSegmentSum` +* `raw_ops.UnwrapDatasetVariant` +* `raw_ops.VarHandleOp` +* `raw_ops.VarIsInitializedOp` +* `raw_ops.Variable` +* `raw_ops.VariableShape` +* `raw_ops.VariableV2` +* `raw_ops.Where` +* `raw_ops.WrapDatasetVariant` +* `raw_ops.Xdivy` +* `raw_ops.Xlog1py` +* `raw_ops.Xlogy` +* `raw_ops.ZerosLike` + +## TensorFlow Text and SentencePiece operators + +The following +[TensorFlow Text](https://www.tensorflow.org/tutorials/tensorflow_text/intro) +and [SentencePiece](https://github.com/google/sentencepiece) operators are +supported if you use the Python API for conversion and import those libraries. + +TF.Text operators: + +* `CaseFoldUTF8` +* `ConstrainedSequence` +* `MaxSpanningTree` +* `NormalizeUTF8` +* `NormalizeUTF8WithOffsetsMap` +* `RegexSplitWithOffsets` +* `RougeL` +* `SentenceFragments` +* `SentencepieceOp` +* `SentencepieceTokenizeOp` +* `SentencepieceTokenizeWithOffsetsOp` +* `SentencepieceDetokenizeOp` +* `SentencepieceVocabSizeOp` +* `SplitMergeTokenizeWithOffsets` +* `UnicodeScriptTokenizeWithOffsets` +* `WhitespaceTokenizeWithOffsets` +* `WordpieceTokenizeWithOffsets` + +SentencePiece operators: + +* `SentencepieceGetPieceSize` +* `SentencepiecePieceToId` +* `SentencepieceIdToPiece` +* `SentencepieceEncodeDense` +* `SentencepieceEncodeSparse` +* `SentencepieceDecode` + +The following snippet shows how to convert models with the above operators: + +```python +import tensorflow as tf +# These imports are required to load operators' definition. +import tensorflow_text as tf_text +import sentencepiece as spm + +converter = tf.lite.TFLiteConverter.from_keras_model(your_model) +converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS +] +model_data = converter.convert() +``` + +On the runtime side, it is also required to link the TensorFlow Text or +SentencePiece library into the final app or binary. + +## User's defined Operators + +*Note: This feature is only available in tf-nightly and the upcoming v2.5.0 +version* + +If you +[created your own TensorFlow operators](https://www.tensorflow.org/guide/create_op), +you can also convert models containing them to TensorFlow Lite by listing +required operators in the `experimental_select_user_tf_ops` as following: + +```python +import tensorflow as tf + +ops_module = tf.load_op_library('./your_ops_library.so') + +converter = tf.lite.TFLiteConverter.from_saved_model(your_model) +converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS +] +converter.target_spec.experimental_select_user_tf_ops = [ + 'your_op_name1', + 'your_op_name2' +] +model_data = converter.convert() +``` + +On the runtime side, it is also required to link your operators library into the +final app or binary. diff --git a/tensorflow/lite/g3doc/guide/ops_select.md b/tensorflow/lite/g3doc/guide/ops_select.md index 19e8cb372e0..dca1bd93263 100644 --- a/tensorflow/lite/g3doc/guide/ops_select.md +++ b/tensorflow/lite/g3doc/guide/ops_select.md @@ -1,17 +1,15 @@ # Select TensorFlow operators -Caution: This feature is experimental. - Since the TensorFlow Lite builtin operator library only supports a limited number of TensorFlow operators, not every model is convertible. For details, refer to [operator compatibility](ops_compatibility.md). To allow conversion, users can enable the usage of -[certain TensorFlow ops](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/flex/allowlisted_flex_ops.cc) -in their TensorFlow Lite model. However, running TensorFlow Lite models with -TensorFlow ops requires pulling in the core TensorFlow runtime, which increases -the TensorFlow Lite interpreter binary size. For Android, you can avoid this by -selectively building only required Tensorflow ops. For the details, refer to +[certain TensorFlow ops](op_select_allowlist.md) in their TensorFlow Lite model. +However, running TensorFlow Lite models with TensorFlow ops requires pulling in +the core TensorFlow runtime, which increases the TensorFlow Lite interpreter +binary size. For Android, you can avoid this by selectively building only +required Tensorflow ops. For the details, refer to [reduce binary size](../guide/reduce_binary_size.md). This document outlines how to [convert](#convert_a_model) and