license import { BackendTimingInfo , DataMover , DataType , fill , KernelBackend , ones , Rank , rsqrt , Scalar , scalar , ShapeMap , Tensor , Tensor1D , tensor1d , Tensor2D , tensor2d , Tensor3D , tensor3d , Tensor4D , tidy , util } from '@tensorflow/tfjs-core' ; import { EPSILON_FLOAT32 } from '@tensorflow/tfjs-core/dist/backends/backend' ; import { Conv2DInfo , Conv3DInfo } from '@tensorflow/tfjs-core/dist/ops/conv_util' ; import { Activation } from '@tensorflow/tfjs-core/dist/ops/fused_util' ; import { Tensor5D } from '@tensorflow/tfjs-core/dist/tensor' ; import { BackendValues , upcastType } from '@tensorflow/tfjs-core/dist/types' ; import { isNullOrUndefined } from 'util' ; import { Int64Scalar } from './int64_tensors' ; import { createTensorsTypeOpAttr , createTypeOpAttr , getTFDType } from './ops/op_utils' ; import { TensorMetadata , TFEOpAttr , TFJSBinding } from './tfjs_binding' ; type TensorInfo = { shape : number [ ] ; dtype : number ; values : BackendValues ; id : number ; } ; interface DataId { } export class NodeJSKernelBackend extends KernelBackend { binding : TFJSBinding ; isGPUPackage : boolean ; private tensorMap = new WeakMap < DataId , TensorInfo > ( ) ; constructor ( binding , packageName ) { super ( ) ; this . binding = binding ; this . isGPUPackage = packageName === '@tensorflow/tfjs-node-gpu' ; } setDataMover ( dataMover ) { } private getDTypeInteger ( dtype ) { switch ( dtype ) { case 'float32' : return this . binding . TF_FLOAT ; case 'int32' : return this . binding . TF_INT32 ; case 'bool' : return this . binding . TF_BOOL ; case 'complex64' : return this . binding . TF_COMPLEX64 ; case 'string' : return this . binding . TF_STRING ; default : throw new Error ( `Unsupported DType: ${ dtype }` ) ; } } private typeAttributeFromTensor ( value ) { return this . getDTypeInteger ( value . dtype ) ; } private createOutputTensor ( metadata ) { const newId = { } ; this . tensorMap . set ( newId , { shape : metadata . shape , dtype : metadata . dtype , id : metadata . id , values : null } ) ; let dtype ; switch ( metadata . dtype ) { case this . binding . TF_FLOAT : dtype = 'float32' ; break ; case this . binding . TF_INT32 : dtype = 'int32' ; break ; case this . binding . TF_BOOL : dtype = 'bool' ; break ; case this . binding . TF_COMPLEX64 : dtype = 'complex64' ; break ; case this . binding . TF_STRING : dtype = 'string' ; break ; case this . binding . TF_RESOURCE : dtype = 'string' ; break ; case this . binding . TF_UINT8 : dtype = 'int32' ; break ; default : throw new Error ( `Unknown dtype enum ${ metadata . dtype }` ) ; } return Tensor . make ( metadata . shape , { dataId : newId } , dtype ) ; } private getInputTensorIds ( tensors ) { const ids = [ ] ; for ( let i = 0 ; i < tensors . length ; i ++ ) { if ( tensors [ i ] instanceof Tensor ) { const info = this . tensorMap . get ( ( tensors [ i ] as Tensor ) . dataId ) ; if ( info . values != null ) { info . id = this . binding . createTensor ( info . shape , info . dtype , info . values ) ; info . values = null ; this . tensorMap . set ( ( tensors [ i ] as Tensor ) . dataId , info ) ; } ids . push ( info . id ) ; } else if ( tensors [ i ] instanceof Int64Scalar ) { const value = ( tensors [ i ] as Int64Scalar ) . valueArray ; const id = this . binding . createTensor ( [ ] , this . binding . TF_INT64 , value ) ; ids . push ( id ) ; } else { throw new Error ( `Invalid Tensor type: ${ typeof tensors [ i ] }` ) ; } } return ids ; } private createReductionOpAttrs ( tensor ) { return [ { name : 'keep_dims' , type : this . binding . TF_ATTR_BOOL , value : false } , createTypeOpAttr ( 'T' , tensor . dtype ) , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; } private executeSingleInput ( name , input ) { const opAttrs = [ createTypeOpAttr ( 'T' , input . dtype ) ] ; return this . executeSingleOutput ( name , opAttrs , [ input ] ) ; } floatPrecision ( ) { return 32 ; } epsilon ( ) { return EPSILON_FLOAT32 ; } param name param opAttrs param inputs return executeSingleOutput ( name , opAttrs , inputs ) { const outputMetadata = this . binding . executeOp ( name , opAttrs , this . getInputTensorIds ( inputs ) , 1 ) ; return this . createOutputTensor ( outputMetadata [ 0 ] ) ; } param name param opAttrs param inputs param numOutputs return executeMultipleOutputs ( name , opAttrs , inputs , numOutputs ) { const outputMetadata = this . binding . executeOp ( name , opAttrs , this . getInputTensorIds ( inputs ) , numOutputs ) ; return outputMetadata . map ( m => this . createOutputTensor ( m ) ) ; } dispose ( ) { } async read ( dataId ) { return this . readSync ( dataId ) ; } readSync ( dataId ) { if ( ! this . tensorMap . has ( dataId ) ) { throw new Error ( `Tensor ${ dataId } was not registered!` ) ; } const info = this . tensorMap . get ( dataId ) ; if ( info . values != null ) { return info . values ; } else { return this . binding . tensorDataSync ( info . id ) ; } } disposeData ( dataId ) { const id = this . tensorMap . get ( dataId ) . id ; if ( id != null && id >= 0 ) { this . binding . deleteTensor ( id ) ; } this . tensorMap . delete ( dataId ) ; } write ( dataId , values ) { if ( ! this . tensorMap . has ( dataId ) ) { throw new Error ( `Tensor ${ dataId } was not registered!` ) ; } const info = this . tensorMap . get ( dataId ) ; info . values = values ; this . tensorMap . set ( dataId , info ) ; } register ( dataId , shape , dtype ) { if ( ! this . tensorMap . has ( dataId ) ) { this . tensorMap . set ( dataId , { shape , dtype : getTFDType ( dtype ) , values : null , id : - 1 } ) ; } } fill < R extends Rank > ( shape , value , dtype ? ) { if ( dtype == null ) { if ( typeof value === 'number' ) { dtype = 'float32' ; } else { dtype = 'string' ; } } const shapeTensor = tensor1d ( shape , 'int32' ) ; const valueTensor = scalar ( value , dtype ) ; const opAttrs = [ { name : 'T' , type : this . binding . TF_ATTR_TYPE , value : this . getDTypeInteger ( dtype ) } , { name : 'index_type' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_INT32 } ] ; return this . executeSingleOutput ( 'Fill' , opAttrs , [ shapeTensor , valueTensor ] ) as Tensor < R > ; } onesLike < R extends Rank > ( x ) { const opAttrs = [ { name : 'T' , type : this . binding . TF_ATTR_TYPE , value : this . getDTypeInteger ( x . dtype ) } ] ; return this . executeSingleOutput ( 'OnesLike' , opAttrs , [ x ] ) as Tensor < R > ; } zerosLike < R extends Rank > ( x ) { const opAttrs = [ { name : 'T' , type : this . binding . TF_ATTR_TYPE , value : this . getDTypeInteger ( x . dtype ) } ] ; return this . executeSingleOutput ( 'ZerosLike' , opAttrs , [ x ] ) as Tensor < R > ; } stridedSlice < T extends Tensor > ( x , begin , end , strides , beginMask , endMask , ellipsisMask , newAxisMask , shrinkAxisMask ) { const beginTensor = tensor1d ( begin , 'int32' ) ; const endTensor = tensor1d ( end , 'int32' ) ; const stridesTensor = tensor1d ( strides , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Index' , 'int32' ) , { name : 'begin_mask' , type : this . binding . TF_ATTR_INT , value : beginMask } , { name : 'end_mask' , type : this . binding . TF_ATTR_INT , value : endMask } , { name : 'ellipsis_mask' , type : this . binding . TF_ATTR_INT , value : ellipsisMask } , { name : 'new_axis_mask' , type : this . binding . TF_ATTR_INT , value : newAxisMask } , { name : 'shrink_axis_mask' , type : this . binding . TF_ATTR_INT , value : shrinkAxisMask } ] ; return this . executeSingleOutput ( 'StridedSlice' , opAttrs , [ x , beginTensor , endTensor , stridesTensor ] ) as T ; } unstack ( x , axis ) { if ( axis >= x . shape . length ) { throw new Error ( `Invalid axis supplied: ${ axis } shape length: ${ x . shape . length }` ) ; } const num = x . shape [ axis ] ; const opAttrs = [ { name : 'num' , type : this . binding . TF_ATTR_INT , value : num } , createTypeOpAttr ( 'T' , x . dtype ) , { name : 'axis' , type : this . binding . TF_ATTR_INT , value : axis } ] ; return this . executeMultipleOutputs ( 'Unpack' , opAttrs , [ x ] , num ) ; } batchMatMul ( a , b , transposeA , transposeB ) { const opAttrs = [ createTypeOpAttr ( 'T' , a . dtype ) , { name : 'adj_x' , type : this . binding . TF_ATTR_BOOL , value : transposeA } , { name : 'adj_y' , type : this . binding . TF_ATTR_BOOL , value : transposeB } ] ; return this . executeSingleOutput ( 'BatchMatMul' , opAttrs , [ a , b ] ) as Tensor < Rank . R3 > ; } fusedConv2d ( x , filter , convInfo , bias ? , activation ? , preluActivationWeights ? ) { let result = this . conv2d ( x , filter , convInfo ) ; if ( bias != null ) { result = this . add ( result , bias ) as Tensor4D ; } if ( activation != null ) { if ( activation === 'linear' ) { } else if ( activation === 'relu' ) { result = this . relu ( result ) ; } else if ( activation === 'prelu' ) { result = this . prelu ( result , preluActivationWeights ) as Tensor4D ; } else { throw new Error ( `Activation: ${ activation } has not been implemented for the Node.js backend` ) ; } } return result ; } fusedBatchMatMul ( a , b , transposeA , transposeB , bias ? , activation ? , preluActivationWeights ? ) { let result = this . batchMatMul ( a , b , transposeA , transposeB ) ; if ( bias != null ) { result = this . add ( result , bias ) as Tensor3D ; } if ( activation != null ) { if ( activation === 'linear' ) { } else if ( activation === 'relu' ) { result = this . relu ( result ) ; } else if ( activation === 'prelu' ) { result = this . prelu ( result , preluActivationWeights ) as Tensor3D ; } else { throw new Error ( `Activation: ${ activation } has not been implemented for the Node.js backend` ) ; } } return result ; } slice < T extends Tensor > ( x , begin , size ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Index' , 'int32' ) ] ; const beginTensor = tensor1d ( begin , 'int32' ) ; const sizeTensor = tensor1d ( size , 'int32' ) ; return this . executeSingleOutput ( 'Slice' , opAttrs , [ x , beginTensor , sizeTensor ] ) as T ; } reverse < T extends Tensor > ( a , axis ) { const opAttrs = [ createTypeOpAttr ( 'Tidx' , 'int32' ) , createTypeOpAttr ( 'T' , a . dtype ) ] ; const axisTensor = tensor1d ( axis , 'int32' ) ; return this . executeSingleOutput ( 'ReverseV2' , opAttrs , [ a , axisTensor ] ) as T ; } concat ( tensors , axis ) { const opAttrs = [ { name : 'N' , type : this . binding . TF_ATTR_INT , value : tensors . length } , { name : 'Tidx' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_INT32 } , createTensorsTypeOpAttr ( 'T' , tensors ) ] ; const inputs = Array . from ( tensors ) ; inputs . push ( scalar ( axis , 'int32' ) ) ; return this . executeSingleOutput ( 'ConcatV2' , opAttrs , inputs ) ; } neg < T extends Tensor > ( a ) { return this . executeSingleInput ( 'Neg' , a ) as T ; } add ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Add' , opAttrs , [ a , b ] ) ; } select ( condition , a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Select' , opAttrs , [ condition , a , b ] ) ; } addN < T extends Tensor > ( tensors ) { const opAttrs = [ createTypeOpAttr ( 'T' , tensors [ 0 ] . dtype ) , { name : 'N' , type : this . binding . TF_ATTR_INT , value : tensors . length } ] ; return this . executeSingleOutput ( 'AddN' , opAttrs , tensors ) as T ; } subtract ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Sub' , opAttrs , [ a , b ] ) ; } multiply ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Mul' , opAttrs , [ a , b ] ) ; } realDivide ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'RealDiv' , opAttrs , [ a , b ] ) ; } floorDiv ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'FloorDiv' , opAttrs , [ a , b ] ) ; } divide ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Div' , opAttrs , [ a , b ] ) ; } unsortedSegmentSum < T extends Tensor > ( x , segmentIds , numSegments ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tindices' , 'int32' ) , createTypeOpAttr ( 'Tnumsegments' , 'int32' ) ] ; return this . executeSingleOutput ( 'UnsortedSegmentSum' , opAttrs , [ x , segmentIds , scalar ( numSegments , 'int32' ) ] ) ; } sum ( x , axes ) { const axisTensor = tensor1d ( axes , 'int32' ) ; return this . executeSingleOutput ( 'Sum' , this . createReductionOpAttrs ( x ) , [ x , axisTensor ] ) ; } prod ( x , axes ) { const axesTensor = tensor1d ( axes , 'int32' ) ; const opAttrs = [ { name : 'keep_dims' , type : this . binding . TF_ATTR_BOOL , value : false } , createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; return this . executeSingleOutput ( 'Prod' , opAttrs , [ x , axesTensor ] ) ; } argMin ( x , axis ) { const xInput = x . dtype === 'bool' ? x . toInt ( ) : x ; const axisScalar = scalar ( axis , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , xInput . dtype ) , createTypeOpAttr ( 'Tidx' , 'int32' ) , createTypeOpAttr ( 'output_type' , 'int32' ) ] ; return this . executeSingleOutput ( 'ArgMin' , opAttrs , [ xInput , axisScalar ] ) ; } argMax ( x , axis ) { const xInput = x . dtype === 'bool' ? x . toInt ( ) : x ; const axisScalar = scalar ( axis , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , xInput . dtype ) , createTypeOpAttr ( 'Tidx' , 'int32' ) , createTypeOpAttr ( 'output_type' , 'int32' ) ] ; return this . executeSingleOutput ( 'ArgMax' , opAttrs , [ xInput , axisScalar ] ) ; } equal ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Equal' , opAttrs , [ a , b ] ) ; } notEqual ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'NotEqual' , opAttrs , [ a , b ] ) ; } less ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Less' , opAttrs , [ a , b ] ) ; } lessEqual ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'LessEqual' , opAttrs , [ a , b ] ) ; } greater ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Greater' , opAttrs , [ a , b ] ) ; } greaterEqual ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'GreaterEqual' , opAttrs , [ a , b ] ) ; } logicalNot < T extends Tensor > ( a ) { return this . executeSingleOutput ( 'LogicalNot' , [ ] , [ a ] ) as T ; } logicalAnd ( a , b ) { return this . executeSingleOutput ( 'LogicalAnd' , [ ] , [ a , b ] ) ; } logicalOr ( a , b ) { return this . executeSingleOutput ( 'LogicalOr' , [ ] , [ a , b ] ) ; } where ( condition ) { return this . executeSingleOutput ( 'Where' , [ ] , [ condition ] ) as Tensor2D ; } topKValues < T extends Tensor > ( x , k ) { throw new Error ( 'Method not implemented.' ) ; } topKIndices ( x , k ) { throw new Error ( 'Method not implemented.' ) ; } topk < T extends Tensor > ( x , k ? , sorted ? ) { const kCount = isNullOrUndefined ( k ) ? 1 : k ; const isSorted = isNullOrUndefined ( sorted ) ? true : sorted ; const opAttrs = [ { name : 'sorted' , type : this . binding . TF_ATTR_BOOL , value : isSorted } , createTypeOpAttr ( 'T' , x . dtype ) , ] ; const kTensor = scalar ( kCount , 'int32' ) ; return this . executeMultipleOutputs ( 'TopKV2' , opAttrs , [ x , kTensor ] , 2 ) as [ T , T ] ; } min ( x , axes ) { const axesTensor = tensor1d ( axes , 'int32' ) ; return this . executeSingleOutput ( 'Min' , this . createReductionOpAttrs ( x ) , [ x , axesTensor ] ) ; } minimum ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Minimum' , opAttrs , [ a , b ] ) ; } max ( x , axes ) { const axesTensor = tensor1d ( axes , 'int32' ) ; return this . executeSingleOutput ( 'Max' , this . createReductionOpAttrs ( x ) , [ x , axesTensor ] ) ; } maximum ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , upcastType ( a . dtype , b . dtype ) ) ] ; return this . executeSingleOutput ( 'Maximum' , opAttrs , [ a , b ] ) ; } all ( x , axes ) { const opAttrs = [ { name : 'keep_dims' , type : this . binding . TF_ATTR_BOOL , value : false } , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; const axesTensor = tensor1d ( axes , 'int32' ) ; return this . executeSingleOutput ( 'All' , opAttrs , [ x , axesTensor ] ) ; } any ( x , axes ) { const opAttrs = [ { name : 'keep_dims' , type : this . binding . TF_ATTR_BOOL , value : false } , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; const axesTensor = tensor1d ( axes , 'int32' ) ; return this . executeSingleOutput ( 'Any' , opAttrs , [ x , axesTensor ] ) ; } ceil < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Ceil' , x ) as T ; } floor < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Floor' , x ) as T ; } pow < T extends Tensor > ( a , b ) { const dtype = upcastType ( a . dtype , b . dtype ) ; const opAttrs = [ createTypeOpAttr ( 'T' , dtype ) ] ; return this . executeSingleOutput ( 'Pow' , opAttrs , [ a . cast ( dtype ) , b . cast ( dtype ) ] ) as T ; } exp < T extends Tensor > ( x ) { const xTensor = x . dtype === 'int32' ? x . toFloat ( ) : x ; return this . executeSingleInput ( 'Exp' , xTensor ) as T ; } log < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Log' , x ) as T ; } log1p < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Log1p' , x ) as T ; } sqrt < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Sqrt' , x ) as T ; } square < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Square' , x ) as T ; } relu < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Relu' , x ) as T ; } prelu < T extends Tensor < Rank > > ( x , a ) { const pos = this . relu ( x ) ; const neg = a . mul ( x . sub ( this . abs ( x ) ) ) . mul ( 0.5 ) ; return pos . add ( neg ) ; } elu < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Elu' , x ) as T ; } eluDer < T extends Tensor > ( dy , y ) { const opAttrs = [ createTypeOpAttr ( 'T' , y . dtype ) ] ; return this . executeSingleOutput ( 'EluGrad' , opAttrs , [ dy , y ] ) as T ; } selu < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Selu' , x ) as T ; } int < T extends Tensor > ( x ) { throw new Error ( 'Method not implemented.' ) ; } clip < T extends Tensor > ( x , min , max ) { const xMin = this . minimum ( x , scalar ( max ) ) ; return this . maximum ( xMin , scalar ( min ) ) as T ; } abs < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Abs' , x ) as T ; } complexAbs < T extends Tensor > ( x ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tout' , 'float32' ) ] ; return this . executeSingleOutput ( 'ComplexAbs' , opAttrs , [ x ] ) as T ; } sigmoid < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Sigmoid' , x ) as T ; } sin < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Sin' , x ) as T ; } cos < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Cos' , x ) as T ; } tan < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Tan' , x ) as T ; } asin < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Asin' , x ) as T ; } acos < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Acos' , x ) as T ; } atan < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Atan' , x ) as T ; } sinh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Sinh' , x ) as T ; } cosh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Cosh' , x ) as T ; } tanh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Tanh' , x ) as T ; } mod ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , a . dtype ) ] ; return this . executeSingleOutput ( 'FloorMod' , opAttrs , [ a , b ] ) ; } round < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Round' , x ) as T ; } sign < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Sign' , x ) as T ; } isNaN < T extends Tensor > ( x ) { return this . executeSingleInput ( 'IsNan' , x ) as T ; } isInf < T extends Tensor > ( x ) { return this . executeSingleInput ( 'IsInf' , x ) as T ; } isFinite < T extends Tensor > ( x ) { return this . executeSingleInput ( 'IsFinite' , x ) as T ; } rsqrt < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Rsqrt' , x ) as T ; } reciprocal < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Reciprocal' , x ) as T ; } asinh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Asinh' , x ) as T ; } acosh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Acosh' , x ) as T ; } atanh < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Atanh' , x ) as T ; } erf < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Erf' , x ) as T ; } squaredDifference ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , a . dtype ) ] ; return this . executeSingleOutput ( 'SquaredDifference' , opAttrs , [ a , b ] ) ; } expm1 < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Expm1' , x ) as T ; } softplus < T extends Tensor > ( x ) { return this . executeSingleInput ( 'Softplus' , x ) as T ; } atan2 < T extends Tensor > ( a , b ) { const opAttrs = [ createTypeOpAttr ( 'T' , a . dtype ) ] ; return this . executeSingleOutput ( 'Atan2' , opAttrs , [ a , b ] ) as T ; } step < T extends Tensor > ( x , alpha ) { const dtype = x . dtype ; const nans = this . isNaN ( x ) ; const stepNoNans = this . select ( this . greater ( x , scalar ( 0 , dtype ) ) , ones ( x . shape ) , fill ( x . shape , alpha , dtype ) ) ; return this . select ( nans , x , stepNoNans ) as T ; } conv2d ( x , filter , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'use_cudnn_on_gpu' , type : this . binding . TF_ATTR_BOOL , value : true } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } , ] ; return this . executeSingleOutput ( 'Conv2D' , opAttrs , [ x , filter ] ) as Tensor4D ; } conv2dDerInput ( dy , filter , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , 'float32' ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'use_cudnn_on_gpu' , type : this . binding . TF_ATTR_BOOL , value : true } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; const inputSizes = tensor1d ( convInfo . inShape , 'int32' ) ; return this . executeSingleOutput ( 'Conv2DBackpropInput' , opAttrs , [ inputSizes , filter , dy ] ) as Tensor4D ; } conv2dDerFilter ( x , dy , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , 'float32' ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'use_cudnn_on_gpu' , type : this . binding . TF_ATTR_BOOL , value : true } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; const filterSizes = tensor1d ( convInfo . filterShape , 'int32' ) ; return this . executeSingleOutput ( 'Conv2DBackpropFilter' , opAttrs , [ x , filterSizes , dy ] ) as Tensor4D ; } depthwiseConv2DDerInput ( dy , filter , convInfo ) { const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , 'float32' ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; const inputSizes = tensor1d ( convInfo . inShape , 'int32' ) ; return this . executeSingleOutput ( 'DepthwiseConv2dNativeBackpropInput' , opAttrs , [ inputSizes , filter , dy ] ) as Tensor4D ; } depthwiseConv2DDerFilter ( x , dY , convInfo ) { const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , 'float32' ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; const filterSizes = tensor1d ( convInfo . filterShape , 'int32' ) ; return this . executeSingleOutput ( 'DepthwiseConv2dNativeBackpropFilter' , opAttrs , [ x , filterSizes , dY ] ) as Tensor4D ; } depthwiseConv2D ( input , filter , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const dilations = [ 1 , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , input . dtype ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; return this . executeSingleOutput ( 'DepthwiseConv2dNative' , opAttrs , [ input , filter ] ) as Tensor4D ; } conv3d ( x , filter , convInfo ) { const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; if ( ! this . isGPUPackage && convInfo . dilationDepth > 1 ) { throw new Error ( 'CPU Dilation depth must be 1' ) ; } const dilations = [ 1 , convInfo . dilationDepth , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; return this . executeSingleOutput ( 'Conv3D' , opAttrs , [ x , filter ] ) as Tensor5D ; } conv3dDerInput ( dy , filter , convInfo ) { const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; if ( ! this . isGPUPackage && convInfo . dilationDepth > 1 ) { throw new Error ( 'CPU Dilation depth must be 1' ) ; } const dilations = [ 1 , convInfo . dilationDepth , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , dy . dtype ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } , createTypeOpAttr ( 'Tshape' , 'int32' ) ] ; const inputSizes = tensor1d ( convInfo . inShape , 'int32' ) ; return this . executeSingleOutput ( 'Conv3DBackpropInputV2' , opAttrs , [ inputSizes , filter , dy ] ) as Tensor5D ; } conv3dDerFilter ( x , dY , convInfo ) { const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; if ( ! this . isGPUPackage && convInfo . dilationDepth > 1 ) { throw new Error ( 'CPU Dilation depth must be 1' ) ; } const dilations = [ 1 , convInfo . dilationDepth , convInfo . dilationHeight , convInfo . dilationWidth , 1 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'dilations' , type : this . binding . TF_ATTR_INT , value : dilations } ] ; const filterSizes = tensor1d ( convInfo . filterShape , 'int32' ) ; return this . executeSingleOutput ( 'Conv3DBackpropFilterV2' , opAttrs , [ x , filterSizes , dY ] ) as Tensor5D ; } maxPool ( x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } ] ; return this . executeSingleOutput ( 'MaxPool' , opAttrs , [ x ] ) as Tensor4D ; } maxPoolBackprop ( dy , x , y , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding type was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; return this . executeSingleOutput ( 'MaxPoolGrad' , opAttrs , [ x , y , dy ] ) as Tensor4D ; } avgPool ( x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; return this . executeSingleOutput ( 'AvgPool' , opAttrs , [ x ] ) as Tensor4D ; } avgPoolBackprop ( dy , x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding type was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; const origInputShape = tensor1d ( x . shape , 'int32' ) ; return this . executeSingleOutput ( 'AvgPoolGrad' , opAttrs , [ origInputShape , dy ] ) as Tensor4D ; } avgPool3d ( x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterDepth , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; return this . executeSingleOutput ( 'AvgPool3D' , opAttrs , [ x ] ) as Tensor5D ; } avgPool3dBackprop ( dy , x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding type was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterDepth , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; const origInputShape = tensor1d ( x . shape , 'int32' ) ; return this . executeSingleOutput ( 'AvgPool3DGrad' , opAttrs , [ origInputShape , dy ] ) as Tensor5D ; } maxPool3d ( x , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterDepth , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } ] ; return this . executeSingleOutput ( 'MaxPool3D' , opAttrs , [ x ] ) as Tensor5D ; } maxPool3dBackprop ( dy , x , y , convInfo ) { if ( convInfo . padInfo . type !== 'VALID' && convInfo . padInfo . type !== 'SAME' ) { throw new Error ( `TF Backend supports only 'valid' and 'same' padding ` + `while padding type was ${ convInfo . padInfo . type }` ) ; } const ksize = [ 1 , convInfo . filterDepth , convInfo . filterHeight , convInfo . filterWidth , 1 ] ; const strides = [ 1 , convInfo . strideDepth , convInfo . strideHeight , convInfo . strideWidth , 1 ] ; const padding = convInfo . padInfo . type ; const dataFormat = convInfo . dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW' ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'ksize' , type : this . binding . TF_ATTR_INT , value : ksize } , { name : 'strides' , type : this . binding . TF_ATTR_INT , value : strides } , { name : 'padding' , type : this . binding . TF_ATTR_STRING , value : padding } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , ] ; return this . executeSingleOutput ( 'MaxPool3DGrad' , opAttrs , [ x , y , dy ] ) as Tensor5D ; } reshape < T extends Tensor , R extends Rank > ( x , shape ) { const shapeTensor = tensor1d ( shape , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tshape' , shapeTensor . dtype ) ] ; return this . executeSingleOutput ( 'Reshape' , opAttrs , [ x , shapeTensor ] ) as Tensor < R > ; } cast < T extends Tensor > ( x , dtype ) { const opAttrs = [ createTypeOpAttr ( 'SrcT' , x . dtype ) , createTypeOpAttr ( 'DstT' , dtype ) , { name : 'Truncate' , type : this . binding . TF_ATTR_BOOL , value : false } ] ; return this . executeSingleOutput ( 'Cast' , opAttrs , [ x ] ) as T ; } tile < T extends Tensor > ( x , reps ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tmultiples' , 'int32' ) ] ; const multiples = tensor1d ( reps , 'int32' ) ; return this . executeSingleOutput ( 'Tile' , opAttrs , [ x , multiples ] ) as T ; } pad < T extends Tensor > ( x , paddings , constantValue ) { const paddingsTensor = tensor2d ( paddings , [ paddings . length , 2 ] , 'int32' ) ; const constantTensor = scalar ( constantValue , x . dtype ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tpaddings' , paddingsTensor . dtype ) ] ; return this . executeSingleOutput ( 'PadV2' , opAttrs , [ x , paddingsTensor , constantTensor ] ) as T ; } transpose < T extends Tensor > ( x , perm ) { const permTensor = tensor1d ( perm , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tperm' , 'int32' ) ] ; return this . executeSingleOutput ( 'Transpose' , opAttrs , [ x , permTensor ] ) as T ; } gather < T extends Tensor > ( x , indices , axis ) { const axisTensor = scalar ( axis , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'Tparams' , x . dtype ) , createTypeOpAttr ( 'Tindices' , indices . dtype ) , createTypeOpAttr ( 'Taxis' , 'int32' ) ] ; return this . executeSingleOutput ( 'GatherV2' , opAttrs , [ x , indices , axisTensor ] ) as T ; } gatherND ( x , indices ) { const opAttrs = [ createTypeOpAttr ( 'Tparams' , x . dtype ) , createTypeOpAttr ( 'Tindices' , 'int32' ) ] ; return this . executeSingleOutput ( 'GatherNd' , opAttrs , [ x , indices ] ) ; } scatterND < R extends Rank > ( indices , updates , shape ) { const opAttrs = [ createTypeOpAttr ( 'T' , updates . dtype ) , createTypeOpAttr ( 'Tindices' , 'int32' ) ] ; const shapeTensor = tensor1d ( shape , 'int32' ) ; return this . executeSingleOutput ( 'ScatterNd' , opAttrs , [ indices , updates , shapeTensor ] ) as Tensor < R > ; } batchToSpaceND < T extends Tensor > ( x , blockShape , crops ) { const blockShapeTensor = tensor1d ( blockShape , 'int32' ) ; const cropsTensor = tensor2d ( crops , [ crops . length , crops [ 0 ] . length ] , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tblock_shape' , 'int32' ) , createTypeOpAttr ( 'Tcrops' , cropsTensor . dtype ) ] ; return this . executeSingleOutput ( 'BatchToSpaceND' , opAttrs , [ x , blockShapeTensor , cropsTensor ] ) as T ; } spaceToBatchND < T extends Tensor > ( x , blockShape , paddings ) { const blockShapeTensor = tensor1d ( blockShape , 'int32' ) ; const paddingsTensor = tensor2d ( paddings , [ paddings . length , paddings [ 0 ] . length ] , 'int32' ) ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tblock_shape' , 'int32' ) , createTypeOpAttr ( 'Tpaddings' , paddingsTensor . dtype ) ] ; return this . executeSingleOutput ( 'SpaceToBatchND' , opAttrs , [ x , blockShapeTensor , paddingsTensor ] ) as T ; } resizeBilinear ( x , newHeight , newWidth , alignCorners ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'align_corners' , type : this . binding . TF_ATTR_BOOL , value : alignCorners } , ] ; const size = tensor1d ( [ newHeight , newWidth ] , 'int32' ) ; return this . executeSingleOutput ( 'ResizeBilinear' , opAttrs , [ x , size ] ) as Tensor4D ; } resizeBilinearBackprop ( dy , x , alignCorners ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'align_corners' , type : this . binding . TF_ATTR_BOOL , value : alignCorners } ] ; return this . executeSingleOutput ( 'ResizeBilinearGrad' , opAttrs , [ dy , x ] ) as Tensor4D ; } resizeNearestNeighbor ( x , newHeight , newWidth , alignCorners ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'align_corners' , type : this . binding . TF_ATTR_BOOL , value : alignCorners } , ] ; const size = tensor1d ( [ newHeight , newWidth ] , 'int32' ) ; return this . executeSingleOutput ( 'ResizeNearestNeighbor' , opAttrs , [ x , size ] ) as Tensor4D ; } resizeNearestNeighborBackprop ( dy , x , alignCorners ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'align_corners' , type : this . binding . TF_ATTR_BOOL , value : alignCorners } ] ; const [ , origHeight , origWidth , ] = x . shape ; const size = tensor1d ( [ origHeight , origWidth ] , 'int32' ) ; return this . executeSingleOutput ( 'ResizeNearestNeighborGrad' , opAttrs , [ dy , size ] ) as Tensor4D ; } batchNormalization ( x , mean , variance , varianceEpsilon , scale ? , offset ? ) { if ( mean . rank > 1 ) { let inv = rsqrt ( variance . add ( scalar ( varianceEpsilon ) ) ) ; if ( scale != null ) { inv = inv . mul ( scale ) ; } const xNorm = x . sub ( mean ) . mul ( inv ) as Tensor4D ; return offset != null ? xNorm . add ( offset ) : xNorm ; } const dataFormat = 'NHWC' ; const depth = x . shape [ 3 ] ; const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'epsilon' , type : this . binding . TF_ATTR_FLOAT , value : varianceEpsilon } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } , { name : 'is_training' , type : this . binding . TF_ATTR_BOOL , value : false } , ] ; const numOutputs = 5 ; if ( scale == null ) { scale = fill ( [ depth ] , 1 ) as Tensor1D ; } if ( offset == null ) { offset = fill ( [ depth ] , 0 ) as Tensor1D ; } return this . executeMultipleOutputs ( 'FusedBatchNorm' , opAttrs , [ x , scale , offset , mean , variance ] , numOutputs ) [ 0 ] as Tensor4D ; } localResponseNormalization4D ( x , radius , bias , alpha , beta ) { const opAttrs = [ createTypeOpAttr ( 'T' , x . dtype ) , { name : 'depth_radius' , type : this . binding . TF_ATTR_INT , value : radius } , { name : 'bias' , type : this . binding . TF_ATTR_FLOAT , value : bias } , { name : 'alpha' , type : this . binding . TF_ATTR_FLOAT , value : alpha } , { name : 'beta' , type : this . binding . TF_ATTR_FLOAT , value : beta } , ] ; return this . executeSingleOutput ( 'LRN' , opAttrs , [ x ] ) as Tensor4D ; } LRNGrad ( dy , inputImage , outputImage , radius , bias , alpha , beta ) { const opAttrs = [ createTypeOpAttr ( 'T' , dy . dtype ) , { name : 'depth_radius' , type : this . binding . TF_ATTR_INT , value : radius } , { name : 'bias' , type : this . binding . TF_ATTR_FLOAT , value : bias } , { name : 'alpha' , type : this . binding . TF_ATTR_FLOAT , value : alpha } , { name : 'beta' , type : this . binding . TF_ATTR_FLOAT , value : beta } , ] ; return this . executeSingleOutput ( 'LRNGrad' , opAttrs , [ dy , inputImage , outputImage ] ) as Tensor4D ; } multinomial ( logits , normalized , numSamples , seed ) { if ( normalized ) { throw new Error ( 'TF Node backend does not support normalized logits ' + 'passed to multinomial' ) ; } const opAttrs = [ createTypeOpAttr ( 'T' , logits . dtype ) , createTypeOpAttr ( 'output_dtype' , 'int32' ) , { name : 'seed' , type : this . binding . TF_ATTR_INT , value : seed } , { name : 'seed2' , type : this . binding . TF_ATTR_INT , value : seed * seed } , ] ; return this . executeSingleOutput ( 'Multinomial' , opAttrs , [ logits , scalar ( numSamples , 'int32' ) ] ) as Tensor2D ; } oneHot ( indices , depth , onValue , offValue ) { const depthTensor = scalar ( depth , 'int32' ) ; const onValueTensor = scalar ( onValue , 'int32' ) ; const offValueTensor = scalar ( offValue , 'int32' ) ; const opAttrs = [ { name : 'axis' , type : this . binding . TF_ATTR_INT , value : - 1 } , createTypeOpAttr ( 'T' , indices . dtype ) , createTypeOpAttr ( 'TI' , indices . dtype ) ] ; return this . executeSingleOutput ( 'OneHot' , opAttrs , [ indices , depthTensor , onValueTensor , offValueTensor ] ) as Tensor2D ; } cumsum ( x , axis , exclusive , reverse ) { const axisTensor = scalar ( axis , 'int32' ) ; const opAttrs = [ { name : 'exclusive' , type : this . binding . TF_ATTR_BOOL , value : exclusive } , { name : 'reverse' , type : this . binding . TF_ATTR_BOOL , value : reverse } , createTypeOpAttr ( 'T' , x . dtype ) , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; return this . executeSingleOutput ( 'Cumsum' , opAttrs , [ x , axisTensor ] ) ; } nonMaxSuppression ( boxes , scores , maxOutputSize , iouThreshold ? , scoreThreshold ? ) { const opAttrs = [ createTypeOpAttr ( 'T' , boxes . dtype ) ] ; const maxOutputSizeTensor = scalar ( maxOutputSize , 'int32' ) ; const iouThresholdTensor = scalar ( iouThreshold ) ; const scoreThresholdTensor = scalar ( scoreThreshold ) ; return this . executeSingleOutput ( 'NonMaxSuppressionV3' , opAttrs , [ boxes , scores , maxOutputSizeTensor , iouThresholdTensor , scoreThresholdTensor ] ) as Tensor1D ; } fft ( x ) { const opAttrs = [ createTypeOpAttr ( 'Tcomplex' , x . dtype ) ] ; return this . executeSingleOutput ( 'FFT' , opAttrs , [ x ] ) as Tensor < Rank . R2 > ; } ifft ( x ) { const opAttrs = [ createTypeOpAttr ( 'Tcomplex' , x . dtype ) ] ; return this . executeSingleOutput ( 'IFFT' , opAttrs , [ x ] ) as Tensor2D ; } complex < T extends Tensor < Rank > > ( real , imag ) { const opAttrs = [ createTensorsTypeOpAttr ( 'T' , real ) , { name : 'Tout' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_COMPLEX64 } , ] ; const inputs = [ real , imag ] ; return this . executeSingleOutput ( 'Complex' , opAttrs , inputs ) as T ; } real < T extends Tensor < Rank > > ( input ) { const opAttrs = [ createTensorsTypeOpAttr ( 'T' , input ) , { name : 'Tout' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_FLOAT } ] ; const inputs = [ input ] ; return this . executeSingleOutput ( 'Real' , opAttrs , inputs ) as T ; } imag < T extends Tensor < Rank > > ( input ) { const opAttrs = [ { name : 'T' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_COMPLEX64 } , { name : 'Tout' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_FLOAT } ] ; const inputs = [ input ] ; return this . executeSingleOutput ( 'Imag' , opAttrs , inputs ) as T ; } cropAndResize ( image , boxes , boxIndex , cropSize , method , extrapolationValue ) { const opAttrs = [ createTypeOpAttr ( 'T' , image . dtype ) , { name : 'method' , type : this . binding . TF_ATTR_STRING , value : method } , { name : 'extrapolation_value' , type : this . binding . TF_ATTR_FLOAT , value : extrapolationValue } ] ; const cropSizeTensor = tensor1d ( cropSize , 'int32' ) ; return this . executeSingleOutput ( 'CropAndResize' , opAttrs , [ image , boxes , boxIndex , cropSizeTensor ] ) as Tensor < Rank . R4 > ; } depthToSpace ( x , blockSize , dataFormat ) { const opAttrs = [ createTensorsTypeOpAttr ( 'T' , x ) , { name : 'block_size' , type : this . binding . TF_ATTR_INT , value : blockSize < 2 ? 2 : blockSize } , { name : 'data_format' , type : this . binding . TF_ATTR_STRING , value : dataFormat } ] ; const inputs = [ x ] ; return this . executeSingleOutput ( 'DepthToSpace' , opAttrs , inputs ) as Tensor < Rank . R4 > ; } split < T extends Tensor < Rank > > ( value , sizeSplits , axis ) { const opAttrs = [ { name : 'num_split' , type : this . binding . TF_ATTR_INT , value : sizeSplits . length } , createTensorsTypeOpAttr ( 'T' , value ) , { name : 'Tlen' , type : this . binding . TF_ATTR_TYPE , value : this . binding . TF_INT32 } ] ; const inputs = [ value ] ; inputs . push ( tensor1d ( sizeSplits , 'int32' ) as T ) ; inputs . push ( scalar ( axis , 'int32' ) as T ) ; return this . executeMultipleOutputs ( 'SplitV' , opAttrs , inputs , sizeSplits . length ) as T [ ] ; } sparseToDense < R extends Rank > ( sparseIndices , sparseValues , outputShape , defaultValue ) { const opAttrs = [ { name : 'validate_indices' , type : this . binding . TF_ATTR_BOOL , value : true } , createTypeOpAttr ( 'T' , sparseValues . dtype ) , createTypeOpAttr ( 'Tindices' , sparseIndices . dtype ) ] ; const outputShapeTensor = tensor1d ( outputShape , 'int32' ) ; return this . executeSingleOutput ( 'SparseToDense' , opAttrs , [ sparseIndices , outputShapeTensor , sparseValues , defaultValue ] ) as Tensor < R > ; } linspace ( start , stop , num ) { const opAttrs = [ createTypeOpAttr ( 'T' , 'float32' ) , createTypeOpAttr ( 'Tidx' , 'int32' ) ] ; const inputs = [ scalar ( start , 'float32' ) , scalar ( stop , 'float32' ) , scalar ( num , 'int32' ) ] ; return this . executeSingleOutput ( 'LinSpace' , opAttrs , inputs ) as Tensor1D ; } fromPixels ( pixels , numChannels ) { if ( pixels == null ) { throw new Error ( 'pixels passed to fromPixels() can not be null' ) ; } if ( ( pixels as any ) . getContext == null ) { throw new Error ( 'When running in node, pixels must be an HTMLCanvasElement ' + 'like the one returned by the `canvas` npm package' ) ; } const vals = ( pixels as any ) . getContext ( '2d' ) . getImageData ( 0 , 0 , pixels . width , pixels . height ) . data ; let values ; if ( numChannels === 4 ) { values = new Int32Array ( vals ) ; } else { const numPixels = pixels . width * pixels . height ; values = new Int32Array ( numPixels * numChannels ) ; for ( let i = 0 ; i < numPixels ; i ++ ) { for ( let channel = 0 ; channel < numChannels ; ++ channel ) { values [ i * numChannels + channel ] = vals [ i * 4 + channel ] ; } } } const outShape = [ pixels . height , pixels . width , numChannels ] ; return tensor3d ( values , outShape , 'int32' ) ; } decodeJpeg ( contents , channels , ratio , fancyUpscaling , tryRecoverTruncated , acceptableFraction , dctMethod ) { const opAttrs = [ { name : 'channels' , type : this . binding . TF_ATTR_INT , value : channels } , { name : 'ratio' , type : this . binding . TF_ATTR_INT , value : ratio } , { name : 'fancy_upscaling' , type : this . binding . TF_ATTR_BOOL , value : fancyUpscaling } , { name : 'try_recover_truncated' , type : this . binding . TF_ATTR_BOOL , value : tryRecoverTruncated } , { name : 'acceptable_fraction' , type : this . binding . TF_ATTR_FLOAT , value : acceptableFraction } , { name : 'dct_method' , type : this . binding . TF_ATTR_STRING , value : dctMethod } ] ; const inputArgs = [ scalar ( contents , 'string' ) ] ; return this . executeSingleOutput ( 'DecodeJpeg' , opAttrs , inputArgs ) as Tensor < Rank . R3 > ; } decodePng ( contents , channels ) { const opAttrs = [ { name : 'channels' , type : this . binding . TF_ATTR_INT , value : channels } ] ; const inputArgs = [ scalar ( contents , 'string' ) ] ; return this . executeSingleOutput ( 'DecodePng' , opAttrs , inputArgs ) as Tensor < Rank . R3 > ; } decodeBmp ( contents , channels ) { const opAttrs = [ { name : 'channels' , type : this . binding . TF_ATTR_INT , value : channels } ] ; const inputArgs = [ scalar ( contents , 'string' ) ] ; return this . executeSingleOutput ( 'DecodeBmp' , opAttrs , inputArgs ) as Tensor < Rank . R3 > ; } decodeGif ( contents ) { const inputArgs = [ scalar ( contents , 'string' ) ] ; return this . executeSingleOutput ( 'DecodeGif' , [ ] , inputArgs ) as Tensor < Rank . R4 > ; } summaryWriter ( logdir ) { const opAttrs = [ { name : 'shared_name' , type : this . binding . TF_ATTR_STRING , value : `logdir:${ logdir }` } , { name : 'container' , type : this . binding . TF_ATTR_STRING , value : '' } ] ; const writerResource = this . executeSingleOutput ( 'SummaryWriter' , opAttrs , [ ] ) ; return writerResource as Tensor1D ; } createSummaryFileWriter ( resourceHandle , logdir , maxQueue ? , flushMillis ? , filenameSuffix ? ) { const inputArgs = [ resourceHandle , scalar ( logdir ) , scalar ( maxQueue == null ? 10 : maxQueue , 'int32' ) , scalar ( flushMillis == null ? 2 * 60 * 1000 : flushMillis , 'int32' ) , scalar ( filenameSuffix == null ? '.v2' : filenameSuffix ) ] ; this . executeMultipleOutputs ( 'CreateSummaryFileWriter' , [ ] , inputArgs , 0 ) ; } writeScalarSummary ( resourceHandle , step , name , value ) { tidy ( ( ) => { util . assert ( Number . isInteger ( step ) , ( ) => `step is expected to be an integer, but is instead ${ step }` ) ; const inputArgs = [ resourceHandle , new Int64Scalar ( step ) , scalar ( name , 'string' ) ] ; let typeAttr ; if ( typeof value === 'number' ) { inputArgs . push ( scalar ( value ) ) ; typeAttr = this . binding . TF_FLOAT ; } else { util . assert ( value . rank === 0 , ( ) => `A non-scalar tensor (rank ${ value . rank }) is passed to ` + `writeScalarSummary()` ) ; inputArgs . push ( value ) ; typeAttr = this . typeAttributeFromTensor ( value ) ; } const opAttrs = [ { name : 'T' , type : this . binding . TF_ATTR_TYPE , value : typeAttr } ] ; this . binding . executeOp ( 'WriteScalarSummary' , opAttrs , this . getInputTensorIds ( inputArgs ) , 0 ) ; } ) ; } flushSummaryWriter ( resourceHandle ) { const inputArgs = [ resourceHandle ] ; this . executeMultipleOutputs ( 'FlushSummaryWriter' , [ ] , inputArgs , 0 ) ; } memory ( ) { return { unreliable : true } ; } async time ( f ) { const start = process . hrtime ( ) ; f ( ) ; const elapsed = process . hrtime ( start ) ; return { kernelMs : elapsed [ 0 ] * 1000 + elapsed [ 1 ] / 1000000 } ; } }