(args: {
inputs: MaxPoolGradInputs,
backend: MathBackendCPU,
attrs: MaxPoolGradAttrs
})
| 21 | import {maxPoolPositions} from '../utils/pool_utils'; |
| 22 | |
| 23 | export function maxPoolGrad(args: { |
| 24 | inputs: MaxPoolGradInputs, |
| 25 | backend: MathBackendCPU, |
| 26 | attrs: MaxPoolGradAttrs |
| 27 | }): TensorInfo { |
| 28 | const {inputs, backend, attrs} = args; |
| 29 | const {dy, input, output} = inputs; |
| 30 | const x = input; |
| 31 | assertNotComplex([input, output], 'maxPoolGrad'); |
| 32 | const {filterSize, strides, pad, dimRoundingMode} = attrs; |
| 33 | |
| 34 | const convInfo = backend_util.computePool2DInfo( |
| 35 | x.shape as [number, number, number, number], filterSize, strides, |
| 36 | 1 /* dilations */, pad, dimRoundingMode); |
| 37 | const xValues = backend.data.get(x.dataId).values as TypedArray; |
| 38 | const maxPosBuf = buffer( |
| 39 | convInfo.outShape, x.dtype, |
| 40 | maxPoolPositions(xValues, x.shape, x.dtype, convInfo).values); |
| 41 | const strideHeight = convInfo.strideHeight; |
| 42 | const strideWidth = convInfo.strideWidth; |
| 43 | const dilationHeight = convInfo.dilationHeight; |
| 44 | const dilationWidth = convInfo.dilationWidth; |
| 45 | const effectiveFilterHeight = convInfo.effectiveFilterHeight; |
| 46 | const effectiveFilterWidth = convInfo.effectiveFilterWidth; |
| 47 | const padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left; |
| 48 | const padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top; |
| 49 | const dx = |
| 50 | buffer<Rank.R4>(x.shape as [number, number, number, number], 'float32'); |
| 51 | |
| 52 | const dyData = backend.data.get(dy.dataId).values as Float32Array; |
| 53 | const dyBuf = buffer<Rank.R4>( |
| 54 | dy.shape as [number, number, number, number], 'float32', dyData); |
| 55 | |
| 56 | for (let b = 0; b < convInfo.batchSize; ++b) { |
| 57 | for (let d = 0; d < convInfo.inChannels; ++d) { |
| 58 | for (let dxR = 0; dxR < convInfo.inHeight; ++dxR) { |
| 59 | for (let dxC = 0; dxC < convInfo.inWidth; ++dxC) { |
| 60 | // Shader code begins. |
| 61 | const dyRCorner = dxR - padTop; |
| 62 | const dyCCorner = dxC - padLeft; |
| 63 | let dotProd = 0; |
| 64 | for (let wR = 0; wR < effectiveFilterHeight; wR += dilationHeight) { |
| 65 | const dyR = (dyRCorner + wR) / strideHeight; |
| 66 | if (dyR < 0 || dyR >= convInfo.outHeight || |
| 67 | Math.floor(dyR) !== dyR) { |
| 68 | continue; |
| 69 | } |
| 70 | for (let wC = 0; wC < effectiveFilterWidth; wC += dilationWidth) { |
| 71 | const dyC = (dyCCorner + wC) / strideWidth; |
| 72 | if (dyC < 0 || dyC >= convInfo.outWidth || |
| 73 | Math.floor(dyC) !== dyC) { |
| 74 | continue; |
| 75 | } |
| 76 | const maxPos = effectiveFilterHeight * effectiveFilterWidth - 1 - |
| 77 | (maxPosBuf.get(b, dyR, dyC, d) as number); |
| 78 | const curPos = wR * effectiveFilterWidth + wC; |
| 79 | |
| 80 | const mask = maxPos === curPos ? 1 : 0; |
no test coverage detected
searching dependent graphs…