// Adapted from interp.cpp from Caffe util by Pauline Luc // Originally developed by George Papandreou #ifndef TH_GENERIC_FILE #define TH_GENERIC_FILE "generic/VolumetricUpSamplingTrilinear.c" #else static inline void THNN_(VolumetricUpSamplingTrilinear_shapeCheck) (THTensor *input, THTensor *gradOutput, int nBatch, int nChannels, int inputDepth, int inputHeight, int inputWidth, int outputDepth, int outputHeight, int outputWidth) { THArgCheck(inputDepth > 0 && inputHeight > 0 && inputWidth > 0 && outputDepth > 0 && outputHeight > 0 && outputWidth > 0, 2, "input and output sizes should be greater than 0," " but got input (D: %d, H: %d, W: %d) output (D: %d, H: %d, W: %d)", inputDepth, inputHeight, inputWidth, outputDepth, outputHeight, outputWidth); if (input != NULL) { THNN_ARGCHECK(input->nDimension == 5, 2, input, "5D input tensor expected but got: %s"); } if (gradOutput != NULL) { THNN_CHECK_DIM_SIZE(gradOutput, 5, 0, nBatch); THNN_CHECK_DIM_SIZE(gradOutput, 5, 1, nChannels); THNN_CHECK_DIM_SIZE(gradOutput, 5, 2, outputDepth); THNN_CHECK_DIM_SIZE(gradOutput, 5, 3, outputHeight); THNN_CHECK_DIM_SIZE(gradOutput, 5, 4, outputWidth); } } void THNN_(VolumetricUpSamplingTrilinear_updateOutput)( THNNState *state, THTensor *input, THTensor *output, int outputDepth, int outputHeight, int outputWidth){ int nbatch = THTensor_(size)(input, 0); int channels = THTensor_(size)(input, 1); int inputDepth = THTensor_(size)(input, 2); int inputHeight = THTensor_(size)(input, 3); int inputWidth = THTensor_(size)(input, 4); THNN_(VolumetricUpSamplingTrilinear_shapeCheck) (input, NULL, nbatch, channels, inputDepth, inputHeight, inputWidth, outputDepth, outputHeight, outputWidth); input = THTensor_(newContiguous)(input); THTensor_(resize5d)(output, THTensor_(size)(input, 0), THTensor_(size)(input, 1), outputDepth, outputHeight, outputWidth); THTensor_(zero)(output); real *idata = THTensor_(data)(input); real *odata = THTensor_(data)(output); channels = nbatch * channels; THAssert(inputDepth > 0 && inputHeight > 0 && inputWidth > 0 && outputDepth > 0 && outputHeight > 0 && outputWidth > 0); // special case: just copy if (inputDepth == outputDepth && inputHeight == outputHeight && inputWidth == outputWidth) { for (int t2 = 0; t2 < outputDepth; ++t2) { const int t1 = t2; 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[t1 * inputHeight * inputWidth + h1 * inputWidth + w1]; real* pos2 = &odata[t2 * outputHeight * outputWidth + h2 * outputWidth + w2]; for (int c = 0; c < channels; ++c) { pos2[0] = pos1[0]; pos1 += inputWidth * inputHeight * inputDepth; pos2 += outputWidth * outputHeight * outputDepth; } } } } return; } const float rdepth = (outputDepth > 1) ? (float)(inputDepth - 1)/(outputDepth - 1) : 0.f; 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 t2 = 0; t2 < outputDepth; ++t2) { const float t1r = rdepth * t2; const int t1 = t1r; const int t1p = (t1 < inputDepth - 1) ? 1 : 0; const real t1lambda = t1r - t1; const real t0lambda = (real)1. - t1lambda; 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[t1 * inputHeight * inputWidth + h1 * inputWidth + w1]; real* pos2 = &odata[t2 * outputHeight * outputWidth + h2 * outputWidth + w2]; for (int c = 0; c < channels; ++c) { pos2[0] = t0lambda * (h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[w1p]) + h1lambda * (w0lambda * pos1[h1p * inputWidth] + w1lambda * pos1[h1p * inputWidth + w1p])) + t1lambda * (h0lambda * (w0lambda * pos1[t1p * inputHeight * inputWidth] + w1lambda * pos1[t1p * inputHeight * inputWidth + w1p]) + h1lambda * (w0lambda * pos1[t1p * inputHeight * inputWidth + h1p * inputWidth] + w1lambda * pos1[t1p * inputHeight * inputWidth + h1p * inputWidth + w1p])); pos1 += inputWidth * inputHeight * inputDepth; pos2 += outputWidth * outputHeight * outputDepth; } } } } THTensor_(free)(input); } void THNN_(VolumetricUpSamplingTrilinear_updateGradInput)( THNNState *state, THTensor *gradOutput, THTensor *gradInput, int nbatch, int channels, int inputDepth, int inputHeight, int inputWidth, int outputDepth, int outputHeight, int outputWidth){ THNN_(VolumetricUpSamplingTrilinear_shapeCheck) (NULL, gradOutput, nbatch, channels, inputDepth, inputHeight, inputWidth, outputDepth, outputHeight, outputWidth); THTensor_(resize5d)(gradInput, nbatch, channels, inputDepth, 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 (inputDepth == outputDepth && inputHeight == outputHeight && inputWidth == outputWidth) { for (int t2 = 0; t2 < outputDepth; ++t2) { const int t1 = t2; 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[t1 * inputHeight * inputWidth + h1 * inputWidth + w1]; const real* pos2 = &data2[t2 * outputHeight * outputWidth + h2 * outputWidth + w2]; for (int c = 0; c < channels; ++c) { pos1[0] += pos2[0]; pos1 += inputWidth * inputHeight * inputDepth; pos2 += outputWidth * outputHeight * outputDepth; } } } } return; } const float rdepth = (outputDepth > 1) ? (float)(inputDepth - 1)/(outputDepth - 1) : 0.f; 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 t2 = 0; t2 < outputDepth; ++t2) { const float t1r = rdepth * t2; const int t1 = t1r; const int t1p = (t1 < inputDepth - 1) ? 1 : 0; const real t1lambda = t1r - t1; const real t0lambda = (real)1. - t1lambda; 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[t1 * inputHeight * inputWidth + h1 * inputWidth + w1]; const real* pos2 = &data2[t2 * outputHeight * outputWidth + h2 * outputWidth + w2]; for (int c = 0; c < channels; ++c) { pos1[0] += t0lambda * h0lambda * w0lambda * pos2[0]; pos1[w1p] += t0lambda * h0lambda * w1lambda * pos2[0]; pos1[h1p * inputWidth] += t0lambda * h1lambda * w0lambda * pos2[0]; pos1[h1p * inputWidth + w1p] += t0lambda * h1lambda * w1lambda * pos2[0]; pos1[t1p * inputHeight * inputWidth] += t1lambda * h0lambda * w0lambda * pos2[0]; pos1[t1p * inputHeight * inputWidth + w1p] += t1lambda * h0lambda * w1lambda * pos2[0]; pos1[t1p * inputHeight * inputWidth + h1p * inputWidth] += t1lambda * h1lambda * w0lambda * pos2[0]; pos1[t1p * inputHeight * inputWidth + h1p * inputWidth + w1p] += t1lambda * h1lambda * w1lambda * pos2[0]; pos1 += inputWidth * inputHeight * inputDepth; pos2 += outputWidth * outputHeight * outputDepth; } } } } THTensor_(free)(gradOutput); } #endif