| 229 | userCode: string; |
| 230 | |
| 231 | constructor( |
| 232 | convInfo: backend_util.Conv3DInfo, poolType: 'max'|'avg', |
| 233 | computePositions: boolean, flattenPositions = false, |
| 234 | includeBatchInIndex = false) { |
| 235 | if (poolType === 'avg' && computePositions) { |
| 236 | throw new Error('Cannot compute positions for average pool.'); |
| 237 | } |
| 238 | |
| 239 | const filterWidth = convInfo.filterWidth; |
| 240 | const strideDepth = convInfo.strideDepth; |
| 241 | const strideHeight = convInfo.strideHeight; |
| 242 | const strideWidth = convInfo.strideWidth; |
| 243 | const dilationDepth = convInfo.dilationDepth; |
| 244 | const dilationHeight = convInfo.dilationHeight; |
| 245 | const dilationWidth = convInfo.dilationWidth; |
| 246 | const effectiveFilterDepth = convInfo.effectiveFilterDepth; |
| 247 | const effectiveFilterHeight = convInfo.effectiveFilterHeight; |
| 248 | const effectiveFilterWidth = convInfo.effectiveFilterWidth; |
| 249 | |
| 250 | const padFront = convInfo.padInfo.front; |
| 251 | const padTop = convInfo.padInfo.top; |
| 252 | const padLeft = convInfo.padInfo.left; |
| 253 | this.outputShape = convInfo.outShape; |
| 254 | |
| 255 | const isAvgPool = poolType === 'avg'; |
| 256 | |
| 257 | let initializationValue = '0.0'; |
| 258 | if (!isAvgPool) { |
| 259 | // WebGL on Firefox Linux can't compile 1/0 so we do 1/eps. |
| 260 | initializationValue = '-1.0 / 1e-20'; |
| 261 | } |
| 262 | |
| 263 | if (computePositions) { |
| 264 | const compareOp = '>='; |
| 265 | |
| 266 | this.userCode = ` |
| 267 | const ivec3 strides = |
| 268 | ivec3(${strideDepth}, ${strideHeight}, ${strideWidth}); |
| 269 | const ivec3 pads = ivec3(${padFront}, ${padTop}, ${padLeft}); |
| 270 | |
| 271 | void main() { |
| 272 | ivec5 coords = getOutputCoords(); |
| 273 | int batch = coords.x; |
| 274 | int ch = coords.u; |
| 275 | |
| 276 | ivec3 xCorner = ivec3(coords.y, coords.z, coords.w) * strides - pads; |
| 277 | int xDCorner = xCorner.x; |
| 278 | int xRCorner = xCorner.y; |
| 279 | int xCCorner = xCorner.z; |
| 280 | |
| 281 | // max/min x(?, ?, ?, ch) to get y(yD, yR, yC, ch). |
| 282 | // ? = to be determined |
| 283 | float minMaxValue = 0.0; |
| 284 | float minMaxValueFound = 0.0; |
| 285 | int minMaxPosition = 0; |
| 286 | |
| 287 | for (int wD = 0; wD < ${effectiveFilterDepth}; |
| 288 | wD += ${dilationDepth}) { |