@@ -18,9 +18,6 @@ namespace webnn {
18
18
19
19
class ConvOpBuilder : public BaseOpBuilder {
20
20
// Add operator related.
21
- public:
22
- void AddInitializersToSkip (ModelBuilder& model_builder, const Node& node) const override ;
23
-
24
21
private:
25
22
Status AddToModelBuilderImpl (ModelBuilder& model_builder, const Node& node,
26
23
const logging::Logger& logger) const override ORT_MUST_USE_RESULT;
@@ -33,13 +30,6 @@ class ConvOpBuilder : public BaseOpBuilder {
33
30
const logging::Logger& logger) const override ;
34
31
};
35
32
36
- void ConvOpBuilder::AddInitializersToSkip (ModelBuilder& model_builder, const Node& node) const {
37
- // skip the weight for conv as we need to transpose for preferred layout NHWC.
38
- if (model_builder.GetPreferredLayout () == DataLayout::NHWC) {
39
- model_builder.AddInitializerToSkip (node.InputDefs ()[1 ]->Name ()); // W
40
- }
41
- }
42
-
43
33
// Helper functions
44
34
common::Status SetConvBaseOptions (ModelBuilder& model_builder,
45
35
const Node& node, emscripten::val& options,
@@ -48,7 +38,6 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder,
48
38
const std::vector<int64_t >& strides,
49
39
const std::vector<int64_t >& dilations,
50
40
std::vector<int64_t >& pads,
51
- const bool is_nhwc,
52
41
const bool is_conv1d,
53
42
const logging::Logger& logger) {
54
43
NodeAttrHelper helper (node);
@@ -61,7 +50,7 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder,
61
50
// Calculate explicit padding for autoPad.
62
51
if (AutoPadType::SAME_UPPER == auto_pad_type || AutoPadType::SAME_LOWER == auto_pad_type) {
63
52
ORT_RETURN_IF_ERROR (HandleAutoPad (input_shape, weight_shape[2 ], weight_shape[3 ],
64
- pads, strides, dilations, auto_pad_type, pads_out, !is_nhwc ));
53
+ pads, strides, dilations, auto_pad_type, pads_out));
65
54
pads = pads_out;
66
55
}
67
56
} else if (node.OpType () == " ConvTranspose" ) {
@@ -82,7 +71,7 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder,
82
71
// Otherwise compute the output shape, as well as the pads if the auto_pad attribute is SAME_UPPER/SAME_LOWER.
83
72
ORT_RETURN_IF_ERROR (ComputeConvTransposePadsAndOutputShape (input_shape, weight_shape[2 ], weight_shape[3 ],
84
73
pads, strides, dilations, output_padding,
85
- auto_pad_type, pads_out, output_shape, !is_nhwc ));
74
+ auto_pad_type, pads_out, output_shape));
86
75
87
76
if (output_shape[0 ] != -1 && output_shape[1 ] != -1 ) {
88
77
options.set (" outputSizes" , emscripten::val::array (GetVecUint32FromVecInt64 (output_shape)));
@@ -111,89 +100,6 @@ common::Status SetConvBaseOptions(ModelBuilder& model_builder,
111
100
return Status::OK ();
112
101
}
113
102
114
- // Both depthwise Conv and ConvTranspose share the same logic to add the layout.
115
- Status AddInitializerInNewLayout (ModelBuilder& model_builder,
116
- const std::string& name,
117
- bool is_conv,
118
- bool is_conv1d) {
119
- const auto & tensor = *model_builder.GetInitializerTensors ().at (name);
120
- auto data_type = tensor.data_type ();
121
-
122
- const auto & shape = tensor.dims ();
123
- std::vector<uint32_t > dims = GetVecUint32FromVecInt64 (std::vector<int64_t >(std::begin (shape), std::end (shape)));
124
-
125
- if (is_conv1d) {
126
- // Support conv1d by prepending a 1 size dimension.
127
- dims.push_back (1 );
128
- }
129
-
130
- const uint8_t * src = nullptr ;
131
- Initializer unpacked_tensor (tensor, model_builder.GetGraphViewer ().ModelPath ());
132
- src = unpacked_tensor.DataAsByteSpan ().data ();
133
- const auto out_t = dims[0 ], in_t = dims[1 ],
134
- h_t = dims[2 ], w_t = dims[3 ];
135
- std::vector<uint32_t > dest_shape;
136
- if (is_conv == 1 )
137
- dest_shape = {out_t , h_t , w_t , in_t }; // L_0231
138
- else
139
- dest_shape = {in_t , h_t , w_t , out_t }; // L_1230 for depthwise conv and convTranspose weight
140
-
141
- SafeInt<size_t > num_elements = SafeInt<size_t >(Product (dest_shape));
142
-
143
- size_t element_size{0 };
144
- switch (data_type) {
145
- case ONNX_NAMESPACE::TensorProto_DataType_UINT8:
146
- element_size = sizeof (uint8_t );
147
- break ;
148
- case ONNX_NAMESPACE::TensorProto_DataType_INT8:
149
- element_size = sizeof (int8_t );
150
- break ;
151
- case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16:
152
- element_size = sizeof (uint16_t );
153
- break ;
154
- case ONNX_NAMESPACE::TensorProto_DataType_FLOAT:
155
- element_size = sizeof (float );
156
- break ;
157
- default :
158
- break ;
159
- }
160
- std::unique_ptr<uint8_t []> buffer_holder (new uint8_t [element_size * num_elements]);
161
- uint8_t * buffer = buffer_holder.get ();
162
-
163
- for (uint32_t out = 0 ; out < out_t ; out++) {
164
- for (uint32_t in = 0 ; in < in_t ; in++) {
165
- for (uint32_t h = 0 ; h < h_t ; h++) {
166
- for (uint32_t w = 0 ; w < w_t ; w++) {
167
- auto onnx_idx = out * in_t * h_t * w_t +
168
- in * h_t * w_t +
169
- h * w_t +
170
- w;
171
-
172
- uint32_t nnapi_idx;
173
- if (is_conv == 1 ) { // L_0231
174
- nnapi_idx = out * h_t * w_t * in_t +
175
- h * w_t * in_t +
176
- w * in_t +
177
- in;
178
- } else { // L_1230 for depthwise conv weight
179
- nnapi_idx = in * h_t * w_t * out_t +
180
- h * w_t * out_t +
181
- w * out_t +
182
- out;
183
- }
184
-
185
- for (size_t i = 0 ; i < element_size; i++) {
186
- buffer[element_size * nnapi_idx + i] = src[element_size * onnx_idx + i];
187
- }
188
- }
189
- }
190
- }
191
- }
192
- ORT_RETURN_IF_ERROR (model_builder.AddOperandFromPersistMemoryBuffer (name, buffer, num_elements * element_size,
193
- dest_shape, data_type));
194
- return Status::OK ();
195
- }
196
-
197
103
// Add operator related.
198
104
199
105
Status ConvOpBuilder::AddToModelBuilderImpl (ModelBuilder& model_builder, const Node& node,
@@ -203,7 +109,6 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N
203
109
const auto & op_type = node.OpType ();
204
110
emscripten::val input = model_builder.GetOperand (input_defs[0 ]->Name ());
205
111
emscripten::val output = emscripten::val::object ();
206
- const auto & initializers (model_builder.GetInitializerTensors ());
207
112
208
113
std::vector<int64_t > input_shape;
209
114
ORT_RETURN_IF_NOT (GetShape (*input_defs[0 ], input_shape, logger), " Cannot get input shape" );
@@ -216,19 +121,11 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N
216
121
auto dilations = helper.Get (" dilations" , std::vector<int64_t >{1 , 1 });
217
122
auto pads = helper.Get (" pads" , std::vector<int64_t >{0 , 0 , 0 , 0 });
218
123
219
- const bool is_nhwc = model_builder.GetPreferredLayout () == DataLayout::NHWC;
220
124
const bool is_conv1d = input_shape.size () == 3 && weight_shape.size () == 3 ;
221
- const bool is_constant_weight = Contains (initializers, weight_name);
222
125
// Support conv1d by prepending a 1 or 2 size dimensions.
223
126
if (is_conv1d) {
224
127
// Reshape input.
225
- if (is_nhwc) {
226
- // For NHWC preferred layout, the input has been transposed.
227
- // For conv1d it is NCD1 -> ND1C, so we need to prepend 1 to the index 2.
228
- input_shape.insert (input_shape.begin () + 2 , 1 );
229
- } else {
230
- input_shape.push_back (1 );
231
- }
128
+ input_shape.push_back (1 );
232
129
std::vector<uint32_t > new_shape = GetVecUint32FromVecInt64 (input_shape);
233
130
input = model_builder.GetBuilder ().call <emscripten::val>(" reshape" , input, emscripten::val::array (new_shape));
234
131
@@ -244,63 +141,19 @@ Status ConvOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N
244
141
emscripten::val options = emscripten::val::object ();
245
142
options.set (" label" , node.Name ());
246
143
ORT_RETURN_IF_ERROR (SetConvBaseOptions (
247
- model_builder, node, options, input_shape, weight_shape, strides, dilations, pads, is_nhwc, is_conv1d, logger));
248
- bool depthwise = false ;
249
- if (op_type == " Conv" || op_type == " ConvInteger" ) {
250
- int groups = options[" groups" ].as <int >();
251
- if (is_nhwc) {
252
- depthwise = (groups == input_shape[3 ] && groups != 1 );
253
- options.set (" inputLayout" , emscripten::val (" nhwc" ));
254
- if (is_constant_weight) {
255
- ORT_RETURN_IF_ERROR (AddInitializerInNewLayout (model_builder, weight_name, !depthwise, is_conv1d));
256
- }
257
- if (!depthwise) {
258
- options.set (" filterLayout" , emscripten::val (" ohwi" ));
259
- } else {
260
- options.set (" filterLayout" , emscripten::val (" ihwo" ));
261
- }
262
- }
263
- } else { // ConvTranspose
264
- if (is_nhwc) {
265
- options.set (" inputLayout" , emscripten::val (" nhwc" ));
266
- options.set (" filterLayout" , emscripten::val (" ohwi" ));
267
- if (is_constant_weight) {
268
- ORT_RETURN_IF_ERROR (AddInitializerInNewLayout (model_builder, weight_name, true , is_conv1d));
269
- }
270
- }
271
- }
272
-
144
+ model_builder, node, options, input_shape, weight_shape, strides, dilations, pads, is_conv1d, logger));
273
145
emscripten::val filter = model_builder.GetOperand (weight_name);
274
146
275
147
if (is_conv1d) {
276
148
// Reshape weight to 4D for conv1d.
277
- if (!is_nhwc || !is_constant_weight) {
278
- // The weight_shape has been appended 1's, reshape weight operand.
279
- std::vector<uint32_t > new_shape = GetVecUint32FromVecInt64 (weight_shape);
280
- emscripten::val reshape_options = emscripten::val::object ();
281
- reshape_options.set (" label" , node.Name () + " _reshape_filter" );
282
- filter = model_builder.GetBuilder ().call <emscripten::val>(" reshape" ,
283
- filter,
284
- emscripten::val::array (new_shape),
285
- reshape_options);
286
- }
287
- }
288
-
289
- emscripten::val transpose_options = emscripten::val::object ();
290
- if (is_nhwc && !is_constant_weight) {
291
- // For NHWC preferred layout, if the weight is input:
292
- // - Transpose it from iohw -> ohwi for convTranspose.
293
- // - Transpose it from oihw -> ihwo for depthwise conv.
294
- // - Transpose it from oihw -> ohwi for conv.
295
- std::vector<uint32_t > perm (4 );
296
- if (op_type == " ConvTranspose" || depthwise) {
297
- perm = {1 , 2 , 3 , 0 }; // L_1230 for depthwise conv and convTranspose weight
298
- } else {
299
- perm = {0 , 2 , 3 , 1 }; // L_0231
300
- }
301
- transpose_options.set (" permutation" , emscripten::val::array (perm));
302
- transpose_options.set (" label" , node.Name () + " _transpose_filter" );
303
- filter = model_builder.GetBuilder ().call <emscripten::val>(" transpose" , filter, transpose_options);
149
+ // The weight_shape has been appended 1's, reshape weight operand.
150
+ std::vector<uint32_t > new_shape = GetVecUint32FromVecInt64 (weight_shape);
151
+ emscripten::val reshape_options = emscripten::val::object ();
152
+ reshape_options.set (" label" , node.Name () + " _reshape_filter" );
153
+ filter = model_builder.GetBuilder ().call <emscripten::val>(" reshape" ,
154
+ filter,
155
+ emscripten::val::array (new_shape),
156
+ reshape_options);
304
157
}
305
158
306
159
if (op_type == " Conv" ) {
0 commit comments