/// <summary> /// Spatials the maximum pooling forward. /// </summary> /// <param name="input">The input.</param> /// <param name="output">The output.</param> /// <param name="indices">The indices.</param> /// <param name="cd">The cd.</param> /// <param name="ceilMode">if set to <c>true</c> [ceil mode].</param> /// <exception cref="ArgumentException">input must be a 4D tensor</exception> /// <exception cref="InvalidOperationException"> /// input image is smaller than kernel size /// or /// pad should be smaller than half of the kernel size /// </exception> public static void SpatialMaxPoolingForward(NDArray input, NDArray output, NDArray indices, ConvolutionDesc2d cd, bool ceilMode) { if (input.DimensionCount != 4) { throw new ArgumentException("input must be a 4D tensor"); } var dimw = 3; var dimh = 2; var dimc = 1; if (input.Shape[dimw] < cd.kW - cd.padW || input.Shape[dimh] < cd.kH - cd.padH) { throw new InvalidOperationException("input image is smaller than kernel size"); } if (cd.padW > cd.kW / 2 || cd.padH > cd.kH / 2) { throw new InvalidOperationException("pad should be smaller than half of the kernel size"); } var nbatch = input.Shape[0]; var nslices = input.Shape[dimc]; var iheight = input.Shape[dimh]; var iwidth = input.Shape[dimw]; long owidth; long oheight; if (ceilMode) { oheight = (long)(Math.Ceiling((float)(iheight - cd.kH + 2 * cd.padH) / cd.dH)) + 1; owidth = (long)(Math.Ceiling((float)(iwidth - cd.kW + 2 * cd.padW) / cd.dW)) + 1; } else { oheight = (long)(Math.Floor((float)(iheight - cd.kH + 2 * cd.padH) / cd.dH)) + 1; owidth = (long)(Math.Floor((float)(iwidth - cd.kW + 2 * cd.padW) / cd.dW)) + 1; } if (cd.padW != 0 || cd.padH != 0) { // ensure that the last pooling starts inside the image if ((oheight - 1) * cd.dH >= iheight + cd.padH) { --oheight; } if ((owidth - 1) * cd.dW >= iwidth + cd.padW) { --owidth; } } using (var inputContig = Ops.AsContiguous(input)) { for (int i = 0; i < nbatch; ++i) { using (var input_i = inputContig.Select(0, i)) using (var output_i = output.Select(0, i)) using (var indices_i = indices.Select(0, i)) { IntPtr input_iPtr, output_iPtr, indices_iPtr; using (NativeWrapper.BuildTensorRefPtr(input_i, out input_iPtr)) using (NativeWrapper.BuildTensorRefPtr(output_i, out output_iPtr)) using (NativeWrapper.BuildTensorRefPtr(indices_i, out indices_iPtr)) { CpuOpsNative.TS_SpatialMaxPooling_updateOutput_frame(input_iPtr, output_iPtr, indices_iPtr, nslices, iwidth, iheight, owidth, oheight, cd.kW, cd.kH, cd.dW, cd.dH, cd.padW, cd.padH); } } } } }