- 人工智能
- 机器学习
- 深度学习
- 前端
- 后端
【免费下载链接】tfjs
A WebGL accelerated JavaScript library for training and deploying ML models.
本文以 tfjs-converter 官方文档 supported_ops.md 为主体,系统梳理 TensorFlow 算子到 TensorFlow.js 算子的映射关系,并结合 operation_mapper.ts、operation_executor.ts 等源码剖析其背后的映射与执行机制,帮助读者在将 TF 模型转换为 TF.js 模型时快速判断算子可用性与用法。
一、本文档的定位与阅读方式
supported_ops.md是 tfjs-converter 中关于"TensorFlow 算子 → TensorFlow.js 算子"映射关系的官方索引文档。它回答了一个核心问题:我训练好的 TensorFlow / Keras 模型里用到的算子,能否被 TensorFlow.js 直接运行?
- 左列
Tensorflow Op Name:模型导出的 GraphDef / SavedModel 中真实存在的算子名(如Conv2D、FusedBatchNormV3)。 - 右列
Tensorflow.js Op Name:tfjs-converter 转换后实际调用的 TF.js API 名(如conv2d、batchNorm)。 - 部分行标注
Not mapped:这些是 TF.js 侧提供的算子,但 TensorFlow 中没有可直接对应的算子(或仅存在于旧版/特定版本中)。它们通常由 TF.js 自定义算子或在转换后的图中以其他方式实现,因此出现在右列。
从源码结构看,这份清单并非手工硬编码,而是与src/operations/目录下的映射表一一对应。operation_mapper.ts在构造函数中加载了arithmetic, basicMath, control, convolution, creation, dynamic, evaluation, graph, hashTable, image, logical, matrices, normalization, reduction, sliceJoin, sparse, spectral, string, transformation这 19 个分类的 op 映射 JSON(operation_mapper.ts#L56-L70),并以tfOpName为键建立查找表。也就是说,文档中的每一行都对应源码中一条真实的映射记录。
1.1 映射(Mapper)与执行(Executor)的两级架构
要读懂这份清单,需要先理解 tfjs-converter 的两级处理流水线:
映射阶段(OperationMapper):把 TensorFlow GraphDef 中的
NodeDef转换成 TF.js 内部的Node结构。核心逻辑在OperationMapper.mapNode():先按tfOpName查表,找不到时回退到getRegisteredOp()注册的自定义算子,仍找不到则该节点映射为{}空 Mapper,错误延迟到运行期(源码注释明确指出 "Unsupported ops will cause an error at run-time (not parse time)",见 operation_mapper.ts#L179-L183)。随后对每个节点的inputs(输入张量)与attrs(属性)逐一解析:输入通过mapper.inputs中定义的start/end索引定位,属性则依据string / number / bool / shape / dtype / func / tensor等类型分派到getStringParam、getNumberParam、getDtypeParam等解析函数(operation_mapper.ts#L216-L334)。执行阶段(OperationExecutor):
executeOp()依据节点的category分发到对应的 executor(arithmetic、basic_math、control、convolution、creation、dynamic、evaluation、graph、logical、matrices、normalization、reduction、slice_join、sparse、spectral、string、transformation、hash_table、custom),最终调用@tensorflow/tfjs-core的算子函数(operation_executor.ts#L55-L124)。
因此,supported_ops.md中的"分类"标题(如 Operations - Arithmetic)对应的是operation_executor.ts中的category分支;而"TF.js Op Name"对应各 executor 内部switch (node.op)后调用的具体 tfjs-core 函数。例如 Arithmetic 分类中的Add/AddV2/BiasAdd三个 TF 算子统一映射到ops.add,FloorMod/Mod映射到ops.mod,RealDiv/Div映射到ops.div(见 arithmetic_executor.ts#L31-L96)。
1.2 为什么文档值得逐表对照
在模型转换前逐表对照的意义在于:
- 预判失败点:如果模型包含清单之外的算子,转换本身(
convert_graph_def)可能成功,但执行到该节点时才抛错。因为mapNode对未知算子不报错,错误发生在executeOp的default分支,抛出Unknown op 'xxx'并建议使用tf.registerOp()注册自定义执行(operation_executor.ts#L113-L117)。 - 选择等价替代:对
Not mapped的算子,通常可以寻找 TF.js 侧的替代实现(如用conv2dTranspose替代反卷积、用topk替代TopKV2的部分场景)。 - 理解命名差异:TF 算子名与 TF.js API 名并不总是相同(如
DepthwiseConv2dNativevsdepthwiseConv2d),清单能避免"按名索骥"的困惑。
二、算术(Arithmetic)与基础数学(Basic math)
2.1 算术算子
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Add / AddN / AddV2 / BiasAdd | add / addN / add(BiasAdd在 executor 中按add执行) |
| Div / DivNoNan / FloorDiv | div / divNoNan / floorDiv |
| FloorMod / Mod | mod |
| Maximum / Minimum | maximum / minimum |
| Mul / Pow / RealDiv | mul / pow / div |
| SquaredDifference / Sub | squaredDifference / sub |
从 arithmetic_executor.ts 可以确认:Add、AddV2、BiasAdd三个 case 均调用ops.add(a, b);RealDiv与Div都调用ops.div;FloorMod与Mod都调用ops.mod。这意味着模型中的BiasAdd在浏览器端会被当作普通加法执行——这解释了为何 TF.js 不需要单独实现BiasAdd内核。
使用建议:转换前若模型以AddV2(TF2.x 默认)或BiasAdd形式表达加法,TF.js 均可直接执行,无需修改图。
2.2 基础数学算子
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Abs / Acos / Acosh / Asin / Asinh / Atan / Atan2 / Atanh | abs / acos / acosh / asin / asinh / atan / atan2 / atanh |
| Ceil / Cos / Cosh / Elu / Erf / Exp / Expm1 / Floor | ceil / cos / cosh / elu / erf / exp / expm1 / floor |
| Imag / LeakyRelu / Log / Log1p / Neg / Prelu / Prod | imag / leakyRelu / log / log1p / neg / prelu / prod |
| Real / Reciprocal / Relu / Relu6 / Round / Rsqrt | real / reciprocal / relu / relu6 / round / rsqrt |
| Selu / Sigmoid / Sign / Sin / Sinh / Softplus | selu / sigmoid / sign / sin / sinh / softplus |
| Sqrt / Square / Tan / Tanh | sqrt / square / tan / tanh |
| IsFinite / IsInf / IsNan | isFinite / isInf / isNaN |
| Complex / ComplexAbs | complex / complexAbs |
| ClipByValue | clipByValue |
| Not mapped | logSigmoid、step |
这一分类覆盖了几乎全部常用的激活函数与基础数学函数。特别值得注意:
- 复数支持:
Complex、ComplexAbs、Imag、Real表明 tfjs-converter 支持包含复数运算的模型(底层依赖 tfjs-core 的complex64数据类型,见parseDtypeParam中DT_COMPLEX64/DT_COMPLEX128 → 'complex64'的映射,operation_mapper.ts#L502-L504)。 - 激活函数家族:
Relu、Relu6、LeakyRelu、Prelu、Elu、Selu、Softplus、Sigmoid、Tanh一应俱全,绝大多数 CNN/RNN 模型都不会在此分类遇阻。 Not mapped的logSigmoid、step属于 TF.js 额外提供的 API,TensorFlow 中没有同名算子。
三、控制流(Control Flow)与图算子(Graph)
3.1 控制流:条件与循环
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| If / StatelessIf / While / StatelessWhile | If / StatelessIf / While / StatelessWhile |
| Enter / Exit / LoopCond / Merge / NextIteration / Switch | 同名保留 |
| EmptyTensorList / TensorArrayV3 系列(Close/Concat/Gather/Read/Scatter/Size/Split/Write) | 同名保留 |
| TensorList 系列(Concat/ConcatV2/FromTensor/Gather/GetItem/Length/PopBack/PushBack/Reserve/Resize/Scatter/ScatterV2/SetItem/Split/Stack) | 同名保留 |
这是清单中最庞大的一类,支撑着tf.while_loop、tf.cond、TensorArray与TensorList结构。从 control_executor.ts 的实现看,While、If等算子会递归执行graph.library.function中定义的子图(mapFunction会把FunctionDef映射为独立的子Graph,见 operation_mapper.ts#L339-L405)。
实践提示:控制流算子在 TF 2.x 的 SavedModel 导出中非常常见(如动态 RNN、tf.map_fn、循环解码器)。如果模型转换后报Unknown op且算子名属于 TensorList/TensorArray 系列,请先确认所使用的 tfjs-converter 版本与本文档一致,因为该清单随版本持续扩充。
3.2 图算子(Graph)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Const / Identity / IdentityN / NoOp / Snapshot / StopGradient | 同名 |
| Placeholder / PlaceholderWithDefault | 同名 |
| FakeQuantWithMinMaxVars | FakeQuantWithMinMaxVars |
| Print / Rank / Shape / ShapeN / Size | 同名 |
Placeholder与Const在图映射中承担特殊角色:transformGraph会单独收集placeholders(模型输入)与weights(常量权重)列表(operation_mapper.ts#L81-L91)。FakeQuantWithMinMaxVars的存在意味着量化感知训练(QAT)导出的图可以在 TF.js 中运行(执行时按伪量化语义处理)。
四、卷积(Convolution)、图像(Images)与池化
4.1 卷积算子
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Conv1D / Conv2D / Conv3D | conv1d / conv2d / conv3d |
| Conv2DBackpropInput | conv2dTranspose(反卷积) |
| DepthwiseConv2d / DepthwiseConv2dNative | depthwiseConv2d |
| _FusedConv2D / FusedDepthwiseConv2dNative | 同名 fused 变体 |
| AvgPool / AvgPool3D / MaxPool / MaxPool3D | avgPool / avgPool3d / maxPool / maxPool3d |
| MaxPoolWithArgmax / Dilation2D | 同名 |
| Not mapped | conv2dTranspose、conv3dTranspose、pool、separableConv2d |
以Conv2D为例,执行器会从节点属性中取出strides、pad、dataFormat(转为大写NHWC/NCHW)、dilations,然后调用ops.conv2d(x, filter, [stride[1], stride[2]], pad, dataFormat, [dilations[1], dilations[2]])(convolution_executor.ts#L103-L117)。_FusedConv2D则是 TF 图优化器融合了 bias 与激活(如Relu)后的算子,TF.js 通过ops.fused.conv2d一次性完成卷积+偏置+激活,显著减少内存往返(convolution_executor.ts#L119-L139)。
注意事项:
- 若希望模型走融合路径,需要在 TensorFlow 侧导出时启用图优化(Grappler 的
_FusedConv2D融合),否则以标准Conv2D执行同样正确。 Not mapped的pool(通用池化封装)与separableConv2D是 TF.js 侧提供的便捷 API,不是 TF 算子名。
4.2 图像算子
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| ResizeBilinear / ResizeNearestNeighbor | resizeBilinear / resizeNearestNeighbor |
| CropAndResize | cropAndResize |
| ImageProjectiveTransformV3 | transform |
| Not mapped | flipLeftRight、rotateWithOffset |
对象检测与图像预处理类模型(如 SSD、Faster R-CNN 的CropAndResize阶段)常用到本分类。ImageProjectiveTransformV3对应 TF.js 的transform(投影变换),用于仿射/透视变换类数据增强。
五、张量操作:创建、切片连接、变换与矩阵
5.1 张量创建(Creation)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Fill / Range / LinSpace | fill / range / linspace |
| Ones / Zeros / OnesLike / ZerosLike | ones / zeros / onesLike / zerosLike |
| OneHot / Multinomial | oneHot / multinomial |
| RandomStandardNormal / RandomUniform / TruncatedNormal | 同名 |
| Not mapped | eye |
注意 TF.js 的随机数算子名与 TF 一致,但随机种子行为由 TF.js 环境标志控制,转换后结果不一定与 Python 端逐位一致,属正常现象。
5.2 切片与连接(Slicing and Joining)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Concat / ConcatV2 | concat |
| Gather / GatherV2 / GatherNd | gather / gatherNd |
| Pack / Unpack / Split / SplitV / Stack | pack / unpack / split / stack |
| Slice / StridedSlice / Reverse / ReverseV2 | slice / stridedSlice / reverse |
| Tile / ScatterNd / SparseToDense | tile / scatterNd / sparseToDense |
| Not mapped | booleanMaskAsync、unstack |
StridedSlice是tf.strided_slice的核心支撑,也是许多 TF 高层 API(如x[..., 1:])编译后的底层算子,几乎每个实用模型都会用到。
5.3 变换(Transformations)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| BatchToSpaceND / SpaceToBatchND | batchToSpaceND / spaceToBatchND |
| DepthToSpace / MirrorPad / Pad / PadV2 | depthToSpace / mirrorPad / pad / padV2 |
| Reshape / Squeeze / ExpandDims / Cast / Transpose | reshape / squeeze / expandDims / cast / transpose |
| BroadcastArgs / BroadcastTo | broadcastArgs / broadcastTo |
| EnsureShape | ensureShape |
| Not mapped | setdiff1dAsync |
Cast依赖parseDtypeParam的数据类型映射表:DT_FLOAT/DT_HALF/DT_DOUBLE → float32、DT_INT32/DT_INT64/DT_INT8/DT_UINT8 → int32、DT_BOOL → bool、DT_STRING → string、DT_COMPLEX64/128 → complex64(operation_mapper.ts#L482-L510)。对未知 dtype,映射返回null且错误同样延迟到运行期。
5.4 矩阵运算(Matrices)与线性代数
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| MatMul / BatchMatMul / BatchMatMulV2 / _FusedMatMul | matMul / batchMatMul / 同名 |
| Transpose / Einsum / MatrixBandPart | transpose / einsum / bandPart |
| Not mapped | dot、norm、outerProduct、qr、gramSchmidt |
_FusedMatMul与_FusedConv2D类似,是 Grappler 融合偏置/激活后的稠密层形态;Einsum让 Transformer 等模型的 attention 计算可以直接转换。
六、归约、归一化、逻辑、评估与哈希表
6.1 归约(Reduction)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| All / Any / Max / Min / Mean / Sum / Prod | all / any / max / min / mean / sum / prod |
| ArgMax / ArgMin | argMax / argMin |
| Bincount / DenseBincount | bincount / denseBincount |
| Not mapped | logSumExp |
6.2 归一化(Normalization)
| TensorFlow Op Name | TensorFlow.js Op Name |
|---|---|
| Softmax / LogSoftmax / LRN | softmax / logSoftmax / lrn |
| FusedBatchNorm / V2 / V3 | 同名 |
| EuclideanNorm / SparseToDense | 同名 |
| Not mapped | batchNorm、moments |
FusedBatchNormV3在 TF 2.x 的tf.keras.layers.BatchNormalization导出图中十分常见。batchNorm、moments是 TF.js 侧的便捷 API(batchNorm对应tf.batchNorm,用于推理阶段的 BN 参数合并或自定义归一化)。
6.3 逻辑(Logical)与评估(Evaluation)
逻辑类:Equal、Greater、GreaterEqual、Less、LessEqual、NotEqual、LogicalAnd、LogicalOr、LogicalNot、Select、SelectV2、BitwiseAnd全部同名映射,另有 TF.js 侧补充的logicalXor。
评估类:TopKV2、Unique、UniqueV2、LowerBound、UpperBound同名映射;TF.js 侧提供topk、confusionMatrix、inTopKAsync。分类任务常用Softmax + topk组合:TopKV2直接可用,topk则用于 TF.js 原生代码中。
6.4 哈希表(Hashtable)
HashTable/HashTableV2、LookupTableFind/Import/Size(含 V2 变体)全部同名映射。哈希表算子依赖ResourceManager管理全局资源——这也是executeOp中唯一需要传入resourceManager参数的分支(operation_executor.ts#L102-L104)。此类算子多见于特征工程类模型(如 Wide & Deep 的 embedding lookup)。
七、RNN、Scan、Segment、Spectral、Signal 与动态算子
7.1 RNN 与 Scan
文档中Tensors - RNN 分类目前为空,即没有列出的 TF 算子;但 RNN 模型并非不可转换——其展开后的 LSTM/GRU 单元算子(MatMul、Sigmoid、Tanh、Add、Mul 等)分别落在前文各分类中,动态长度展开则依赖控制流分类的While/TensorArray。
Scan 分类:Cumprod → cumprod、Cumsum → cumsum,支持前缀扫描类算法。
7.2 Segment 与动态(Dynamic)
- Segment:
Not mapped → unsortedSegmentSum(TF.js 侧 API,对应 TF 的UnsortedSegmentSum;从源码分类看,稀疏/不规则张量能力由sparse_executor与ragged_executor支撑)。 - Dynamic:
ListDiff、NonMaxSuppressionV2/V3/V4/V5、Where全部同名映射。NMS 系列是目标检测后处理的标配,V2~V5 的完整支持意味着检测模型通常可以端到端转换。
7.3 谱(Spectral)与信号(Signal)
- Spectral:
FFT/IFFT/RFFT/IRFFT → fft/ifft/rfft/irfft,支持音频/信号处理类模型的频谱变换。 - Signal:
frame、hammingWindow、hannWindow、stft均为Not mapped(TF.js 侧补充的音频窗口/短时傅里叶工具),TF 中对应算子请使用tf.signal.frame、tf.signal.stft导出前的预处理替代。
八、移动平均(Moving Average)
Not mapped → movingAverage:该分类服务于指数滑动平均(EMA)场景。虽然 TF 侧未列出同名算子,但 TF.js 提供movingAverage便于在浏览器中实现参数滑动平均更新(如在线学习或模型微调)。
九、如何确认你的模型算子是否支持
由于文档随 tfjs-converter 版本演进,最可靠的做法是结合源码三层确认:
- 对照清单:快速浏览本文档对应分类。
- 查映射表源码:
OperationMapper构造函数加载的 19 个分类映射(operation_mapper.ts#L56-L70)与本文档同源;也可直接查看 op_mapper_schema.ts 中OpMapper的 JSON Schema(category/inputs/attrs字段定义),理解一条映射记录由哪些字段构成。 - 查执行器源码:在 executors 目录 中找到对应分类的 executor,看
switch (node.op)是否包含你的算子。若包含,则可确认该算子在该版本中可执行;若不包含但映射表存在,说明属于"已映射但待执行实现"的边缘情况。
兜底方案:对清单外的算子,使用tf.registerOp()(导出自 tfjs-converter/src/index.ts)注册自定义 OpExecutor——executeOp的custom分支会优先调用注册的执行器(operation_executor.ts#L105-L112),并在NodeValueImpl的封装下访问节点输入与属性(custom_op/node_value_impl.ts)。
十、总结
| 分类 | 覆盖要点 |
|---|---|
| 算术/基础数学 | 加减乘除、激活函数全家族、复数、clip |
| 控制流/图 | If/While、TensorArray/TensorList、Placeholder/Const |
| 卷积/图像 | Conv1D~3D、反卷积、池化、fused 融合、resize/crop |
| 张量操作 | 创建、切片连接、变换、矩阵、einsum |
| 归约/归一化 | 统计归约、BN/Softmax 系列 |
| 逻辑/评估/哈希表 | 比较、NMS、topk、lookup |
| 谱/信号/动态 | FFT 族、stft、NMS、Where |
supported_ops.md是一份随版本持续生长的清单:文档中每一行都与 operation_mapper.ts 加载的映射表、operation_executor.ts 的分发逻辑一一对应。对于清单内算子,转换即可用;对于清单外算子,错误会延迟到运行期抛出。建议在转换前导出模型算子清单,与本文档逐项核对,必要时结合tf.registerOp()补齐自定义算子,从而保证模型在浏览器与 Node.js 端的完整可运行性。
- 人工智能
- 机器学习
- 深度学习
- 前端
- 后端
【免费下载链接】tfjs
A WebGL accelerated JavaScript library for training and deploying ML models.
相关推荐
CANN ops-nn 中 MatmulFp32 算子 aclnn 单算子调用样例全解析
CANN ops nn 中 MatmulFp32 算子 aclnn 单算子调用样例全解析 导读 本文基于 CANN ops nn 开源仓库中 experimen
人工智能算子库深度学习CANNAscendTensorFlow Lite 如何用 Select TF ops 转换含不受支持算子的模型并运行推理?
TensorFlow Lite 如何用 Select TF ops 转换含不受支持算子的模型并运行推理? TensorFlow Lite 的 built in
人工智能机器学习深度学习分布式训练预训练TensorFlow到ONNX转换支持状态全面解析
TensorFlow到ONNX转换支持状态全面解析 前言 在深度学习模型部署过程中,模型格式转换是一个关键环节。TensorFlow到ONNX的转换工具(tf2
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考