ggml-webgpu: add layer norm ops (#22406)
* shader(norm): add layer norm ops * shader(norm): stablize floating point computation with Kahan summation and handle mixed types * shader(norm): remove the non-contiguous strides * shader(norm): use the original implementation rather than the kahan summation
This commit is contained in:
@@ -1,20 +1,17 @@
|
||||
#ifdef INPLACE
|
||||
fn update(src_offset: u32, dst_offset: u32, scale: f32) {
|
||||
src[dst_offset] = scale * src[src_offset];
|
||||
}
|
||||
#if defined(SRC_F16) || defined(DST_F16)
|
||||
enable f16;
|
||||
#endif
|
||||
|
||||
@group(0) @binding(1)
|
||||
var<uniform> params: Params;
|
||||
#ifdef SRC_F16
|
||||
#define SRC_TYPE f16
|
||||
#else
|
||||
fn update(src_offset: u32, dst_offset: u32, scale: f32) {
|
||||
dst[dst_offset] = scale * src[src_offset];
|
||||
}
|
||||
#define SRC_TYPE f32
|
||||
#endif
|
||||
|
||||
@group(0) @binding(1)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
#ifdef DST_F16
|
||||
#define DST_TYPE f16
|
||||
#else
|
||||
#define DST_TYPE f32
|
||||
#endif
|
||||
|
||||
struct Params {
|
||||
@@ -40,9 +37,20 @@ struct Params {
|
||||
};
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<storage, read_write> src: array<f32>;
|
||||
var<storage, read_write> src: array<SRC_TYPE>;
|
||||
|
||||
var<workgroup> scratch: array<f32, WG_SIZE>;
|
||||
#ifdef INPLACE
|
||||
@group(0) @binding(1)
|
||||
var<uniform> params: Params;
|
||||
#else
|
||||
@group(0) @binding(1)
|
||||
var<storage, read_write> dst: array<DST_TYPE>;
|
||||
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
#endif
|
||||
|
||||
var<workgroup> scratch: array<f32, WG_SIZE * 2u>;
|
||||
|
||||
@compute @workgroup_size(WG_SIZE)
|
||||
fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
||||
@@ -65,34 +73,81 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
||||
if (col >= params.ne0) {
|
||||
break;
|
||||
}
|
||||
sum += pow(src[i_src_row + col], 2.0);
|
||||
let v = f32(src[i_src_row + col]);
|
||||
#ifdef NORM
|
||||
sum += v;
|
||||
#else
|
||||
sum += v * v;
|
||||
#endif
|
||||
col += WG_SIZE;
|
||||
}
|
||||
|
||||
scratch[lid.x] = sum;
|
||||
workgroupBarrier();
|
||||
var offset: u32 = WG_SIZE / 2;
|
||||
|
||||
var offset: u32 = WG_SIZE / 2u;
|
||||
while (offset > 0) {
|
||||
if (lid.x < offset) {
|
||||
scratch[lid.x] += scratch[lid.x + offset];
|
||||
}
|
||||
offset = offset / 2;
|
||||
offset /= 2u;
|
||||
workgroupBarrier();
|
||||
}
|
||||
sum = scratch[0];
|
||||
|
||||
#ifdef RMS_NORM
|
||||
#ifdef NORM
|
||||
let mean = sum / f32(params.ne0);
|
||||
var sq_sum = 0.0f;
|
||||
col = lid.x;
|
||||
for (var j: u32 = 0; j < elems; j++) {
|
||||
if (col >= params.ne0) {
|
||||
break;
|
||||
}
|
||||
let v = f32(src[i_src_row + col]);
|
||||
let d = v - mean;
|
||||
sq_sum += d * d;
|
||||
col += WG_SIZE;
|
||||
}
|
||||
|
||||
workgroupBarrier();
|
||||
scratch[lid.x] = sq_sum;
|
||||
workgroupBarrier();
|
||||
offset = WG_SIZE / 2u;
|
||||
while (offset > 0) {
|
||||
if (lid.x < offset) {
|
||||
scratch[lid.x] += scratch[lid.x + offset];
|
||||
}
|
||||
offset /= 2u;
|
||||
workgroupBarrier();
|
||||
}
|
||||
|
||||
let variance = scratch[0] / f32(params.ne0);
|
||||
let scale = 1.0 / sqrt(variance + params.eps);
|
||||
#elif defined(RMS_NORM)
|
||||
let scale = 1.0/sqrt(sum/f32(params.ne0) + params.eps);
|
||||
#elif defined(L2_NORM)
|
||||
let scale = 1.0/max(sqrt(sum), params.eps);
|
||||
#endif
|
||||
|
||||
#ifdef NORM
|
||||
let mean_val = mean;
|
||||
#else
|
||||
let mean_val = 0.0f;
|
||||
#endif
|
||||
|
||||
col = lid.x;
|
||||
for (var j: u32 = 0; j < elems; j++) {
|
||||
if (col >= params.ne0) {
|
||||
break;
|
||||
}
|
||||
update(i_src_row + col, i_dst_row + col, scale);
|
||||
let i_src = i_src_row + col;
|
||||
let i_dst = i_dst_row + col;
|
||||
let v = src[i_src];
|
||||
#ifdef INPLACE
|
||||
src[i_dst] = scale * (v - mean_val);
|
||||
#else
|
||||
dst[i_dst] = scale * (v - mean_val);
|
||||
#endif
|
||||
col += WG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user