blob: 73e81a140ec6ebc62a7445dee86ddff74de53b8c [file] [log] [blame]
#ifndef TH_GENERIC_FILE
#define TH_GENERIC_FILE "generic/VolumetricFullConvolution.c"
#else
void THNN_(VolumetricFullConvolution_updateOutput)(
THNNState *state,
THTensor *input,
THTensor *output,
THTensor *weight,
THTensor *bias,
THTensor *finput, // only used by cuda impl
THTensor *fgradInput, // only used by cuda impl
int dT, int dW, int dH,
int pT, int pW, int pH)
{
// number of input & output planes and kernel size is indirectly defined by the weight tensor
THArgCheck(weight->nDimension == 5, 4,
"5D weight tensor is expected (nOutputPlane x nInputPlane x kT x kH x kW)"
);
int nOutputPlane = (int)weight->size[0];
int nInputPlane = (int)weight->size[1];
int kT = (int)weight->size[2];
int kW = (int)weight->size[3];
int kH = (int)weight->size[4];
THArgCheck(kH == kW && pH == pW, 2, "kH == kW && pH == pW is expected");
THArgCheck(input->nDimension == 5, 2, "5D (batch mode) tensor is expected");
THArgCheck(input->size[1] == nInputPlane, 2, "input tensor has wrong number of planes");
// input tensor dimensions
long batchSize = input->size[0];
int inputDepth = (int)input->size[2];
int inputHeight = (int)input->size[3];
int inputWidth = (int)input->size[4];
int outputDepth = (inputDepth - 1) * dT - 2 * pT + kT;
int outputHeight = (inputHeight - 1) * dH - 2 * pH + kH;
int outputWidth = (inputWidth - 1) * dW - 2 * pW + kW;
// Resize output
THTensor_(resize5d)(output, batchSize, nOutputPlane, outputDepth, outputHeight, outputWidth);
// Helpers
THTensor *input_n = THTensor_(new)();
THTensor *output_n = THTensor_(new)();
const real* weight_ptr = THTensor_(data)(weight);
const real* bias_ptr = THTensor_(data)(bias);
int n;
for (n = 0; n < batchSize; ++n)
{
THTensor_(select)(input_n, input, 0, n);
THTensor_(select)(output_n, output, 0, n);
THTensor *outn = THTensor_(new)();
// add bias first
int i;
for (i = 0; i < bias->size[0]; i++)
{
THTensor_(select)(outn,output_n,0,i);
THTensor_(fill)(outn, THTensor_(get1d)(bias, i));
}
THTensor_(free)(outn);
int t, h, w, kc_, kt_, kh_, kw_, c;
const real *input_ptr = THTensor_(data)(input_n);
real *output_ptr = THTensor_(data)(output_n);
for (t = 0; t < inputDepth; t++)
{
for (h = 0; h < inputHeight; h++)
for (w = 0; w < inputWidth; w++)
for (kc_ = 0; kc_ < nOutputPlane; kc_++)
for (kt_ = 0; kt_ < kT; kt_++)
for (kh_ = 0; kh_ < kH; kh_++)
for (kw_ = 0; kw_ < kW; kw_++)
{
int pt = t * dT - pT + kt_;
int ph = h * dH - pH + kh_;
int pw = w * dW - pW + kw_;
if (pt >=0 && ph >=0 && pw >= 0 &&
pt < outputDepth && ph < outputHeight && pw < outputWidth)
{
real val = 0;
for (c = 0; c < nInputPlane; c++)
{
val += input_ptr[((c * inputDepth + t) * inputHeight + h) * inputWidth + w]
* weight_ptr[(((kc_ * nInputPlane + c) * kT + kt_) * kH + kh_) * kW + kw_];
}
output_ptr[((kc_ * outputDepth + pt) * outputHeight + ph) * outputWidth + pw]
+= val;
}
}
}
}
THTensor_(free)(input_n);
THTensor_(free)(output_n);
}
void THNN_(VolumetricFullConvolution_updateGradInput)(
THNNState *state,
THTensor *input,
THTensor *gradOutput,
THTensor *gradInput,
THTensor *weight,
THTensor *finput, // only used by cuda impl
THTensor *fgradInput, // only used by cuda impl
int dT, int dW, int dH,
int pT, int pW, int pH
)
{
// number of input/output planes and kernel size is indirectly defined by the weight tensor
THArgCheck(weight->nDimension == 5, 4,
"5D weight tensor is expected (nOutputPlane x nInputPlane x kT x kH x kW)"
);
int nOutputPlane = (int)weight->size[0];
int nInputPlane = (int)weight->size[1];
int kT = (int)weight->size[2];
int kW = (int)weight->size[3];
int kH = (int)weight->size[4];
THArgCheck(kH == kW && pH == pW, 2, "kH == kW && pH == pW is expected");
THArgCheck(input->nDimension == 5, 2, "5D (batch mode) tensor is expected");
THArgCheck(input->size[1] == nInputPlane, 2, "input tensor has wrong number of planes");
int inputDepth = (int)input->size[2];
int inputHeight = (int)input->size[3];
int inputWidth = (int)input->size[4];
int outputDepth = (inputDepth - 1) * dT - 2 * pT + kT;
int outputHeight = (inputHeight - 1) * dH - 2 * pH + kH;
int outputWidth = (inputWidth - 1) * dW - 2 * pW + kW;
// Batch size
long batchSize = input->size[0];
// Resize output
THTensor_(resize5d)(gradInput, batchSize, nInputPlane, inputDepth, inputHeight, inputWidth);
// Helpers
THTensor *gradInput_n = THTensor_(new)();
THTensor *gradOutput_n = THTensor_(new)();
const real* weight_ptr = THTensor_(data)(weight);
// For each n in batch, do:
int n;
for (n = 0; n < batchSize; n++)
{
THTensor_(select)(gradInput_n, gradInput, 0, n);
THTensor_(select)(gradOutput_n, gradOutput, 0, n);
THTensor_(fill)(gradInput_n, 0);
int t, h, w, kc_, kt_, kh_, kw_, c;
real *gradInput_ptr = THTensor_(data)(gradInput_n);
const real *gradOutput_ptr = THTensor_(data)(gradOutput_n);
for (t = 0; t < inputDepth; t++)
for (h = 0; h < inputHeight; h++)
for (w = 0; w < inputWidth; w++)
for (kc_ = 0; kc_ < nOutputPlane; kc_++)
for (kt_ = 0; kt_ < kT; kt_++)
for (kh_ = 0; kh_ < kH; kh_++)
for (kw_ = 0; kw_ < kW; kw_++)
{
int pt = t * dT - pT + kt_;
int ph = h * dH - pH + kh_;
int pw = w * dW - pW + kw_;
if (pt >=0 && ph >=0 && pw >= 0 &&
pt < outputDepth && ph < outputHeight && pw < outputWidth)
{
for (c = 0; c < nInputPlane; c++)
{
gradInput_ptr[((c * inputDepth + t) * inputHeight + h) * inputWidth + w] +=
gradOutput_ptr[((kc_ * outputDepth + pt) * outputHeight + ph) * outputWidth + pw]
* weight_ptr[(((kc_ * nInputPlane + c) * kT + kt_) * kH + kh_) * kW + kw_];
}
}
}
}
// Free
THTensor_(free)(gradInput_n);
THTensor_(free)(gradOutput_n);
}
void THNN_(VolumetricFullConvolution_accGradParameters)(
THNNState *state,
THTensor *input,
THTensor *gradOutput,
THTensor *gradWeight,
THTensor *gradBias,
THTensor *finput, // only used by cuda impl
THTensor *fgradInput, // only used by cuda impl
int dT, int dW, int dH,
int pT, int pW, int pH,
real scale)
{
// number of input/output planes and kernel size is indirectly defined by the gradWeight tensor
THArgCheck(gradWeight->nDimension == 5, 4,
"5D gradWeight tensor is expected (nOutputPlane x nInputPlane x kT x kH x kW)"
);
int nOutputPlane = (int)gradWeight->size[0];
int nInputPlane = (int)gradWeight->size[1];
int kT = (int)gradWeight->size[2];
int kW = (int)gradWeight->size[3];
int kH = (int)gradWeight->size[4];
THArgCheck(gradBias->nDimension == 1 && gradBias->size[0] == nOutputPlane, 5,
"gradBias tensor has wrong size"
);
THArgCheck(input->nDimension == 5, 2, "5D (batch mode) tensor is expected");
THArgCheck(kH == kW && pH == pW, 2, "kH == kW && pH == pW is expected");
THArgCheck(input->size[1] == nInputPlane, 2, "input tensor has wrong number of planes");
THTensor_(resize1d)(gradBias, nOutputPlane);
THTensor_(resize5d)(gradWeight, nOutputPlane, nInputPlane, kT, kH, kW);
int inputDepth = input->size[2];
int inputHeight = input->size[3];
int inputWidth = input->size[4];
int outputDepth = (inputDepth - 1) * dT - 2 * pT + kT;
int outputHeight = (inputHeight - 1) * dH - 2 * pH + kH;
int outputWidth = (inputWidth - 1) * dW - 2 * pW + kW;
// Batch size
long batchSize = input->size[0];
// Helpers
THTensor *input_n = THTensor_(new)();
THTensor *gradOutput_n = THTensor_(new)();
// reset gradBias = 0
THTensor_(fill)(gradBias, 0);
// reset gradWeight = 0
THTensor_(fill)(gradWeight, 0);
real *gradWeight_ptr = THTensor_(data)(gradWeight);
real *gradBias_ptr = THTensor_(data)(gradBias);
// For each n in batch, do:
int n;
for (n = 0; n < batchSize; n++)
{
THTensor_(select)(input_n, input, 0, n);
THTensor_(select)(gradOutput_n, gradOutput, 0, n);
THTensor *goutn = THTensor_(new)();
// accumulate bias gradient first
int i;
for (i = 0; i < gradBias->size[0]; i++)
{
THTensor_(select)(goutn, gradOutput_n, 0, i);
gradBias_ptr[i] += scale * THTensor_(sumall)(goutn);
}
THTensor_(free)(goutn);
int t, h, w, kc_, kt_, kh_, kw_, c;
const real *input_ptr = THTensor_(data)(input_n);
const real *gradOutput_ptr = THTensor_(data)(gradOutput_n);
for (t = 0; t < inputDepth; t++)
for (h = 0; h < inputHeight; h++)
for (w = 0; w < inputWidth; w++)
for (kc_ = 0; kc_ < nOutputPlane; kc_++)
for (kt_ = 0; kt_ < kT; kt_++)
for (kh_ = 0; kh_ < kH; kh_++)
for (kw_ = 0; kw_ < kW; kw_++)
{
int pt = t * dT - pT + kt_;
int ph = h * dH - pH + kh_;
int pw = w * dW - pW + kw_;
if (pt >=0 && ph >=0 && pw >= 0 &&
pt < outputDepth && ph < outputHeight && pw < outputWidth)
{
for (c = 0; c < nInputPlane; c++)
{
gradWeight_ptr[(((kc_ * nInputPlane + c) * kT + kt_) * kH + kh_) * kW + kw_] +=
scale *
input_ptr[((c * inputDepth + t) * inputHeight + h) * inputWidth + w] *
gradOutput_ptr[((kc_ * outputDepth + pt) * outputHeight + ph) * outputWidth + pw];
}
}
}
}
// Free
THTensor_(free)(input_n);
THTensor_(free)(gradOutput_n);
}
#endif