license import { KernelConfig , KernelFunc , ResizeBilinearGrad , ResizeBilinearGradAttrs , ResizeBilinearGradInputs , TensorInfo , TypedArray , util } from '@tensorflow/tfjs-core' ; import { MathBackendCPU } from '../backend_cpu' ; import { assertNotComplex } from '../cpu_util' ; export function resizeBilinearGrad ( args ) { const { inputs , backend , attrs } = args ; const { images , dy } = inputs ; const { alignCorners } = attrs ; assertNotComplex ( [ dy , images ] , 'resizeBilinearGrad' ) ; const imagesStrides = util . computeStrides ( images . shape ) ; const [ batch , xHeight , xWidth , depth ] = images . shape ; const [ , yHeight , yWidth ] = dy . shape ; const output = new Float32Array ( batch * xHeight * xWidth * depth ) ; const effectiveXSize = [ ( alignCorners && yHeight > 1 ) ? xHeight - 1 : xHeight , ( alignCorners && yWidth > 1 ) ? xWidth - 1 : xWidth ] ; const effectiveYSize = [ ( alignCorners && yHeight > 1 ) ? yHeight - 1 : yHeight , ( alignCorners && yWidth > 1 ) ? yWidth - 1 : yWidth ] ; const heightScale = effectiveXSize [ 0 ] / effectiveYSize [ 0 ] ; const widthScale = effectiveXSize [ 1 ] / effectiveYSize [ 1 ] ; const dyValues = backend . data . get ( dy . dataId ) . values as TypedArray ; let offset = 0 ; for ( let b = 0 ; b < batch ; b ++ ) { const bOffset = b * imagesStrides [ 0 ] ; for ( let r = 0 ; r < yHeight ; r ++ ) { const dxR = r * heightScale ; const topDxRIndex = Math . floor ( dxR ) ; const bottomDxRIndex = Math . min ( Math . ceil ( dxR ) , xHeight - 1 ) ; const topDxROffset = bOffset + topDxRIndex * imagesStrides [ 1 ] ; const bottomDxROffset = bOffset + bottomDxRIndex * imagesStrides [ 1 ] ; const dxRLerp = dxR - topDxRIndex ; const inverseDxRLerp = 1.0 - dxRLerp ; for ( let c = 0 ; c < yWidth ; c ++ ) { const dxC = c * widthScale ; const leftDxCIndex = Math . floor ( dxC ) ; const rightDxCIndex = Math . min ( Math . ceil ( dxC ) , xWidth - 1 ) ; const dxCLerp = dxC - leftDxCIndex ; const inverseDxCLerp = 1.0 - dxCLerp ; const topLeftRCOffset = topDxROffset + leftDxCIndex * imagesStrides [ 2 ] ; const topRightRCOffset = topDxROffset + rightDxCIndex * imagesStrides [ 2 ] ; const bottomLeftRCOffset = bottomDxROffset + leftDxCIndex * imagesStrides [ 2 ] ; const bottomRightRCOffset = bottomDxROffset + rightDxCIndex * imagesStrides [ 2 ] ; const inverseDxRLerpTimesInverseDxCLerp = inverseDxRLerp * inverseDxCLerp ; const inverseDxRLerpTimesDxCLerp = inverseDxRLerp * dxCLerp ; const dxRLerpTimesInverseDxCLerp = dxRLerp * inverseDxCLerp ; const dxRLerpTimesDxCLerp = dxRLerp * dxCLerp ; for ( let d = 0 ; d < depth ; d ++ ) { const dyVal = dyValues [ offset ++ ] ; output [ topLeftRCOffset + d ] += dyVal * inverseDxRLerpTimesInverseDxCLerp ; output [ topRightRCOffset + d ] += dyVal * inverseDxRLerpTimesDxCLerp ; output [ bottomLeftRCOffset + d ] += dyVal * dxRLerpTimesInverseDxCLerp ; output [ bottomRightRCOffset + d ] += dyVal * dxRLerpTimesDxCLerp ; } } } } return backend . makeTensorInfo ( [ batch , xWidth , xHeight , depth ] , 'float32' , output ) ; } export const resizeBilinearGradConfig = { kernelName : ResizeBilinearGrad , backendName : 'cpu' , kernelFunc : resizeBilinearGrad as { } as KernelFunc } ;