/// <summary> /// Outputs the size. /// </summary> /// <param name="inputSizes">The input sizes.</param> /// <param name="weightSizes">The weight sizes.</param> /// <param name="cd">The cd.</param> /// <returns>System.Int64[].</returns> public static long[] OutputSize(long[] inputSizes, long[] weightSizes, ConvolutionDesc2d cd) { int dimf = 1; int dimw = 3; int dimh = 2; var n = inputSizes[0]; var nInputPlane = inputSizes[dimf]; var inputWidth = inputSizes[dimw]; var inputHeight = inputSizes[dimh]; var nOutputPlane = weightSizes[0]; var outputWidth = (inputWidth + 2 * cd.padW - cd.kW) / cd.dW + 1; var outputHeight = (inputHeight + 2 * cd.padH - cd.kH) / cd.dH + 1; return(new long[] { n, nOutputPlane, outputHeight, outputWidth }); }
/// <summary> /// Outputs the size. /// </summary> /// <param name="inputSizes">The input sizes.</param> /// <param name="ceilMode">if set to <c>true</c> [ceil mode].</param> /// <param name="cd">The cd.</param> /// <returns>System.Int64[].</returns> public static long[] OutputSize(long[] inputSizes, bool ceilMode, ConvolutionDesc2d cd) { int dimw = 3; int dimh = 2; var iwidth = inputSizes[dimw]; var iheight = inputSizes[dimh]; long oheight, owidth; 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; } return(new long[] { inputSizes[0], inputSizes[1], oheight, owidth }); }
/// <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); } } } } }
/// <summary> /// Spatials the maximum pooling backward. /// </summary> /// <param name="input">The input.</param> /// <param name="gradOutput">The grad output.</param> /// <param name="gradInput">The grad input.</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> public static void SpatialMaxPoolingBackward(NDArray input, NDArray gradOutput, NDArray gradInput, NDArray indices, ConvolutionDesc2d cd, bool ceilMode) { var dimw = 3; var dimh = 2; var dimc = 1; var nbatch = input.Shape[0]; var nslices = input.Shape[dimc]; var iheight = input.Shape[dimh]; var iwidth = input.Shape[dimw]; var owidth = gradOutput.Shape[dimw]; var oheight = gradOutput.Shape[dimh]; Ops.Fill(gradInput, 0); using (var gradOutputContig = Ops.AsContiguous(gradOutput)) { for (int i = 0; i < nbatch; ++i) { using (var gradInput_i = gradInput.Select(0, i)) using (var gradOutput_i = gradOutputContig.Select(0, i)) using (var indices_i = indices.Select(0, i)) { IntPtr gradInput_iPtr, gradOutput_iPtr, indices_iPtr; using (NativeWrapper.BuildTensorRefPtr(gradInput_i, out gradInput_iPtr)) using (NativeWrapper.BuildTensorRefPtr(gradOutput_i, out gradOutput_iPtr)) using (NativeWrapper.BuildTensorRefPtr(indices_i, out indices_iPtr)) { CpuOpsNative.TS_SpatialMaxPooling_updateGradInput_frame(gradInput_iPtr, gradOutput_iPtr, indices_iPtr, nslices, iwidth, iheight, owidth, oheight, cd.dW, cd.dH); } } } } }
/// <summary> /// Conv2s the backward filter frame. /// </summary> /// <param name="gradOutput">The grad output.</param> /// <param name="gradWeight">The grad weight.</param> /// <param name="gradBias">The grad bias.</param> /// <param name="finput">The finput.</param> /// <param name="cd">The cd.</param> private static void Conv2BackwardFilterFrame(NDArray gradOutput, NDArray gradWeight, NDArray gradBias, NDArray finput, ConvolutionDesc2d cd) { using (var gradOutput2d = gradOutput.View(gradOutput.Shape[0], gradOutput.Shape[1] * gradOutput.Shape[2])) using (var finputT = finput.Transpose()) { Ops.Addmm(gradWeight, 1, gradWeight, 1, gradOutput2d, finputT); Ops.Sum(gradBias, gradOutput2d, 1); } }
/// <summary> /// Conv2s the backward filter. /// </summary> /// <param name="input">The input.</param> /// <param name="gradOutput">The grad output.</param> /// <param name="gradWeight">The grad weight.</param> /// <param name="gradBias">The grad bias.</param> /// <param name="finput">The finput.</param> /// <param name="fgradInput">The fgrad input.</param> /// <param name="cd">The cd.</param> /// <exception cref="InvalidOperationException"> /// Number of output features must equal nOutputPlane /// or /// Kernel size should be greater than zero /// or /// stride should be greater than zero /// </exception> public static void Conv2BackwardFilter(NDArray input, NDArray gradOutput, NDArray gradWeight, NDArray gradBias, NDArray finput, NDArray fgradInput, ConvolutionDesc2d cd) { var nOutputPlane = gradWeight.Shape[0]; var n = input.Shape[0]; if (gradOutput.Shape[1] != nOutputPlane) { throw new InvalidOperationException("Number of output features must equal nOutputPlane"); } if (cd.kW <= 0 && cd.kH <= 0) { throw new InvalidOperationException("Kernel size should be greater than zero"); } if (cd.dW <= 0 && cd.dH <= 0) { throw new InvalidOperationException("stride should be greater than zero"); } for (int i = 0; i < n; ++i) { using (var gradOutput_i = gradOutput.Select(0, i)) using (var finput_i = finput.Select(0, i)) { Conv2BackwardFilterFrame(gradOutput_i, gradWeight, gradBias, finput_i, cd); } } }
/// <summary> /// Conv2s the backward input frame. /// </summary> /// <param name="gradOutput">The grad output.</param> /// <param name="gradInput">The grad input.</param> /// <param name="weight">The weight.</param> /// <param name="fgradInput">The fgrad input.</param> /// <param name="cd">The cd.</param> private static void Conv2BackwardInputFrame(NDArray gradOutput, NDArray gradInput, NDArray weight, NDArray fgradInput, ConvolutionDesc2d cd) { using (var gradOutput2d = gradOutput.View(gradOutput.Shape[0], gradOutput.Shape[1] * gradOutput.Shape[2])) { Ops.Addmm(fgradInput, 0, fgradInput, 1, weight, gradOutput2d); } Ops.Fill(gradInput, 0); IntPtr fgradInputPtr, gradInputPtr; using (NativeWrapper.BuildTensorRefPtr(fgradInput, out fgradInputPtr)) using (NativeWrapper.BuildTensorRefPtr(gradInput, out gradInputPtr)) { CpuOpsNative.TS_Unfolded_Acc(fgradInputPtr, gradInputPtr, cd.kW, cd.kH, cd.dW, cd.dH, cd.padW, cd.padH, (int)gradInput.Shape[0], (int)gradInput.Shape[2], (int)gradInput.Shape[1], (int)gradOutput.Shape[2], (int)gradOutput.Shape[1]); } }
/// <summary> /// Conv2s the forward. /// </summary> /// <param name="input">The input.</param> /// <param name="output">The output.</param> /// <param name="weight">The weight.</param> /// <param name="bias">The bias.</param> /// <param name="finput">The finput.</param> /// <param name="cd">The cd.</param> /// <exception cref="InvalidOperationException"> /// bias has incorrect size. Expected 1D tensor of size " + nOutputPlane /// or /// or /// or /// 4D input expected (NCHW order) /// or /// finput is incorrect size /// or /// output is incorrect size /// </exception> public static void Conv2Forward(NDArray input, NDArray output, NDArray weight, NDArray bias, NDArray finput, ConvolutionDesc2d cd) { int dimf = 1; int dimw = 3; int dimh = 2; var n = input.Shape[0]; var nInputPlane = input.Shape[dimf]; var inputWidth = input.Shape[dimw]; var inputHeight = input.Shape[dimh]; var nOutputPlane = weight.Shape[0]; var outputWidth = (inputWidth + 2 * cd.padW - cd.kW) / cd.dW + 1; var outputHeight = (inputHeight + 2 * cd.padH - cd.kH) / cd.dH + 1; if (bias != null && (bias.Shape[0] != nOutputPlane)) { throw new InvalidOperationException("bias has incorrect size. Expected 1D tensor of size " + nOutputPlane); } if (outputWidth < 1 || outputHeight < 1) { throw new InvalidOperationException(string.Format( "Output size too small; calculated output size = ({0}x{1}x{2}", nOutputPlane, outputHeight, outputWidth)); } if (nInputPlane * cd.kW * cd.kH != weight.Shape[1]) { throw new InvalidOperationException( string.Format("Input has incorrect number of channels. Got {0}, expected {1}", nInputPlane, weight.Shape[1] / ((float)(cd.kW * cd.kH)))); } if (input.DimensionCount != 4) { throw new InvalidOperationException("4D input expected (NCHW order)"); } if (finput.Shape[0] != n || finput.Shape[1] != cd.kW * cd.kH * nInputPlane || finput.Shape[2] != outputHeight * outputWidth) { throw new InvalidOperationException("finput is incorrect size"); } if (output.Shape[0] != n || output.Shape[1] != nOutputPlane || output.Shape[2] != outputHeight || output.Shape[3] != outputWidth) { throw new InvalidOperationException("output is incorrect size"); } for (int i = 0; i < n; ++i) { using (var input_i = input.Select(0, i)) using (var output_i = output.Select(0, i)) using (var finput_i = finput.Select(0, i)) { Conv2ForwardFrame(input_i, output_i, weight, bias, finput_i, cd.kW, cd.kH, cd.dW, cd.dW, cd.padW, cd.padH, nInputPlane, inputWidth, inputHeight, nOutputPlane, outputWidth, outputHeight); } } }
/// <summary> /// fs the size of the input. /// </summary> /// <param name="inputSizes">The input sizes.</param> /// <param name="outputSizes">The output sizes.</param> /// <param name="cd">The cd.</param> /// <returns>System.Int64[].</returns> public static long[] FInputSize(long[] inputSizes, long[] outputSizes, ConvolutionDesc2d cd) { return(new long[] { inputSizes[0], cd.kW *cd.kH *inputSizes[1], outputSizes[2] * outputSizes[3] }); }