| // Adapted from interp.cpp from Caffe util by Pauline Luc |
| // Originally developed by George Papandreou |
| |
| #ifndef TH_GENERIC_FILE |
| #define TH_GENERIC_FILE "generic/SpatialUpSamplingBilinear.c" |
| #else |
| |
| static inline void THNN_(SpatialUpSamplingBilinear_shapeCheck) |
| (THTensor *input, THTensor *gradOutput, |
| int nBatch, int nChannels, |
| int inputHeight, int inputWidth, |
| int outputHeight, int outputWidth) { |
| THArgCheck(inputHeight > 0 && inputWidth > 0 |
| && outputHeight > 0 && outputWidth > 0, 2, |
| "input and output sizes should be greater than 0," |
| " but got input (H: %d, W: %d) output (H: %d, W: %d)", |
| inputHeight, inputWidth, outputHeight, outputWidth); |
| if (input != NULL) { |
| THNN_ARGCHECK(input->nDimension == 4, 2, input, |
| "4D input tensor expected but got: %s"); |
| } |
| |
| if (gradOutput != NULL) { |
| THNN_CHECK_DIM_SIZE(gradOutput, 4, 0, nBatch); |
| THNN_CHECK_DIM_SIZE(gradOutput, 4, 1, nChannels); |
| THNN_CHECK_DIM_SIZE(gradOutput, 4, 2, outputHeight); |
| THNN_CHECK_DIM_SIZE(gradOutput, 4, 3, outputWidth); |
| } |
| } |
| |
| void THNN_(SpatialUpSamplingBilinear_updateOutput)( |
| THNNState *state, |
| THTensor *input, |
| THTensor *output, |
| int outputHeight, |
| int outputWidth){ |
| |
| int nbatch = THTensor_(size)(input, 0); |
| int channels = THTensor_(size)(input, 1); |
| int inputHeight = THTensor_(size)(input, 2); |
| int inputWidth = THTensor_(size)(input, 3); |
| |
| THNN_(SpatialUpSamplingBilinear_shapeCheck) |
| (input, NULL, |
| nbatch, channels, |
| inputHeight, inputWidth, |
| outputHeight, outputWidth); |
| |
| input = THTensor_(newContiguous)(input); |
| THTensor_(resize4d)(output, |
| THTensor_(size)(input, 0), |
| THTensor_(size)(input, 1), |
| outputHeight, outputWidth); |
| THTensor_(zero)(output); |
| real *idata = THTensor_(data)(input); |
| real *odata = THTensor_(data)(output); |
| channels = nbatch * channels; |
| THAssert(inputHeight > 0 && inputWidth > 0 && outputHeight > 0 && outputWidth > 0); |
| // special case: just copy |
| if (inputHeight == outputHeight && inputWidth == outputWidth) { |
| for (int h2 = 0; h2 < outputHeight; ++h2) { |
| const int h1 = h2; |
| for (int w2 = 0; w2 < outputWidth; ++w2) { |
| const int w1 = w2; |
| const real* pos1 = &idata[h1 * inputWidth + w1]; |
| real* pos2 = &odata[h2 * outputWidth + w2]; |
| for (int c = 0; c < channels; ++c) { |
| pos2[0] = pos1[0]; |
| pos1 += inputWidth * inputHeight; |
| pos2 += outputWidth * outputHeight; |
| } |
| } |
| } |
| return; |
| } |
| const float rheight =(outputHeight > 1) ? (float)(inputHeight - 1)/(outputHeight - 1) : 0.f; |
| const float rwidth = (outputWidth > 1) ? (float)(inputWidth - 1) / (outputWidth - 1) : 0.f; |
| for (int h2 = 0; h2 < outputHeight; ++h2) { |
| const float h1r = rheight * h2; |
| const int h1 = h1r; |
| const int h1p = (h1 < inputHeight - 1) ? 1 : 0; |
| const real h1lambda = h1r - h1; |
| const real h0lambda = (real)1. - h1lambda; |
| for (int w2 = 0; w2 < outputWidth; ++w2) { |
| const float w1r = rwidth * w2; |
| const int w1 = w1r; |
| const int w1p = (w1 < inputWidth - 1) ? 1 : 0; |
| const real w1lambda = w1r - w1; |
| const real w0lambda = (real)1. - w1lambda; |
| const real* pos1 = &idata[h1 * inputWidth + w1]; |
| real* pos2 = &odata[h2 * outputWidth + w2]; |
| for (int c = 0; c < channels; ++c) { |
| pos2[0] = h0lambda * (w0lambda * pos1[0]+ w1lambda * pos1[w1p]) |
| + h1lambda * (w0lambda * pos1[h1p * inputWidth] |
| + w1lambda * pos1[h1p * inputWidth + w1p]); |
| pos1 += inputWidth * inputHeight; |
| pos2 += outputWidth * outputHeight; |
| } |
| } |
| } |
| THTensor_(free)(input); |
| } |
| |
| void THNN_(SpatialUpSamplingBilinear_updateGradInput)( |
| THNNState *state, |
| THTensor *gradOutput, |
| THTensor *gradInput, |
| int nbatch, |
| int channels, |
| int inputHeight, |
| int inputWidth, |
| int outputHeight, |
| int outputWidth){ |
| |
| THNN_(SpatialUpSamplingBilinear_shapeCheck) |
| (NULL, gradOutput, |
| nbatch, channels, |
| inputHeight, inputWidth, |
| outputHeight, outputWidth); |
| |
| THTensor_(resize4d)(gradInput, nbatch, channels, inputHeight, inputWidth); |
| THTensor_(zero)(gradInput); |
| gradOutput = THTensor_(newContiguous)(gradOutput); |
| real *data1 = THTensor_(data)(gradInput); |
| real *data2 = THTensor_(data)(gradOutput); |
| channels = nbatch * channels; |
| |
| // special case: same-size matching grids |
| if (inputHeight == outputHeight && inputWidth == outputWidth) { |
| for (int h2 = 0; h2 < outputHeight; ++h2) { |
| const int h1 = h2; |
| for (int w2 = 0; w2 < outputWidth; ++w2) { |
| const int w1 = w2; |
| real* pos1 = &data1[h1 * inputWidth + w1]; |
| const real* pos2 = &data2[h2 * outputWidth + w2]; |
| for (int c = 0; c < channels; ++c) { |
| pos1[0] += pos2[0]; |
| pos1 += inputWidth * inputHeight; |
| pos2 += outputWidth * outputHeight; |
| } |
| } |
| } |
| return; |
| } |
| const float rheight =(outputHeight > 1) ? (float)(inputHeight - 1)/(outputHeight - 1) : 0.f; |
| const float rwidth = (outputWidth > 1) ? (float)(inputWidth - 1)/(outputWidth - 1) : 0.f; |
| for (int h2 = 0; h2 < outputHeight; ++h2) { |
| const float h1r = rheight * h2; |
| const int h1 = h1r; |
| const int h1p = (h1 < inputHeight - 1) ? 1 : 0; |
| const real h1lambda = h1r - h1; |
| const real h0lambda = (real)1. - h1lambda; |
| for (int w2 = 0; w2 < outputWidth; ++w2) { |
| const float w1r = rwidth * w2; |
| const int w1 = w1r; |
| const int w1p = (w1 < inputWidth - 1) ? 1 : 0; |
| const real w1lambda = w1r - w1; |
| const real w0lambda = (real)1. - w1lambda; |
| real* pos1 = &data1[h1 * inputWidth + w1]; |
| const real* pos2 = &data2[h2 * outputWidth + w2]; |
| for (int c = 0; c < channels; ++c) { |
| pos1[0] += h0lambda * w0lambda * pos2[0]; |
| pos1[w1p] += h0lambda * w1lambda * pos2[0]; |
| pos1[h1p * inputWidth] += h1lambda * w0lambda * pos2[0]; |
| pos1[h1p * inputWidth + w1p] += h1lambda * w1lambda * pos2[0]; |
| pos1 += inputWidth * inputHeight; |
| pos2 += outputWidth * outputHeight; |
| } |
| } |
| } |
| THTensor_(free)(gradOutput); |
| } |
| |
| #endif |