Skip to content

Commit

Permalink
WebNN: Define XNNPACK Node for transpose
Browse files Browse the repository at this point in the history
This CL implements DefineXnnNodeForTranspose() method that defines
XNNPACK Node for transpose MLOperator by
xnn_define_static_transpose().

For unit tests, this CL implements TransposeTest of
MLGraphXnnpackTest that checks the compute results of transpose
operators.

Bug: 1273291
Change-Id: Id93e9dcd00c95d5c885f4c334f98562bab9e19b3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4092123
Reviewed-by: Jiewei Qian <qjw@chromium.org>
Commit-Queue: Lisha Guo <lisha.guo@intel.com>
Cr-Commit-Position: refs/heads/main@{#1116224}
  • Loading branch information
lisa0314 authored and Chromium LUCI CQ committed Mar 13, 2023
1 parent 2673b87 commit 448662b
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 66 deletions.
73 changes: 73 additions & 0 deletions third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
Expand Up @@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pool_2d_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_transpose_options.h"
#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h"
#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h"

Expand Down Expand Up @@ -886,6 +887,78 @@ TEST_P(MLGraphTest, ReshapeTest) {
}
}

template <typename T>
struct TransposeTester {
OperandInfo<T> input;
Vector<T> expected;

void Test(MLGraphTest& helper,
V8TestingScope& scope,
MLGraphBuilder* builder,
MLTransposeOptions* options = MLTransposeOptions::Create()) {
auto* input_operand = BuildInput(builder, "input", input.dimensions,
input.type, scope.GetExceptionState());
auto* output_operand =
BuildTranspose(scope, builder, input_operand, options);
auto [graph, build_exception] =
helper.BuildGraph(scope, builder, {{"output", output_operand}});
EXPECT_NE(graph, nullptr);

MLNamedArrayBufferViews inputs(
{{"input",
CreateArrayBufferViewForOperand(input_operand, input.values)}});
MLNamedArrayBufferViews outputs(
{{"output", CreateArrayBufferViewForOperand(output_operand)}});
auto* compute_exception =
helper.ComputeGraph(scope, graph, inputs, outputs);
EXPECT_EQ(compute_exception, nullptr);
auto results = GetArrayBufferViewValues<T>(outputs[0].second);
EXPECT_EQ(results, expected);
}
};

TEST_P(MLGraphTest, TransposeTest) {
V8TestingScope scope;
auto* builder = CreateMLGraphBuilder(scope.GetExecutionContext());
{
// Test transpose operator with default options.
auto* options = MLTransposeOptions::Create();
TransposeTester<float>{
.input = {.type = V8MLOperandType::Enum::kFloat32,
.dimensions = {2, 3, 4},
.values =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
}},
.expected =
{
0, 12, 4, 16, 8, 20, 1, 13, 5, 17, 9, 21,
2, 14, 6, 18, 10, 22, 3, 15, 7, 19, 11, 23,
}}
.Test(*this, scope, builder, options);
}
{
// Test transpose with permutation = {0, 2, 1}.
auto* options = MLTransposeOptions::Create();
options->setPermutation({{0, 2, 1}});
TransposeTester<float>{
.input = {.type = V8MLOperandType::Enum::kFloat32,
.dimensions = {2, 3, 4},
.values =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
}},
.expected =
{
0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11,
12, 16, 20, 13, 17, 21, 14, 18, 22, 15, 19, 23,
}}
.Test(*this, scope, builder, options);
}
}

INSTANTIATE_TEST_SUITE_P(
All,
MLGraphTest,
Expand Down
51 changes: 51 additions & 0 deletions third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
Expand Up @@ -21,6 +21,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gemm_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pool_2d_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_resample_2d_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_transpose_options.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/ml/ml.h"
#include "third_party/blink/renderer/modules/ml/ml_context.h"
Expand Down Expand Up @@ -938,6 +939,51 @@ xnn_status DefineXnnNodeForResample2d(
return xnn_status_success;
}

xnn_status DefineXnnNodeForTranspose(
xnn_subgraph_t subgraph,
const MLOperator* transpose,
const OperandValueIdMap& operand_value_id_map,
String& error_message) {
const uint32_t input_id =
GetOperatorInputValueId(transpose, operand_value_id_map);
const uint32_t output_id =
GetOperatorOutputValueId(transpose, operand_value_id_map);
const MLTransposeOptions* options =
static_cast<const MLTransposeOptions*>(transpose->Options());

const auto* input = transpose->Inputs()[0].Get();
CHECK(input);
const auto input_rank = input->Dimensions().size();
// According to WebNN spec:
// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-transpose,
// When permutation is not specified, it’s set to [N-1, ..., 0], where N is
// the rank of the input tensor.
Vector<int32_t> default_permutation(input_rank);
for (wtf_size_t i = 0; i < input_rank - 1; i++) {
default_permutation[i] = input_rank - 1 - i;
}
const Vector<int32_t> permutation =
options->getPermutationOr(std::move(default_permutation));

// The current WebNN spec defines the value of permutation as signed
// integer: https://www.w3.org/TR/webnn/#dom-mltransposeoptions-permutation
// And an issue has been filed to track it:
// https://github.com/webmachinelearning/webnn/issues/317
Vector<size_t> xnn_permutation(input_rank);
base::ranges::transform(permutation, xnn_permutation.begin(), [](int32_t p) {
return base::checked_cast<size_t>(p);
});
const uint32_t flags = 0;
// XNNPACK will memcpy the content of `xnn_permutation` vector to its internal
// structure, so it is safe to release `xnn_permutation` vector after this
// call. Please refer to the implementation at:
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/xnnpack/src/src/subgraph/static-transpose.c;l=267
XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_static_transpose(
subgraph, xnn_permutation.size(), xnn_permutation.data(), input_id,
output_id, flags));
return xnn_status_success;
}

// Define an XNNPACK Node given an MLOperator object and add it into the
// Subgraph object. The operand_value_id_map is used to find the corresponding
// input and output XNNPACK Values of this MLOperator object. This method calls
Expand Down Expand Up @@ -1003,6 +1049,11 @@ xnn_status DefineXnnNode(xnn_subgraph_t subgraph,
subgraph, ml_operator, operand_value_id_map, error_message));
break;
}
case MLOperator::OperatorKind::kTranspose: {
XNN_CHECK_STATUS(DefineXnnNodeForTranspose(
subgraph, ml_operator, operand_value_id_map, error_message));
break;
}
default: {
error_message = "The operator (" +
MLOperator::OperatorKindToString(ml_operator->Kind()) +
Expand Down

This file was deleted.

This file was deleted.

@@ -0,0 +1,23 @@
This is a testharness.js-based test.
PASS transpose float32 1D tensor default options / cpu / async
PASS transpose float32 2D tensor default options / cpu / async
PASS transpose float32 3D tensor default options / cpu / async
PASS transpose float32 4D tensor default options / cpu / async
PASS transpose float32 5D tensor default options / cpu / async
PASS transpose float32 1D tensor options.permutation / cpu / async
PASS transpose float32 2D tensor options.permutation / cpu / async
PASS transpose float32 3D tensor options.permutation / cpu / async
PASS transpose float32 4D tensor options.permutation / cpu / async
PASS transpose float32 5D tensor options.permutation / cpu / async
PASS transpose float32 1D tensor default options / gpu / async
PASS transpose float32 2D tensor default options / gpu / async
PASS transpose float32 3D tensor default options / gpu / async
PASS transpose float32 4D tensor default options / gpu / async
PASS transpose float32 5D tensor default options / gpu / async
PASS transpose float32 1D tensor options.permutation / gpu / async
PASS transpose float32 2D tensor options.permutation / gpu / async
PASS transpose float32 3D tensor options.permutation / gpu / async
PASS transpose float32 4D tensor options.permutation / gpu / async
PASS transpose float32 5D tensor options.permutation / gpu / async
Harness: the test ran to completion.

0 comments on commit 448662b

Please sign in to comment.