Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
adddd06
Add CPU and WebGPU kernels for GatedAdd, GatedRMSNorm, LinearAttentio…
Copilot Aug 15, 2026
c35a2a0
Fix WebGPU input/output binding order and remove unused include
Copilot Aug 15, 2026
d336d6e
Reuse shared activation utilities for Qwen CPU gates
Copilot Aug 15, 2026
72d1767
Document shared activation functor reuse
Copilot Aug 15, 2026
a2302a0
Align LinearAttentionGate CPU error message
Copilot Aug 15, 2026
8661dc5
Align WebGPU LinearAttentionGate error message
Copilot Aug 15, 2026
ed1fc02
Apply requested clang-format corrections
Copilot Aug 15, 2026
e8e303f
Clarify WebGPU SiLU helper name
Copilot Aug 15, 2026
e6216fd
Fix CPU iteration width and FP16 rounding
Copilot Aug 15, 2026
d00553c
Clarify WebGPU sigmoid helper
Copilot Aug 15, 2026
52258f0
Cast WebGPU FP16 GatedAdd output
Copilot Aug 15, 2026
72e5dc6
Fix float buffer packing into Eigen for CPU
Copilot Aug 15, 2026
d7c787f
Fix clang-format indentation in linear_attention_gates
Copilot Aug 15, 2026
cdba354
Add CUDA BF16 LpNormalization support and test
Copilot Aug 15, 2026
2539fa3
Add missing registration for LpNorm BF16 CUDA
Copilot Aug 15, 2026
50e329e
Add CUDA BF16 support for CausalConvWithState and LinearAttention
Copilot Aug 15, 2026
38f8596
Update docs
kunal-vaishnavi Aug 15, 2026
fc78255
Relax GatedAdd reduced precision tolerance
Copilot Aug 15, 2026
b96bf7f
Relax WebGPU GatedAdd FP16 tolerance
Copilot Aug 16, 2026
1460571
Address WebGPU review feedback: use Get/SetByOffset, drop redundant c…
Copilot Aug 18, 2026
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
9 changes: 6 additions & 3 deletions docs/OperatorKernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ The **OpSet Version** column uses the following notation:
|FusedConv|*in* X:**T**<br> *in* W:**T**<br> *in* B:**T**<br> *in* Z:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
|FusedGemm|*in* A:**T**<br> *in* B:**T**<br> *in* C:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
|FusedMatMul|*in* A:**T**<br> *in* B:**T**<br> *out* Y:**T**|1+|**T** = tensor(double), tensor(float)|
|GatedAdd|*in* X:**T**<br> *in* Y:**T**<br> *in* gate:**T**<br> *out* output:**T**|1+|**T** = tensor(float), tensor(float16)|
|GatedRMSNorm|*in* X:**T**<br> *in* scale:**T**<br> *in* gate:**T**<br> *out* Y:**T**|1+|**T** = tensor(float), tensor(float16)|
|GatherBlockQuantized|*in* data:**T1**<br> *in* indices:**Tind**<br> *in* scales:**T2**<br> *in* zero_points:**T1**<br> *out* output:**T2**|1+|**T1** = tensor(int4), tensor(uint4), tensor(uint8)<br/> **T2** = tensor(float), tensor(float16)<br/> **Tind** = tensor(int32), tensor(int64)|
|GatherND|*in* data:**T**<br> *in* indices:**Tind**<br> *out* output:**T**|1+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)<br/> **Tind** = tensor(int32), tensor(int64)|
|Gelu|*in* X:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
Expand All @@ -595,6 +597,7 @@ The **OpSet Version** column uses the following notation:
|GroupQueryAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* past_key:**T_CACHE**<br> *in* past_value:**T_CACHE**<br> *in* seqlens_k:**M**<br> *in* total_sequence_length:**M**<br> *in* cos_cache:**T**<br> *in* sin_cache:**T**<br> *in* position_ids:**tensor(int64)**<br> *in* attention_bias:**T**<br> *in* head_sink:**T**<br> *in* k_scale:**T_KV_SCALE**<br> *in* v_scale:**T_KV_SCALE**<br> *in* q_norm_weight:**T**<br> *in* k_norm_weight:**T**<br> *out* output:**T**<br> *out* present_key:**T_CACHE**<br> *out* present_value:**T_CACHE**<br> *out* output_qk:**T**|1+|**M** = tensor(int32)<br/> **T** = tensor(float), tensor(float16)<br/> **T_CACHE** = tensor(float), tensor(float16), tensor(int8), tensor(uint8)<br/> **T_KV_SCALE** = tensor(float)|
|Inverse|*in* X:**T**<br> *out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)|
|LinearAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* past_state:**S**<br> *in* decay:**T**<br> *in* beta:**T**<br> *out* output:**T**<br> *out* present_state:**S**|1+|**T** = tensor(float)|
|LinearAttentionGate|*in* a:**T**<br> *in* dt_bias:**TF**<br> *in* decay_scale:**TF**<br> *in* b:**T**<br> *out* decay:**T**<br> *out* beta:**T**|1+|**T** = tensor(float), tensor(float16)<br/> **TF** = tensor(float)|
|MRotaryEmbedding|*in* input:**T**<br> *in* position_ids:**M**<br> *in* cos_cache:**T**<br> *in* sin_cache:**T**<br> *out* output:**T**|1+|**M** = tensor(int64)<br/> **T** = tensor(float), tensor(float16)|
|MatMulBnb4|*in* A:**T1**<br> *in* B:**T2**<br> *in* absmax:**T1**<br> *out* Y:**T1**|1+|**T1** = tensor(float)<br/> **T2** = tensor(uint8)|
|MatMulFpQ4|*in* A:**T1**<br> *in* B:**T2**<br> *in* B_shape:**T3**<br> *out* Y:**T1**|1+|**T1** = tensor(float)<br/> **T2** = tensor(uint8)<br/> **T3** = tensor(int64)|
Expand Down Expand Up @@ -836,7 +839,7 @@ The **OpSet Version** column uses the following notation:
|||[13, 18]|**B** = tensor(bool)<br/> **I** = tensor(int64)<br/> **V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[11, 12]|**B** = tensor(bool)<br/> **I** = tensor(int64)<br/> **V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||[1, 10]|**B** = tensor(bool)<br/> **I** = tensor(int64)<br/> **V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|LpNormalization|*in* input:**T**<br> *out* output:**T**|22+|**T** = tensor(float), tensor(float16)|
|LpNormalization|*in* input:**T**<br> *out* output:**T**|22+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|||[1, 21]|**T** = tensor(float), tensor(float16)|
|MatMul|*in* A:**T**<br> *in* B:**T**<br> *out* Y:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)|
|||[9, 12]|**T** = tensor(double), tensor(float), tensor(float16)|
Expand Down Expand Up @@ -1073,7 +1076,7 @@ The **OpSet Version** column uses the following notation:
|BiasSplitGelu|*in* X:**T**<br> *in* bias:**T**<br> *out* Y:**T**|1+|**T** = tensor(float), tensor(float16)|
|BitmaskBiasDropout|*in* data:**T**<br> *in* bias:**T**<br> *in* residual:**T**<br> *in* ratio:**T1**<br> *in* training_mode:**T2**<br> *out* output:**T**<br> *out* mask:**T3**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T1** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T2** = tensor(bool)<br/> **T3** = tensor(uint32)|
|BitmaskDropout|*in* data:**T**<br> *in* ratio:**T1**<br> *in* training_mode:**T2**<br> *out* output:**T**<br> *out* mask:**T3**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T1** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)<br/> **T2** = tensor(bool)<br/> **T3** = tensor(uint32)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**|1+|**T** = tensor(float), tensor(float16)|
|CausalConvWithState|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* past_state:**T**<br> *out* output:**T**<br> *out* present_state:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|ComplexMul|*in* A:**T**<br> *in* B:**T**<br> *out* C:**T**|1+|**T** = tensor(float), tensor(float16)|
|ComplexMulConj|*in* A:**T**<br> *in* B:**T**<br> *out* C:**T**|1+|**T** = tensor(float), tensor(float16)|
|ConvTransposeWithDynamicPads|*in* X:**T**<br> *in* W:**T**<br> *in* Pads:**tensor(int64)**<br> *in* B:**T**<br> *out* Y:**T**|1+|**T** = tensor(float)|
Expand All @@ -1100,7 +1103,7 @@ The **OpSet Version** column uses the following notation:
|GroupQueryAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* past_key:**T_CACHE**<br> *in* past_value:**T_CACHE**<br> *in* seqlens_k:**M**<br> *in* total_sequence_length:**M**<br> *in* cos_cache:**T**<br> *in* sin_cache:**T**<br> *in* position_ids:**tensor(int64)**<br> *in* attention_bias:**T**<br> *in* head_sink:**T**<br> *in* k_scale:**T_KV_SCALE**<br> *in* v_scale:**T_KV_SCALE**<br> *in* q_norm_weight:**T**<br> *in* k_norm_weight:**T**<br> *out* output:**T**<br> *out* present_key:**T_CACHE**<br> *out* present_value:**T_CACHE**<br> *out* output_qk:**T**|1+|**M** = tensor(int32)<br/> **T** = tensor(bfloat16), tensor(float16)<br/> **T_CACHE** = tensor(bfloat16), tensor(float16), tensor(float8e4m3fn), tensor(int8)<br/> **T_KV_SCALE** = tensor(float)|
|Inverse|*in* X:**T**<br> *out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)|
|Irfft|*in* X:**T**<br> *out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)|
|LinearAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* past_state:**S**<br> *in* decay:**T**<br> *in* beta:**T**<br> *out* output:**T**<br> *out* present_state:**S**|1+|**T** = tensor(float), tensor(float16)|
|LinearAttention|*in* query:**T**<br> *in* key:**T**<br> *in* value:**T**<br> *in* past_state:**S**<br> *in* decay:**T**<br> *in* beta:**T**<br> *out* output:**T**<br> *out* present_state:**S**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)|
|LinearAttentionGate|*in* a:**T**<br> *in* dt_bias:**TF**<br> *in* decay_scale:**TF**<br> *in* b:**T**<br> *out* decay:**T**<br> *out* beta:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)<br/> **TF** = tensor(float)|
|LongformerAttention|*in* input:**T**<br> *in* weight:**T**<br> *in* bias:**T**<br> *in* mask:**T**<br> *in* global_weight:**T**<br> *in* global_bias:**T**<br> *in* global:**G**<br> *out* output:**T**|1+|**T** = tensor(float), tensor(float16)|
|MRotaryEmbedding|*in* input:**T**<br> *in* position_ids:**M**<br> *in* cos_cache:**T**<br> *in* sin_cache:**T**<br> *out* output:**T**|1+|**M** = tensor(int64)<br/> **T** = tensor(bfloat16), tensor(float), tensor(float16)|
Expand Down
95 changes: 95 additions & 0 deletions onnxruntime/contrib_ops/cpu/bert/gated_add.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
// Licensed under the MIT License.

#include "contrib_ops/cpu/bert/gated_add.h"

#include "core/framework/tensor.h"
#include "core/platform/threadpool.h"

namespace onnxruntime {
namespace contrib {

#define REGISTER_KERNEL_TYPED(T) \
ONNX_OPERATOR_TYPED_KERNEL_EX( \
GatedAdd, \
kMSDomain, \
1, \
T, \
kCpuExecutionProvider, \
KernelDefBuilder() \
.TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
GatedAdd<T>);

REGISTER_KERNEL_TYPED(float)
REGISTER_KERNEL_TYPED(MLFloat16)

#undef REGISTER_KERNEL_TYPED

namespace {

// output = x + round_to_T(y * gate). For MLFloat16 the product is rounded to half before the
// add, matching separate ONNX Mul and Add operators.
template <typename T>
inline T GatedAddValue(T x, T y, T gate) {
if constexpr (std::is_same_v<T, MLFloat16>) {
const T product(y.ToFloat() * gate.ToFloat());
return T(x.ToFloat() + product.ToFloat());
} else {
return x + y * gate;
}
}

} // namespace

template <typename T>
Status GatedAdd<T>::Compute(OpKernelContext* context) const {
const Tensor* x = context->Input<Tensor>(0);
const Tensor* y = context->Input<Tensor>(1);
const Tensor* gate = context->Input<Tensor>(2);
const TensorShape& shape = x->Shape();

ORT_RETURN_IF_NOT(shape.NumDimensions() >= 1, "X must have rank >= 1");
ORT_RETURN_IF_NOT(y->Shape() == shape, "Y must have the same shape as X");
ORT_RETURN_IF_NOT(gate->Shape().NumDimensions() == shape.NumDimensions(),
"gate must have the same rank as X");

const size_t last_axis = shape.NumDimensions() - 1;
const int64_t hidden_size = shape[last_axis];
ORT_RETURN_IF_NOT(hidden_size > 0, "X last dimension must be positive");
ORT_RETURN_IF_NOT(gate->Shape()[last_axis] == 1, "gate last dimension must be 1");
for (size_t axis = 0; axis < last_axis; ++axis) {
ORT_RETURN_IF_NOT(gate->Shape()[axis] == shape[axis],
"gate dimension ", axis, " must match X");
}

Tensor* output = context->Output(0, shape);
const int64_t count = shape.Size();
if (count == 0) {
return Status::OK();
}

const T* x_data = x->Data<T>();
const T* y_data = y->Data<T>();
const T* gate_data = gate->Data<T>();
T* output_data = output->MutableData<T>();
const int64_t num_rows = count / hidden_size;

concurrency::ThreadPool::TryBatchParallelFor(
context->GetOperatorThreadPool(), onnxruntime::narrow<ptrdiff_t>(num_rows),
[&](ptrdiff_t row) {
const int64_t offset = row * hidden_size;
const T gate_value = gate_data[row];
for (int64_t i = 0; i < hidden_size; ++i) {
output_data[offset + i] = GatedAddValue<T>(x_data[offset + i], y_data[offset + i], gate_value);
}
},
0);

return Status::OK();
}

template class GatedAdd<float>;
template class GatedAdd<MLFloat16>;

} // namespace contrib
} // namespace onnxruntime
21 changes: 21 additions & 0 deletions onnxruntime/contrib_ops/cpu/bert/gated_add.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include "core/common/common.h"
#include "core/framework/op_kernel.h"

namespace onnxruntime {
namespace contrib {

// output = X + round_to_T(Y * gate), with gate broadcast across the last dimension.
template <typename T>
class GatedAdd final : public OpKernel {
public:
explicit GatedAdd(const OpKernelInfo& info) : OpKernel(info) {}
Status Compute(OpKernelContext* context) const override;
};

} // namespace contrib
} // namespace onnxruntime
181 changes: 181 additions & 0 deletions onnxruntime/contrib_ops/cpu/bert/linear_attention_gates.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
// Licensed under the MIT License.

#include "contrib_ops/cpu/bert/linear_attention_gates.h"

#include <cmath>

#include "core/framework/tensor.h"
#include "core/mlas/inc/mlas.h"
#include "core/platform/threadpool.h"

namespace onnxruntime {
namespace contrib {

#define REGISTER_KERNEL_TYPED(Op, T) \
ONNX_OPERATOR_TYPED_KERNEL_EX( \
Op, \
kMSDomain, \
1, \
T, \
kCpuExecutionProvider, \
KernelDefBuilder() \
.TypeConstraint("T", DataTypeImpl::GetTensorType<T>()) \
.TypeConstraint("TF", DataTypeImpl::GetTensorType<float>()), \
Op<T>);

REGISTER_KERNEL_TYPED(LinearAttentionGate, float)
REGISTER_KERNEL_TYPED(LinearAttentionGate, MLFloat16)

#undef REGISTER_KERNEL_TYPED

#define REGISTER_KERNEL_TYPED(Op, T) \
ONNX_OPERATOR_TYPED_KERNEL_EX( \
Op, \
kMSDomain, \
1, \
T, \
kCpuExecutionProvider, \
KernelDefBuilder() \
.TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
Op<T>);

REGISTER_KERNEL_TYPED(GatedRMSNorm, float)
REGISTER_KERNEL_TYPED(GatedRMSNorm, MLFloat16)

#undef REGISTER_KERNEL_TYPED

namespace {

inline float SigmoidFloat(float value) {
float output;
MlasComputeLogistic(&value, &output, 1);
return output;
}

inline float SoftplusFloat(float value) {
return value > 0.0f ? value + std::log(std::exp(-value) + 1.0f) : std::log(std::exp(value) + 1.0f);
}

} // namespace

template <typename T>
Status LinearAttentionGate<T>::Compute(OpKernelContext* context) const {
const Tensor* a = context->Input<Tensor>(0);
const Tensor* dt_bias = context->Input<Tensor>(1);
const Tensor* decay_scale = context->Input<Tensor>(2);
const Tensor* b = context->Input<Tensor>(3); // optional

const auto& a_shape = a->Shape();
ORT_RETURN_IF_NOT(a_shape.NumDimensions() >= 1, "a must have rank >= 1");
const int64_t num_heads = a_shape[a_shape.NumDimensions() - 1];
ORT_RETURN_IF_NOT(num_heads > 0, "a last dimension must be positive");

ORT_RETURN_IF_NOT(dt_bias->Shape().Size() == num_heads,
"dt_bias must have ", num_heads, " elements, got ", dt_bias->Shape().Size());
ORT_RETURN_IF_NOT(decay_scale->Shape().Size() == num_heads,
"decay_scale must have ", num_heads, " elements, got ", decay_scale->Shape().Size());

Tensor* decay = context->Output(0, a_shape);
Tensor* beta = context->Output(1, a_shape);

if (beta != nullptr) {
ORT_RETURN_IF_NOT(b != nullptr, "The b input is required when the beta output is requested");
ORT_RETURN_IF_NOT(b->Shape() == a_shape, "b must have the same shape as a");
}

const int64_t count = a_shape.Size();
if (count == 0) {
return Status::OK();
}

const T* a_data = a->Data<T>();
const T* b_data = b == nullptr ? nullptr : b->Data<T>();
const float* dt_bias_data = dt_bias->Data<float>();
const float* decay_scale_data = decay_scale->Data<float>();
T* decay_data = decay->MutableData<T>();
T* beta_data = beta == nullptr ? nullptr : beta->MutableData<T>();

const int64_t num_tokens = count / num_heads;

concurrency::ThreadPool::TryBatchParallelFor(
context->GetOperatorThreadPool(), onnxruntime::narrow<ptrdiff_t>(num_tokens),
[&](ptrdiff_t token) {
const int64_t offset = token * num_heads;
for (int64_t h = 0; h < num_heads; ++h) {
const int64_t idx = offset + h;
const float biased = static_cast<float>(a_data[idx]) + dt_bias_data[h];
decay_data[idx] = static_cast<T>(decay_scale_data[h] * SoftplusFloat(biased));
if (beta_data != nullptr) {
beta_data[idx] = static_cast<T>(SigmoidFloat(static_cast<float>(b_data[idx])));
}
}
},
0);

return Status::OK();
}

template <typename T>
GatedRMSNorm<T>::GatedRMSNorm(const OpKernelInfo& info) : OpKernel(info) {
epsilon_ = info.GetAttrOrDefault<float>("epsilon", 1e-5f);
}

template <typename T>
Status GatedRMSNorm<T>::Compute(OpKernelContext* context) const {
const Tensor* input = context->Input<Tensor>(0);
const Tensor* scale = context->Input<Tensor>(1);
const Tensor* gate = context->Input<Tensor>(2);

const auto& shape = input->Shape();
ORT_RETURN_IF_NOT(shape.NumDimensions() >= 1, "X must have rank >= 1");
ORT_RETURN_IF_NOT(gate->Shape() == shape, "gate must have the same shape as X");

const int64_t norm_size = scale->Shape().Size();
ORT_RETURN_IF_NOT(norm_size > 0, "scale must not be empty");
const int64_t last_dim = shape[shape.NumDimensions() - 1];
ORT_RETURN_IF_NOT(last_dim % norm_size == 0,
"X last dimension (", last_dim, ") must be a multiple of the scale length (",
norm_size, ")");

Tensor* output = context->Output(0, shape);
const int64_t count = shape.Size();
if (count == 0) {
return Status::OK();
}
const int64_t num_rows = count / norm_size;

const T* input_data = input->Data<T>();
const T* scale_data = scale->Data<T>();
const T* gate_data = gate->Data<T>();
T* output_data = output->MutableData<T>();

concurrency::ThreadPool::TryBatchParallelFor(
context->GetOperatorThreadPool(), onnxruntime::narrow<ptrdiff_t>(num_rows),
[&](ptrdiff_t row) {
const int64_t offset = row * norm_size;
float sum_sq = 0.0f;
for (int64_t i = 0; i < norm_size; ++i) {
const float v = static_cast<float>(input_data[offset + i]);
sum_sq += v * v;
}
const float inv_rms = 1.0f / std::sqrt(sum_sq / static_cast<float>(norm_size) + epsilon_);
for (int64_t i = 0; i < norm_size; ++i) {
const float z = static_cast<float>(gate_data[offset + i]);
const float normalized = static_cast<float>(input_data[offset + i]) * inv_rms *
static_cast<float>(scale_data[i]);
output_data[offset + i] = static_cast<T>(normalized * (z * SigmoidFloat(z)));
}
},
0);

return Status::OK();
}

template class LinearAttentionGate<float>;
template class LinearAttentionGate<MLFloat16>;
template class GatedRMSNorm<float>;
template class GatedRMSNorm<MLFloat16>;

} // namespace contrib
} // namespace onnxruntime
Loading
Loading