Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions js/web/docs/webgpu-operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Do not modify directly.*
| GridSample | ai.onnx(16-19); com.ms.internal.nhwc(16-19) | |
| GroupQueryAttention | com.microsoft(1+) | |
| HardSigmoid | ai.onnx(6+) | |
| HardSwish | ai.onnx(14+) | |
| If | ai.onnx(1-10,11-12,13-18,19-20,21+) | |
| InstanceNormalization | ai.onnx(6+); com.ms.internal.nhwc(6+) | |
| LayerNormalization | ai.onnx(1-16,17+) | |
Expand Down
1 change: 1 addition & 0 deletions js/web/lib/wasm/jsep/webgpu/op-resolve-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const WEBGPU_OP_RESOLVE_RULES: Map<string, OperatorImplementation> = new
['GridSample', [gridSample, parseGridSampleAttributes]],
['GroupQueryAttention', [groupQueryAttention]],
['HardSigmoid', [unaryOps.hardSigmoid, unaryOps.parseHardSigmoidAttributes]],
['HardSwish', [unaryOps.hardSwish]],
['InstanceNormalization', [instanceNorm]],
['LayerNormalization', [layerNorm]],
['LeakyRelu', [unaryOps.leakyRelu, unaryOps.parseAlphaAttributes]],
Expand Down
12 changes: 12 additions & 0 deletions js/web/lib/wasm/jsep/webgpu/ops/unary-op.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,18 @@ export const hardSigmoid = (context: ComputeContext, attributes: HardSigmoidAttr
);
};

export const hardSwish = (context: ComputeContext): void => {
const dataType = tensorTypeToWsglValueType(context.inputs[0].dataType);
context.compute(
createElementwiseProgramInfo(
context.inputs[0],
'HardSwish',
(a) =>
`${a} * max(vec4<${dataType}>(0.0), min(vec4<${dataType}>(1.0), vec4<${dataType}>(${dataType}(1.0 / 6.0)) * ${a} + vec4<${dataType}>(0.5)))`,
),
);
};

export const sin = (context: ComputeContext): void => {
context.compute(createElementwiseProgramInfo(context.inputs[0], 'Sin', 'sin'));
};
Expand Down
2 changes: 2 additions & 0 deletions onnxruntime/core/providers/js/js_execution_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 13, Erf
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 6, 12, Sigmoid);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 13, Sigmoid);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 6, HardSigmoid);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 14, HardSwish);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 6, 12, Log);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kOnnxDomain, 13, Log);

Expand Down Expand Up @@ -440,6 +441,7 @@ std::unique_ptr<KernelRegistry> RegisterKernels() {
KERNEL_CREATE_INFO_VERSIONED(6, 12, Sigmoid),
KERNEL_CREATE_INFO(13, Sigmoid),
KERNEL_CREATE_INFO(6, HardSigmoid),
KERNEL_CREATE_INFO(14, HardSwish),
KERNEL_CREATE_INFO_VERSIONED(6, 12, Log),
KERNEL_CREATE_INFO(13, Log),

Expand Down
3 changes: 3 additions & 0 deletions onnxruntime/core/providers/js/operators/unary.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ JSEP_ELEMENTWISE_KERNEL(Sigmoid, 13, Sigmoid)
JSEP_CLASS_IMPL_ATTRIBUTE_FLOAT_2_DEFAULT(HardSigmoid, HardSigmoid, alpha, 0.2, beta, 0.5)
JSEP_ELEMENTWISE_KERNEL(HardSigmoid, 6, HardSigmoid)

JSEP_KERNEL_IMPL(HardSwish, HardSwish)
JSEP_ELEMENTWISE_KERNEL(HardSwish, 14, HardSwish)

JSEP_KERNEL_IMPL(Log, Log)
JSEP_ELEMENTWISE_VERSIONED_KERNEL(Log, 6, 12, Log)
JSEP_ELEMENTWISE_KERNEL(Log, 13, Log)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ class HardSigmoid final : public UnaryElementwise {

WEBGPU_ELEMENTWISE_KERNEL(HardSigmoid, 6, WebGpuSupportedFloatTypes())

WEBGPU_ELEMENTWISE_IMPL(HardSwish, "hard_swish_v(a)", HardSwishImpl, ShaderUsage::UseElementTypeAlias)
WEBGPU_ELEMENTWISE_KERNEL(HardSwish, 14, WebGpuSupportedFloatTypes())

WEBGPU_ELEMENTWISE_IMPL(Sin, "sin(a)")
WEBGPU_ELEMENTWISE_KERNEL(Sin, 7, WebGpuSupportedFloatTypes())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ fn hard_sigmoid_v(v: vec4<x_element_t>) -> vec4<x_element_t> {
}
)";

constexpr const char HardSwishImpl[] = R"(
fn hard_swish_v(v: vec4<x_element_t>) -> vec4<x_element_t> {
let alpha = x_element_t(1.0 / 6.0);
let beta_v = vec4<x_element_t>(x_element_t(0.5));
return v * max(vec4<x_element_t>(0.0),
min(vec4<x_element_t>(1.0), alpha * v + beta_v));
}
)";

// built-in function tanh() does not work with large input (f32 88.7 or f16 11.09)
// https://github.com/gpuweb/gpuweb/issues/4458
constexpr const char TanhImpl[] = R"(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ static const BuildKernelCreateInfoFn build_kernel_create_info_function_table[] =
KERNEL_CREATE_INFO_VERSIONED(6, 12, Sigmoid),
KERNEL_CREATE_INFO(13, Sigmoid),
KERNEL_CREATE_INFO(6, HardSigmoid),
KERNEL_CREATE_INFO(14, HardSwish),
KERNEL_CREATE_INFO_VERSIONED(6, 12, Log),
KERNEL_CREATE_INFO(13, Log),

Expand Down
54 changes: 54 additions & 0 deletions onnxruntime/test/providers/webgpu/hardswish_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include <algorithm>
#include <array>
#include <type_traits>
#include <vector>

#include "gtest/gtest.h"

#include "default_providers.h"
#include "test/providers/provider_test_utils.h"

namespace onnxruntime {
namespace test {

template <typename T>
void RunHardSwishTest() {
auto webgpu_ep = DefaultWebGpuExecutionProvider();
if (!webgpu_ep) {
GTEST_SKIP() << "WebGPU execution provider is not available.";
}

const std::vector<int64_t> kDims{2, 5};
const std::vector<float> input_values{-6.0f, -3.0f, -1.0f, 0.0f, 1.0f, 3.0f, 6.0f, 8.0f, -8.0f, 0.5f};
std::vector<float> expected_values;
expected_values.reserve(input_values.size());
std::transform(input_values.cbegin(), input_values.cend(), std::back_inserter(expected_values),
[](float x) { return x * std::max(0.0f, std::min(1.0f, x / 6.0f + 0.5f)); });

OpTester test("HardSwish", 14);
if constexpr (std::is_same_v<T, float>) {
test.AddInput<T>("X", kDims, input_values);
test.AddOutput<T>("Y", kDims, expected_values);
} else {
test.AddInput<T>("X", kDims, FloatsToMLFloat16s(input_values));
test.AddOutput<T>("Y", kDims, FloatsToMLFloat16s(expected_values));
test.SetOutputAbsErr("Y", 0.01f);
test.SetOutputRelErr("Y", 0.01f);
}

test.ConfigEp(std::move(webgpu_ep)).RunWithConfig();
}

TEST(HardSwish_WebGPU, Float32) {
RunHardSwishTest<float>();
}

TEST(HardSwish_WebGPU, Float16) {
RunHardSwishTest<MLFloat16>();
}

} // namespace test
} // namespace onnxruntime
Loading