Skip to content

Commit 55592ec

Browse files
committed
[TOP] complete level2 (apache#8)
* [TOP] complete level2 * [TOP] add split
1 parent 1338865 commit 55592ec

File tree

9 files changed

+756
-249
lines changed

9 files changed

+756
-249
lines changed

nnvm/include/nnvm/top/nn.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@
88

99
#include <dmlc/base.h>
1010
#include <dmlc/parameter.h>
11+
#include <nnvm/tuple.h>
1112

1213
namespace nnvm {
1314
namespace top {
1415

16+
// Layout flag in spatial conv and pooling.
1517
enum LayoutFlag {
16-
kNCHW = 0,
18+
kNCHW,
1719
kNHWC,
1820
kCHWN,
19-
20-
kNCW = 1 << 3,
21+
kNCW,
2122
kNWC,
2223
kCWN,
23-
24-
kNCDHW = 1 << 5,
24+
kNCDHW,
2525
kNDHWC,
2626
kCDHWN
2727
};
@@ -101,7 +101,7 @@ struct LeakyReLUParam : public dmlc::Parameter<LeakyReLUParam> {
101101
}
102102
};
103103

104-
struct Conv2DParam : public dmlc::Parameter<Conv2DParam> {
104+
struct ConvParam : public dmlc::Parameter<ConvParam> {
105105
int channels;
106106
TShape kernel_size;
107107
TShape strides;
@@ -111,7 +111,7 @@ struct Conv2DParam : public dmlc::Parameter<Conv2DParam> {
111111
int layout;
112112
bool use_bias;
113113

114-
DMLC_DECLARE_PARAMETER(Conv2DParam) {
114+
DMLC_DECLARE_PARAMETER(ConvParam) {
115115
DMLC_DECLARE_FIELD(channels)
116116
.describe("The dimensionality of the output space"
117117
"i.e. the number of output channels in the convolution.");
@@ -141,10 +141,14 @@ struct Conv2DParam : public dmlc::Parameter<Conv2DParam> {
141141
DMLC_DECLARE_FIELD(use_bias).set_default(true)
142142
.describe("Whether the layer uses a bias vector.");
143143
}
144+
// constants
145+
static const constexpr int kData = 0;
146+
static const constexpr int kWeight = 1;
147+
static const constexpr int kBias = 2;
144148
};
145149

146150

147-
struct Conv2DTransposeParam : public dmlc::Parameter<Conv2DTransposeParam> {
151+
struct ConvTransposeParam : public dmlc::Parameter<ConvTransposeParam> {
148152
int channels;
149153
TShape kernel_size;
150154
TShape strides;
@@ -155,7 +159,7 @@ struct Conv2DTransposeParam : public dmlc::Parameter<Conv2DTransposeParam> {
155159
int layout;
156160
bool use_bias;
157161

158-
DMLC_DECLARE_PARAMETER(Conv2DTransposeParam) {
162+
DMLC_DECLARE_PARAMETER(ConvTransposeParam) {
159163
DMLC_DECLARE_FIELD(channels)
160164
.describe("The dimensionality of the output space"
161165
"i.e. the number of output channels in the convolution.");
@@ -187,17 +191,22 @@ struct Conv2DTransposeParam : public dmlc::Parameter<Conv2DTransposeParam> {
187191
DMLC_DECLARE_FIELD(use_bias).set_default(true)
188192
.describe("Whether the layer uses a bias vector.");
189193
}
194+
// constants
195+
static const constexpr int kData = 0;
196+
static const constexpr int kWeight = 1;
197+
static const constexpr int kBias = 2;
190198
};
191199

192-
struct Pool2DParam : public dmlc::Parameter<Pool2DParam> {
200+
201+
struct PoolParam : public dmlc::Parameter<PoolParam> {
193202
TShape pool_size;
194203
TShape strides;
195204
TShape padding;
196205
int groups;
197206
int layout;
198207
bool ceil_mode;
199208

200-
DMLC_DECLARE_PARAMETER(Pool2DParam) {
209+
DMLC_DECLARE_PARAMETER(PoolParam) {
201210
DMLC_DECLARE_FIELD(pool_size)
202211
.describe("Size of the pooling windows..");
203212
DMLC_DECLARE_FIELD(strides).set_default(TShape({1, 1}))
@@ -225,10 +234,10 @@ struct Pool2DParam : public dmlc::Parameter<Pool2DParam> {
225234
};
226235

227236

228-
struct GlobalPool2DParam : public dmlc::Parameter<GlobalPool2DParam> {
237+
struct GlobalPoolParam : public dmlc::Parameter<GlobalPoolParam> {
229238
int layout;
230239

231-
DMLC_DECLARE_PARAMETER(GlobalPool2DParam) {
240+
DMLC_DECLARE_PARAMETER(GlobalPoolParam) {
232241
DMLC_DECLARE_FIELD(layout)
233242
.add_enum("NCHW", kNCHW)
234243
.add_enum("NHWC", kNHWC)

nnvm/include/nnvm/top/tensor.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#ifndef NNVM_TOP_TENSOR_H_
77
#define NNVM_TOP_TENSOR_H_
88

9+
#include <dmlc/base.h>
10+
#include <dmlc/parameter.h>
11+
#include <nnvm/tuple.h>
12+
913
namespace nnvm {
1014
namespace top {
1115

@@ -17,6 +21,19 @@ struct ConcatenateParam : public dmlc::Parameter<ConcatenateParam> {
1721
}
1822
};
1923

24+
struct SplitParam : public dmlc::Parameter<SplitParam> {
25+
// numpy convention, only support indices, not support list.
26+
Tuple<int> indices_or_sections;
27+
int axis;
28+
29+
DMLC_DECLARE_PARAMETER(SplitParam) {
30+
DMLC_DECLARE_FIELD(indices_or_sections)
31+
.describe("Number of outputs to be splitted");
32+
DMLC_DECLARE_FIELD(axis).set_lower_bound(0).set_default(1)
33+
.describe("the axis to be splitted.");
34+
}
35+
};
36+
2037
enum TypeFlag {
2138
kFloat32 = 0,
2239
kFloat64 = 1,
@@ -56,8 +73,6 @@ struct ScalarParam : public dmlc::Parameter<ScalarParam> {
5673
}
5774
};
5875

59-
60-
6176
} // namespace top
6277
} // namespace nnvm
6378

nnvm/src/top/nn/convolution.cc

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*!
2+
* Copyright (c) 2017 by Contributors
3+
* \file convolution.cc
4+
* \brief Convolution operators
5+
*/
6+
#include <nnvm/op.h>
7+
#include <nnvm/node.h>
8+
#include <nnvm/op_attr_types.h>
9+
#include <nnvm/top/nn.h>
10+
#include "./nn_common.h"
11+
#include "../op_common.h"
12+
#include "../elemwise_op_common.h"
13+
14+
namespace nnvm {
15+
namespace top {
16+
17+
// conv2d
18+
DMLC_REGISTER_PARAMETER(ConvParam);
19+
20+
inline bool Conv2DInferShape(const nnvm::NodeAttrs& attrs,
21+
std::vector<TShape>* in_shape,
22+
std::vector<TShape>* out_shape) {
23+
const ConvParam& param = nnvm::get<ConvParam>(attrs.parsed);
24+
if (param.use_bias) {
25+
CHECK_EQ(in_shape->size(), 3U) << "Input:[data, weight, bias]";
26+
} else {
27+
CHECK_EQ(in_shape->size(), 2U) << "Input:[data, weight]";
28+
}
29+
CHECK_EQ(out_shape->size(), 1U);
30+
31+
TShape dshape = in_shape->at(0);
32+
if (dshape.ndim() == 0) return false;
33+
dshape = ConvertLayout(dshape, param.layout, kNCHW);
34+
35+
CHECK_EQ(dshape.ndim(), 4U) << "Input data should be 4D";
36+
CHECK_EQ(param.kernel_size.ndim(), 2U);
37+
CHECK_EQ(param.strides.ndim(), 2U)
38+
<< "incorrect stride size: " << param.strides;
39+
CHECK_EQ(param.dilation.ndim(), 2U)
40+
<< "incorrect dilate size: " << param.dilation;
41+
CHECK_EQ(dshape[1] % param.groups, 0U)
42+
<< "input channels must divide group size";
43+
CHECK_EQ(param.channels % param.groups, 0U)
44+
<< "output channels must divide group size";
45+
46+
TShape wshape({param.channels / param.groups,
47+
dshape[1] / param.groups,
48+
param.kernel_size[0],
49+
param.kernel_size[1]});
50+
51+
wshape = ConvertLayout(wshape, kNCHW, param.layout);
52+
wshape[0] *= param.groups;
53+
54+
NNVM_ASSIGN_INPUT_SHAPE(attrs, *in_shape, ConvParam::kWeight, wshape);
55+
if (param.use_bias) {
56+
NNVM_ASSIGN_INPUT_SHAPE(attrs, *in_shape,
57+
ConvParam::kBias, TShape({param.channels}));
58+
}
59+
// dilation
60+
dim_t dilated_ksize_y = 1 + (param.kernel_size[0] - 1) * param.dilation[0];
61+
dim_t dilated_ksize_x = 1 + (param.kernel_size[1] - 1) * param.dilation[1];
62+
TShape oshape({dshape[0], param.channels, 0, 0});
63+
if (dshape[2] != 0) {
64+
oshape[2] = (dshape[2] + param.padding[0] * 2 - dilated_ksize_y) / param.strides[0] + 1;
65+
}
66+
if (dshape[3] != 0) {
67+
oshape[3] = (dshape[3] + param.padding[1] * 2 - dilated_ksize_x) / param.strides[1] + 1;
68+
}
69+
NNVM_ASSIGN_OUTPUT_SHAPE(attrs, *out_shape, 0,
70+
ConvertLayout(oshape, kNCHW, param.layout));
71+
// Perform incomplete shape inference. Fill in the missing values in data shape.
72+
// 1) We can always fill in the batch_size.
73+
// 2) We can back-calculate the input height/width if the corresponding stride is 1.
74+
oshape = ConvertLayout((*out_shape)[0], param.layout, kNCHW);
75+
dshape[0] = oshape[0];
76+
if (oshape[2] && param.strides[0] == 1) {
77+
dshape[2] = oshape[2] + dilated_ksize_y - 1 - 2 * param.padding[0];
78+
}
79+
if (oshape[3] && param.strides[1] == 1) {
80+
dshape[3] = oshape[3] + dilated_ksize_x - 1 - 2 * param.padding[1];
81+
}
82+
NNVM_ASSIGN_INPUT_SHAPE(attrs, *in_shape, ConvParam::kData,
83+
ConvertLayout(dshape, kNCHW, param.layout));
84+
// Check whether the kernel sizes are valid
85+
if (dshape[2] != 0) {
86+
CHECK_LE(dilated_ksize_y, dshape[2] + 2 * param.padding[0])
87+
<< "kernel size exceed input";
88+
}
89+
if (dshape[3] != 0) {
90+
CHECK_LE(dilated_ksize_x, dshape[3] + 2 * param.padding[1])
91+
<< "kernel size exceed input";
92+
}
93+
return true;
94+
}
95+
96+
NNVM_REGISTER_OP(conv2d)
97+
.describe(R"code(2D convolution layer (e.g. spatial convolution over images).
98+
99+
This layer creates a convolution kernel that is convolved
100+
with the layer input to produce a tensor of
101+
outputs. If `use_bias` is True,
102+
a bias vector is created and added to the outputs.
103+
104+
- **data**: This depends on the `layout` parameter. Input is 4D array of shape
105+
(batch_size, in_channels, height, width) if `layout` is `NCHW`.
106+
- **weight**: (channels, in_channels, kernel_size[0], kernel_size[1])
107+
- **bias**: (channels,)
108+
- **out**: This depends on the `layout` parameter. Output is 4D array of shape
109+
(batch_size, channels, out_height, out_width) if `layout` is `NCHW`.
110+
111+
)code" NNVM_ADD_FILELINE)
112+
.add_argument("data", "4D Tensor", "Input data.")
113+
.add_argument("weight", "4D Tensor", "Weight matrix.")
114+
.add_argument("bias", "1D Tensor", "Bias parameter.")
115+
.add_arguments(ConvParam::__FIELDS__())
116+
.set_attr_parser(ParamParser<ConvParam>)
117+
.set_num_outputs(1)
118+
.set_num_inputs(UseBiasNumInputs<ConvParam>)
119+
.set_attr<FListInputNames>("FListInputNames", UseBiasListInputNames<ConvParam>)
120+
.set_attr<FInferShape>("FInferShape", Conv2DInferShape)
121+
.set_attr<FInferType>("FInferType", ElemwiseType<-1, 1>)
122+
.set_support_level(2);
123+
124+
125+
DMLC_REGISTER_PARAMETER(ConvTransposeParam);
126+
127+
inline bool ConvTransposeInferShape(const nnvm::NodeAttrs& attrs,
128+
std::vector<TShape>* in_shape,
129+
std::vector<TShape>* out_shape) {
130+
const ConvTransposeParam& param = nnvm::get<ConvTransposeParam>(attrs.parsed);
131+
if (param.use_bias) {
132+
CHECK_EQ(in_shape->size(), 3U) << "Input:[data, weight, bias]";
133+
} else {
134+
CHECK_EQ(in_shape->size(), 2U) << "Input:[data, weight]";
135+
}
136+
CHECK_EQ(out_shape->size(), 1U);
137+
const TShape& dshape = (*in_shape)[ConvTransposeParam::kData];
138+
if (dshape.ndim() == 0) return false;
139+
TShape dshape_nchw = ConvertLayout(dshape, param.layout, kNCHW);
140+
141+
CHECK_EQ(dshape_nchw[1] % param.groups, 0U)
142+
<< "input num_filter must divide group size";
143+
CHECK_EQ(param.channels % param.groups, 0U)
144+
<< "output num_filter must divide group size";
145+
CHECK_EQ(param.kernel_size.ndim(), 2U)
146+
<< "incorrect kernel size: " << param.kernel_size;
147+
CHECK_EQ(param.strides.ndim(), 2U)
148+
<< "incorrect stride size: " << param.strides;
149+
CHECK_EQ(param.dilation.ndim(), 2U)
150+
<< "incorrect dilate size: " << param.dilation;
151+
152+
TShape wshape({dshape_nchw[1],
153+
param.channels / param.groups,
154+
param.kernel_size[0], param.kernel_size[1]});
155+
wshape = ConvertLayout(wshape, kNCHW, param.layout);
156+
157+
NNVM_ASSIGN_INPUT_SHAPE(attrs, *in_shape, ConvTransposeParam::kWeight, wshape);
158+
159+
if (param.use_bias) {
160+
NNVM_ASSIGN_INPUT_SHAPE(attrs, *in_shape,
161+
ConvTransposeParam::kBias,
162+
TShape({param.channels}));
163+
}
164+
// dilation
165+
dim_t dilated_ksize_y = 1 + (param.kernel_size[0] - 1) * param.dilation[0];
166+
dim_t dilated_ksize_x = 1 + (param.kernel_size[1] - 1) * param.dilation[1];
167+
// output shape.
168+
TShape oshape({dshape_nchw[0], param.channels, 0, 0});
169+
oshape[2] = (param.strides[0] * (dshape_nchw[2] - 1) + dilated_ksize_y -
170+
2 * param.padding[0] + param.output_padding[0]);
171+
172+
oshape[3] = (param.strides[1] * (dshape_nchw[3] - 1) + dilated_ksize_x -
173+
2 * param.padding[1] + param.output_padding[1]);
174+
NNVM_ASSIGN_OUTPUT_SHAPE(attrs, *out_shape, 0,
175+
ConvertLayout(oshape, kNCHW, param.layout));
176+
return true;
177+
}
178+
179+
NNVM_REGISTER_OP(conv2d_transpose)
180+
.describe(R"code(Transposed 2D convolution layer (sometimes called Deconvolution).
181+
182+
The need for transposed convolutions generally arises
183+
from the desire to use a transformation going in the opposite direction
184+
of a normal convolution, i.e., from something that has the shape of the
185+
output of some convolution to something that has the shape of its input
186+
while maintaining a connectivity pattern that is compatible with
187+
said convolution.
188+
189+
- **data**: This depends on the `layout` parameter. Input is 4D array of shape
190+
(batch_size, in_channels, height, width) if `layout` is `NCHW`.
191+
- **weight**: (channels, in_channels, kernel_size[0], kernel_size[1])
192+
- **bias**: (channels,)
193+
- **out**: This depends on the `layout` parameter. Output is 4D array of shape
194+
(batch_size, channels, out_height, out_width) if `layout` is `NCHW`.
195+
196+
out_height and out_width are calculated as::
197+
out_height = (height-1)*strides[0]-2*padding[0]+kernel_size[0]+output_padding[0]
198+
out_width = (width-1)*strides[1]-2*padding[1]+kernel_size[1]+output_padding[1]
199+
200+
)code" NNVM_ADD_FILELINE)
201+
.add_argument("data", "4D Tensor", "Input data.")
202+
.add_argument("weight", "4D Tensor", "Weight matrix.")
203+
.add_argument("bias", "1D Tensor", "Bias parameter.")
204+
.add_arguments(ConvTransposeParam::__FIELDS__())
205+
.set_attr_parser(ParamParser<ConvTransposeParam>)
206+
.set_num_outputs(1)
207+
.set_num_inputs(UseBiasNumInputs<ConvTransposeParam>)
208+
.set_attr<FListInputNames>("FListInputNames", UseBiasListInputNames<ConvTransposeParam>)
209+
.set_attr<FInferShape>("FInferShape", ConvTransposeInferShape)
210+
.set_attr<FInferType>("FInferType", ElemwiseType<-1, 1>)
211+
.set_support_level(2);
212+
213+
} // namespace top
214+
} // namespace nnvm

0 commit comments

Comments
 (0)