Skip to content

Commit f5b7831

Browse files
huningxinChromium LUCI CQ
authored and
Chromium LUCI CQ
committed
WebNN: Define XNNPACK Node for conv2d MLOperator
This CL implements the DefineXnnNodeForConv2d() method for WebNN conv2d MLOperator that defines XNNPACK conv2d or depthwise conv2d Node according to MLConv2dOptions. This CL only supports the input layout “nhwc”, filter layout “ohwi” for regular conv2d and filter layout “ihow” for depthwise conv2d. Other input and filter layouts could be supported by inserting transpose operators later. There is also another proposal [1] that suggests simplifying the layouts support. The implementation will be updated according to the WG’s consensus. For unit tests, this CL implements Conv2dTest of MLGraphXnnpackTest that tests against conv2d, depthwise conv2d with and without fused bias operand and relu activation. [1]: webmachinelearning/webnn#324 Bug: 1273291 Change-Id: I8a70ee7bb053b386e12ff46e67d139683b044383 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4031876 Reviewed-by: Jiewei Qian <[email protected]> Commit-Queue: ningxin hu <[email protected]> Cr-Commit-Position: refs/heads/main@{#1093328}
1 parent 358b2f2 commit f5b7831

File tree

6 files changed

+422
-67
lines changed

6 files changed

+422
-67
lines changed

third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc

+45-52
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <algorithm>
88

99
#include "base/numerics/checked_math.h"
10-
#include "third_party/abseil-cpp/absl/types/optional.h"
1110
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
1211
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h"
1312
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h"
@@ -133,53 +132,6 @@ MLOperand* BuildElementWiseBinary(MLGraphBuilder* builder,
133132
return output;
134133
}
135134

136-
struct PaddingSizes {
137-
uint32_t begin;
138-
uint32_t end;
139-
};
140-
141-
// Calculate the padding given auto pad, input size, filter size, stride and
142-
// dilation. Return the calculated padding sizes if no error.
143-
absl::optional<PaddingSizes> CalculatePaddingForAutoPad(
144-
V8MLAutoPad::Enum auto_pad,
145-
const uint32_t input_size,
146-
const uint32_t filter_size,
147-
const uint32_t stride,
148-
const uint32_t dilation) {
149-
auto checked_output_size =
150-
(base::MakeCheckedNum<uint32_t>(input_size) + stride - 1) / stride;
151-
auto checked_dilated_filter_size =
152-
(base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
153-
auto checked_needed_input_size =
154-
(checked_output_size - 1) * stride + checked_dilated_filter_size;
155-
if (!checked_needed_input_size.IsValid()) {
156-
return absl::nullopt;
157-
}
158-
auto checked_total_padding =
159-
checked_needed_input_size.ValueOrDie() > input_size
160-
? checked_needed_input_size - input_size
161-
: base::MakeCheckedNum<uint32_t>(0);
162-
base::CheckedNumeric<uint32_t> checked_padding_begin, checked_padding_end;
163-
switch (auto_pad) {
164-
case V8MLAutoPad::Enum::kSameUpper:
165-
checked_padding_begin = checked_total_padding / 2;
166-
checked_padding_end = (checked_total_padding + 1) / 2;
167-
break;
168-
case V8MLAutoPad::Enum::kSameLower:
169-
checked_padding_begin = (checked_total_padding + 1) / 2;
170-
checked_padding_end = checked_total_padding / 2;
171-
break;
172-
default:
173-
NOTREACHED();
174-
}
175-
uint32_t padding_begin, padding_end;
176-
if (!checked_padding_begin.AssignIfValid(&padding_begin) ||
177-
!checked_padding_end.AssignIfValid(&padding_end)) {
178-
return absl::nullopt;
179-
}
180-
return PaddingSizes({.begin = padding_begin, .end = padding_end});
181-
}
182-
183135
// Calculate the output size for conv2d based on WebNN spec:
184136
// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-conv2d
185137
// Return the calculated output size if no error.
@@ -315,7 +267,7 @@ absl::optional<FloatSize2D> ValidateAndCalculateConv2dOutputSizes(
315267
// options.padding array are ignored and the explicit padding values need to
316268
// be calculated.
317269
if (auto_pad != V8MLAutoPad::Enum::kExplicit) {
318-
auto padding_sizes_height = CalculatePaddingForAutoPad(
270+
auto padding_sizes_height = MLGraphBuilder::CalculatePaddingForAutoPad(
319271
auto_pad.AsEnum(), input_height, filter_height, stride_height,
320272
dilation_height);
321273
if (!padding_sizes_height) {
@@ -327,9 +279,9 @@ absl::optional<FloatSize2D> ValidateAndCalculateConv2dOutputSizes(
327279
}
328280
padding_beginning_height = padding_sizes_height.value().begin;
329281
padding_ending_height = padding_sizes_height.value().end;
330-
auto padding_sizes_width =
331-
CalculatePaddingForAutoPad(auto_pad.AsEnum(), input_width, filter_width,
332-
stride_width, dilation_width);
282+
auto padding_sizes_width = MLGraphBuilder::CalculatePaddingForAutoPad(
283+
auto_pad.AsEnum(), input_width, filter_width, stride_width,
284+
dilation_width);
333285
if (!padding_sizes_width) {
334286
exception_state.ThrowDOMException(
335287
DOMExceptionCode::kDataError,
@@ -561,6 +513,47 @@ MLContext* MLGraphBuilder::GetContext() const {
561513
return ml_context_;
562514
}
563515

516+
// static
517+
absl::optional<MLGraphBuilder::PaddingSizes>
518+
MLGraphBuilder::CalculatePaddingForAutoPad(V8MLAutoPad::Enum auto_pad,
519+
const uint32_t input_size,
520+
const uint32_t filter_size,
521+
const uint32_t stride,
522+
const uint32_t dilation) {
523+
auto checked_output_size =
524+
(base::MakeCheckedNum<uint32_t>(input_size) + stride - 1) / stride;
525+
auto checked_dilated_filter_size =
526+
(base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
527+
auto checked_needed_input_size =
528+
(checked_output_size - 1) * stride + checked_dilated_filter_size;
529+
if (!checked_needed_input_size.IsValid()) {
530+
return absl::nullopt;
531+
}
532+
auto checked_total_padding =
533+
checked_needed_input_size.ValueOrDie() > input_size
534+
? checked_needed_input_size - input_size
535+
: base::MakeCheckedNum<uint32_t>(0);
536+
base::CheckedNumeric<uint32_t> checked_padding_begin, checked_padding_end;
537+
switch (auto_pad) {
538+
case V8MLAutoPad::Enum::kSameUpper:
539+
checked_padding_begin = checked_total_padding / 2;
540+
checked_padding_end = (checked_total_padding + 1) / 2;
541+
break;
542+
case V8MLAutoPad::Enum::kSameLower:
543+
checked_padding_begin = (checked_total_padding + 1) / 2;
544+
checked_padding_end = checked_total_padding / 2;
545+
break;
546+
default:
547+
NOTREACHED();
548+
}
549+
uint32_t padding_begin, padding_end;
550+
if (!checked_padding_begin.AssignIfValid(&padding_begin) ||
551+
!checked_padding_end.AssignIfValid(&padding_end)) {
552+
return absl::nullopt;
553+
}
554+
return PaddingSizes({.begin = padding_begin, .end = padding_end});
555+
}
556+
564557
MLOperand* MLGraphBuilder::input(String name,
565558
const MLOperandDescriptor* desc,
566559
ExceptionState& exception_state) {

third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h

+18
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_BUILDER_H_
66
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_BUILDER_H_
77

8+
#include "third_party/abseil-cpp/absl/types/optional.h"
89
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
10+
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_auto_pad.h"
911
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
1012
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
1113
#include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h"
@@ -48,6 +50,22 @@ class MODULES_EXPORT MLGraphBuilder final : public ScriptWrappable {
4850

4951
MLContext* GetContext() const;
5052

53+
struct PaddingSizes {
54+
uint32_t begin;
55+
uint32_t end;
56+
};
57+
58+
// Calculate the effective padding based on WebNN auto padding rules.
59+
//
60+
// TODO(crbug.com/1273291): Add the link to WebNN spec's algorithm once it is
61+
// defined, tracked by: https://github.com/webmachinelearning/webnn/issues/326
62+
static absl::optional<PaddingSizes> CalculatePaddingForAutoPad(
63+
V8MLAutoPad::Enum auto_pad,
64+
const uint32_t input_size,
65+
const uint32_t filter_size,
66+
const uint32_t stride,
67+
const uint32_t dilation);
68+
5169
// ml_graph_builder.idl
5270
MLOperand* input(String name,
5371
const MLOperandDescriptor* desc,

third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc

+8-5
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,20 @@ NotShared<DOMArrayBufferView> CreateDOMArrayBufferView(
105105
return buffer_view;
106106
}
107107

108-
MLOperand* BuildConstant(V8TestingScope& scope,
109-
MLGraphBuilder* builder,
110-
const Vector<uint32_t>& dimensions,
111-
V8MLOperandType::Enum type) {
108+
MLOperand* BuildConstant(
109+
V8TestingScope& scope,
110+
MLGraphBuilder* builder,
111+
const Vector<uint32_t>& dimensions,
112+
V8MLOperandType::Enum type,
113+
absl::optional<NotShared<DOMArrayBufferView>> user_buffer_view) {
112114
auto* desc = MLOperandDescriptor::Create();
113115
desc->setDimensions(dimensions);
114116
desc->setType(type);
115117
size_t size = std::accumulate(dimensions.begin(), dimensions.end(), size_t(1),
116118
std::multiplies<uint32_t>());
117119
NotShared<DOMArrayBufferView> buffer_view =
118-
CreateDOMArrayBufferView(size, type);
120+
user_buffer_view ? std::move(user_buffer_view.value())
121+
: CreateDOMArrayBufferView(size, type);
119122
auto* constant =
120123
builder->constant(desc, buffer_view, scope.GetExceptionState());
121124
EXPECT_NE(constant, nullptr);

third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_BUILDER_TEST_H_
77

88
#include "testing/gtest/include/gtest/gtest.h"
9+
#include "third_party/abseil-cpp/absl/types/optional.h"
910
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h"
1011
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_context_options.h"
1112
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h"
@@ -40,10 +41,12 @@ NotShared<DOMArrayBufferView> CreateDOMArrayBufferView(
4041
size_t size,
4142
V8MLOperandType::Enum type);
4243

43-
MLOperand* BuildConstant(V8TestingScope& scope,
44-
MLGraphBuilder* builder,
45-
const Vector<uint32_t>& dimensions,
46-
V8MLOperandType::Enum type);
44+
MLOperand* BuildConstant(
45+
V8TestingScope& scope,
46+
MLGraphBuilder* builder,
47+
const Vector<uint32_t>& dimensions,
48+
V8MLOperandType::Enum type,
49+
absl::optional<NotShared<DOMArrayBufferView>> buffer_view = absl::nullopt);
4750

4851
NotShared<DOMArrayBufferView> CreateArrayBufferViewForOperand(
4952
const MLOperand* operand);

0 commit comments

Comments
 (0)