Skip to content

Commit

Permalink
Fixed various issues w.r.t. groups, strides. Also added correct shape…
Browse files Browse the repository at this point in the history
… infer.
  • Loading branch information
liuliu committed Jan 23, 2024
1 parent 8e461ea commit b6d3966
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 28 deletions.
6 changes: 6 additions & 0 deletions lib/nnc/ccv_nnc.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ typedef struct {
int groups; /**< [convolution.groups] The number of groups for convolutional layer. */
int dilation[CCV_NNC_MAX_DIM_ALLOC]; /**< [convolution.dilation[]] The dilation factor for convolutional layer. Default to 1. */
} convolution;
struct {
int count; /**< [convolution_transpose.count] The number of filters for convolutional layer. */
int groups; /**< [convolution_transpose.groups] The number of groups for convolutional layer. */
int output_padding; /**< [convolution_transpose.output_padding] The output padding to resolve ambiguity when treat this as inverse of convolution. */
int dilation[CCV_NNC_MAX_DIM_ALLOC]; /**< [convolution_transpose.dilation[]] The dilation factor for convolutional layer. Default to 1. */
} convolution_transpose;
struct {
int hidden_size; /**< [rnn.hidden_size] The number of features in the hidden state h. */
int proj_size; /**< [rnn.proj_size] The number of features in the hidden state h. */
Expand Down
4 changes: 2 additions & 2 deletions lib/nnc/cmd/ccv_nnc_cmd_easy.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
// CCV_NNC_CONVOLUTION_BACKWARD
#define CMD_CONVOLUTION_BACKWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)
// CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD
#define CMD_CONVOLUTION_TRANSPOSE_FORWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)
#define CMD_CONVOLUTION_TRANSPOSE_FORWARD(_groups, _count, _output_padding, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution_transpose={.count=_count,.groups=_groups,.output_padding=_output_padding}}), 0)
// CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD
#define CMD_CONVOLUTION_TRANSPOSE_BACKWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)
#define CMD_CONVOLUTION_TRANSPOSE_BACKWARD(_groups, _count, _output_padding, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution_transpose={.count=_count,.groups=_groups,.output_padding=_output_padding}}), 0)
// CCV_NNC_DROPOUT_FORWARD
#define CMD_DROPOUT_FORWARD_X_F(...) ("This should not be used, you should have either 1 parameter or 2 parameters for CMD_DROPOUT_FORWARD")
#define CMD_DROPOUT_FORWARD_X_1(_p) ccv_nnc_cmd(CCV_NNC_DROPOUT_FORWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={1,1,1}},.dropout={.p=_p,.entirety=0}}), 0)
Expand Down
44 changes: 23 additions & 21 deletions lib/nnc/cmd/convolution/ccv_nnc_conv_transpose_cpu_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,41 @@ static int _ccv_nnc_conv_transpose_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_h
const int b_nd = ccv_nnc_tensor_nd(b->info.dim);
assert(b_nd == CCV_NNC_MAX_DIM + 1 || b_nd == CCV_NNC_MAX_DIM + 2);
const int* bdim = (b_nd == CCV_NNC_MAX_DIM + 1) ? b->info.dim : b->info.dim + 1;
const int groups = cmd.info.convolution.groups;
assert(cmd.info.convolution.count % groups == 0);
const int group_size = cmd.info.convolution.count / groups;
const int groups = cmd.info.convolution_transpose.groups;
assert(cmd.info.convolution_transpose.count % groups == 0);
const int group_size = cmd.info.convolution_transpose.count / groups;
// Make sure the weights output dimension matches the network convolution kernels
int astride[CCV_NNC_MAX_DIM_ALLOC];
ccv_nnc_tensor_view_get_stride(a, astride);
int bstride[CCV_NNC_MAX_DIM_ALLOC];
ccv_nnc_tensor_view_get_stride(b, bstride);
assert(!bias || bias->info.dim[0] == cmd.info.convolution.count);
assert(!bias || bias->info.dim[0] == cmd.info.convolution_transpose.count);
const int batch_size = (a_nd == CCV_NNC_MAX_DIM + 2) ? a->info.dim[0] : 1;
const int dilation[CCV_NNC_MAX_DIM] = {
ccv_max(cmd.info.convolution.dilation[0], 1),
ccv_max(cmd.info.convolution.dilation[1], 1)
ccv_max(cmd.info.convolution_transpose.dilation[0], 1),
ccv_max(cmd.info.convolution_transpose.dilation[1], 1)
};
if (a->info.format == CCV_TENSOR_FORMAT_NHWC)
{
// Make sure the weights dimension matches the network dimension
assert(w->info.dim[1] == cmd.info.size.dim[0]);
assert(w->info.dim[2] == cmd.info.size.dim[1]);
assert(w->info.dim[CCV_NNC_MAX_DIM + 1] * groups == cmd.info.convolution.count);
assert(w->info.dim[CCV_NNC_MAX_DIM + 1] * groups == cmd.info.convolution_transpose.count);
const int wdim[CCV_NNC_MAX_DIM] = {
(w->info.dim[1] - 1) * dilation[0] + 1,
(w->info.dim[2] - 1) * dilation[1] + 1
};
assert(w->info.dim[0] == adim[CCV_NNC_MAX_DIM]);
assert(b->info.format == CCV_TENSOR_FORMAT_NHWC);
const int channel_size = w->info.dim[CCV_NNC_MAX_DIM + 1];
const int input_channel_size = w->info.dim[0];
const int input_channel_size = w->info.dim[0] / groups;
const int hwc = w->info.dim[1] * w->info.dim[2] * channel_size;
assert(bdim[CCV_NNC_MAX_DIM] == cmd.info.convolution.count);
parallel_for(idx, cmd.info.convolution.count * batch_size) {
assert(bdim[CCV_NNC_MAX_DIM] == cmd.info.convolution_transpose.count);
parallel_for(idx, cmd.info.convolution_transpose.count * batch_size) {
int c;
const int bidx = idx / cmd.info.convolution.count;
const int k = idx % cmd.info.convolution.count;
const int bidx = idx / cmd.info.convolution_transpose.count;
const int k = idx % cmd.info.convolution_transpose.count;
const int gidx = k / group_size;
float* ap = a->data.f32 + bidx * astride[0];
float* bp = b->data.f32 + bidx * bstride[0] + k;
// kernel weight for one dim.
Expand Down Expand Up @@ -104,7 +105,7 @@ static int _ccv_nnc_conv_transpose_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_h
{
float p = bpz[j[1] * dilation[1] * bstride[CCV_NNC_MAX_DIM]];
for (c = 0; c < input_channel_size; c++)
p += wpz[j[1] * channel_size + c * hwc] * apz[c];
p += wpz[j[1] * channel_size + (c + gidx * input_channel_size) * hwc] * apz[c + gidx * input_channel_size];
bpz[j[1] * dilation[1] * bstride[CCV_NNC_MAX_DIM]] = p;
}
wpz += w->info.dim[CCV_NNC_MAX_DIM] * channel_size;
Expand All @@ -117,7 +118,7 @@ static int _ccv_nnc_conv_transpose_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_h
} parallel_endfor
} else if (a->info.format == CCV_TENSOR_FORMAT_NCHW) {
// Make sure the weights dimension matches the network dimension
assert(w->info.dim[1] * groups == cmd.info.convolution.count);
assert(w->info.dim[1] * groups == cmd.info.convolution_transpose.count);
assert(w->info.dim[2] == cmd.info.size.dim[0]);
assert(w->info.dim[3] == cmd.info.size.dim[1]);
const int wdim[CCV_NNC_MAX_DIM] = {
Expand All @@ -127,14 +128,15 @@ static int _ccv_nnc_conv_transpose_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_h
assert(w->info.dim[0] == adim[0]);
assert(b->info.format == CCV_TENSOR_FORMAT_NCHW);
const int channel_size = w->info.dim[1];
const int input_channel_size = w->info.dim[0];
const int input_channel_size = w->info.dim[0] / groups;
const int hw = w->info.dim[2] * w->info.dim[3];
const int chw = channel_size * hw;
assert(bdim[0] == cmd.info.convolution.count);
parallel_for(idx, cmd.info.convolution.count * batch_size) {
assert(bdim[0] == cmd.info.convolution_transpose.count);
parallel_for(idx, cmd.info.convolution_transpose.count * batch_size) {
int c;
const int bidx = idx / cmd.info.convolution.count;
const int k = idx % cmd.info.convolution.count;
const int bidx = idx / cmd.info.convolution_transpose.count;
const int k = idx % cmd.info.convolution_transpose.count;
const int gidx = k / group_size;
float* ap = a->data.f32 + bidx * astride[0];
float* bp = b->data.f32 + bidx * bstride[0] + k * bstride[1];
// kernel weight for one dim.
Expand Down Expand Up @@ -179,11 +181,11 @@ static int _ccv_nnc_conv_transpose_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_h
{
float p = bpz[j[1] * dilation[1] * bstride[CCV_NNC_MAX_DIM + 1]];
for (c = 0; c < input_channel_size; c++)
p += wpz[j[1] + c * chw] * apz[c * astride[1]];
p += wpz[j[1] + (c + gidx * input_channel_size) * chw] * apz[(c + gidx * input_channel_size) * astride[1]];
bpz[j[1] * dilation[1] * bstride[CCV_NNC_MAX_DIM + 1]] = p;
}
wpz += w->info.dim[CCV_NNC_MAX_DIM + 1];
apz += astride[CCV_NNC_MAX_DIM] * dilation[0];
bpz += bstride[CCV_NNC_MAX_DIM] * dilation[0];
}
}
ap += astride[CCV_NNC_MAX_DIM];
Expand Down
34 changes: 31 additions & 3 deletions lib/nnc/cmd/convolution/ccv_nnc_convolution.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,39 @@ REGISTER_COMMAND(CCV_NNC_CONVOLUTION_BACKWARD)(ccv_nnc_cmd_registry_t* const reg
//@REGISTER_EASY_COMMAND_MACRO(CCV_NNC_CONVOLUTION_BACKWARD)
#define CMD_CONVOLUTION_BACKWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)

static void _ccv_nnc_conv_transpose_tensor_auto_forw(const ccv_nnc_cmd_param_t cmd, const ccv_nnc_tensor_param_t* inputs, const int input_size, const ccv_nnc_hint_t hint, ccv_nnc_tensor_param_t* outputs, const int output_size)
{
assert(output_size == 1);
outputs[0].type = inputs[0].type;
outputs[0].format = inputs[0].format;
outputs[0].datatype = inputs[0].datatype;
// Get the channel output from the weight matrix.
const int count = ccv_nnc_tensor_get_n(inputs[1]);
assert(count == cmd.convolution_transpose.count);
ccv_nnc_tensor_set_c(outputs, ccv_nnc_tensor_nd(inputs[0].dim), count);
ccv_nnc_tensor_set_n(outputs, ccv_nnc_tensor_get_n(inputs[0]));
ccv_nnc_cmd_param_t modified_cmd = cmd;
int i = 0;
for (i = 0; i < CCV_NNC_MAX_DIM; i++)
ccv_nnc_hint_tensor_forward(modified_cmd, inputs[0], hint, outputs);
assert(inputs[0].format == outputs[0].format);
const int nd = ccv_nnc_tensor_nd(inputs[0].dim);
assert(nd == CCV_NNC_MAX_DIM + 1 || nd == CCV_NNC_MAX_DIM + 2);
int hw = ccv_nnc_tensor_hw(inputs[0], nd);
assert(hw >= 0);
for (i = 0; i < CCV_NNC_MAX_DIM; i++)
{
const int stride = ccv_max(1, hint.stride.dim[i]);
const int size_dim = (modified_cmd.size.dim[i] - 1) * ccv_max(cmd.convolution_transpose.dilation[i], 1) + 1;
outputs[0].dim[i + hw] = (inputs[0].dim[i + hw] - 1) * stride + size_dim - hint.border.begin[i] - hint.border.end[i] + cmd.convolution_transpose.output_padding;
}
}

REGISTER_COMMAND(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD)(ccv_nnc_cmd_registry_t* const registry)
FIND_BACKEND(ccv_nnc_conv_transpose_cpu_ref.c)
{
registry->bitmask = _ccv_nnc_conv_forw_bitmask;
registry->tensor_auto = _ccv_nnc_conv_tensor_auto_forw;
registry->tensor_auto = _ccv_nnc_conv_transpose_tensor_auto_forw;
}

REGISTER_COMMAND(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD)(ccv_nnc_cmd_registry_t* const registry)
Expand All @@ -88,6 +116,6 @@ REGISTER_COMMAND(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD)(ccv_nnc_cmd_registry_t*
}

//@REGISTER_EASY_COMMAND_MACRO(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD)
#define CMD_CONVOLUTION_TRANSPOSE_FORWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)
#define CMD_CONVOLUTION_TRANSPOSE_FORWARD(_groups, _count, _output_padding, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_FORWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution_transpose={.count=_count,.groups=_groups,.output_padding=_output_padding}}), 0)
//@REGISTER_EASY_COMMAND_MACRO(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD)
#define CMD_CONVOLUTION_TRANSPOSE_BACKWARD(_groups, _count, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution={.count=_count,.groups=_groups}}), 0)
#define CMD_CONVOLUTION_TRANSPOSE_BACKWARD(_groups, _count, _output_padding, ...) ccv_nnc_cmd(CCV_NNC_CONVOLUTION_TRANSPOSE_BACKWARD, 0, ((ccv_nnc_cmd_param_t){.size={.dim={__VA_ARGS__}},.convolution_transpose={.count=_count,.groups=_groups,.output_padding=_output_padding}}), 0)
Loading

0 comments on commit b6d3966

Please sign in to comment.