53 const ffi::Array<int64_t>& axis,
double epsilon,
54 std::string name =
"T_layer_norm", std::string tag =
kInjective) {
56 const auto& data_type = data->dtype;
57 const auto& gamma_type = gamma->dtype;
58 const auto& beta_type = beta.has_value() ? beta.value()->dtype : data_type;
59 TVM_FFI_ICHECK(data_type == gamma_type && data_type == beta_type)
60 <<
"layer_norm: data, gamma and beta must have the same type";
62 <<
"layer_norm: only support float32 and float16 for now";
67 auto ndim = data->shape.size();
68 TVM_FFI_ICHECK_NE(ndim, 0) <<
"Cannot reduce a 0 dim Tensor";
69 auto real_axis =
GetRealAxis(
static_cast<int>(ndim), axis);
75 auto make_eval_range = [&real_axis, &reduce_axes,
76 ndim](
const ffi::Array<PrimVar>& non_reduce_indices) {
77 ffi::Array<PrimExpr> eval_range;
81 for (
size_t i = 0; i < ndim; ++i) {
82 if (std::find(real_axis.begin(), real_axis.end(), i) != real_axis.end()) {
84 eval_range.push_back(reduce_axes[red_counter]);
87 eval_range.push_back(non_reduce_indices[arg_counter]);
96 [is_float16, &data, &reduce_axes, &make_eval_range,
97 f32_ty](
const ffi::Array<PrimVar>& indices) {
98 auto eval_range = make_eval_range(indices);
105 data->op.value()->name +
"_sum", kCommReduce);
108 PrimExpr reduce_extent = MakeConst(reduce_dtype, 1);
109 for (
int i : real_axis) {
110 reduce_extent *= data->shape[i];
114 [&temp_sum, &reduce_extent](
const ffi::Array<PrimVar>& indices) {
115 return temp_sum(indices) / reduce_extent;
117 data->op.value()->name +
"_mean",
kInjective);
121 [is_float16, &data, &reduce_axes, &make_eval_range, &temp_mean,
122 f32_ty](
const ffi::Array<PrimVar>& indices) {
123 auto eval_range = make_eval_range(indices);
128 PrimExpr diff = x - temp_mean(indices);
129 return prim::sum(diff * diff, reduce_axes);
131 data->op.value()->name +
"_var_sum", kCommReduce);
133 auto layer_norm_func = [&](
const ffi::Array<PrimVar>& indices) {
134 ffi::Array<PrimVar> reduce_indices, non_reduce_indices;
135 for (
int i = 0, n =
static_cast<int>(indices.size()); i < n; ++i) {
136 if (std::find(real_axis.begin(), real_axis.end(), i) != real_axis.end()) {
137 reduce_indices.push_back(indices[i]);
139 non_reduce_indices.push_back(indices[i]);
142 auto mean = temp_mean(non_reduce_indices);
143 auto var = temp_var_sum(non_reduce_indices) / reduce_extent;
149 if (beta.has_value()) {
154 return te::compute(data->shape, layer_norm_func, name, tag);
PrimExpr sum(PrimExpr source, ffi::Array< s_tir::IterVar > axis, ffi::Array< PrimExpr > init={}, Location loc=UnknownLoc())
sum of source expression over axis
Tensor compute(ffi::Array< PrimExpr > shape, FCompute fcompute, std::string name="tensor", std::string tag="", ffi::Map< ffi::String, ffi::Any > attrs={})
Construct a new tensor by computing over shape, using the computation rule: result_tensor[axis] = fco...
Tensor layer_norm(const Tensor &data, const Tensor &gamma, const ffi::Optional< Tensor > &beta, const ffi::Array< int64_t > &axis, double epsilon, std::string name="T_layer_norm", std::string tag=kInjective)
Layer normalization.
Definition layer_norm.h:52
ffi::Array< PrimExpr > MakeReduceTargetShape(const std::vector< int > &real_axis, const Tensor &data, bool keepdims, bool atleast1d)
Calculate the target shape for a reduce op.
Definition reduction.h:98
std::vector< int > GetRealAxis(int ndim, const ffi::Optional< ffi::Array< int64_t > > &axis)
Convert a reduction axis which could be empty or have negative elements into a real axis with valid d...
Definition reduction.h:64