wgml 0.2.0

Cross-platform GPU LLM inference.
Documentation
#import wgblas::shape as Shape;

@group(0) @binding(0)
var<uniform> in_shape: Shape::Shape;
@group(0) @binding(1)
var<uniform> out_shape: Shape::Shape;
@group(0) @binding(2)
var<storage, read_write> in_vec: array<f32>;
@group(0) @binding(3)
var<storage, read_write> out_vec: array<f32>;

const WORKGROUP_SIZE: u32 = 128;
const NUDGE_FACTOR: f32 = 1.0e-5;

var<workgroup> workspace: array<f32, WORKGROUP_SIZE>;
var<workgroup> the_mean: f32;
var<workgroup> scale: f32;

fn reduce_sum(thread_id: u32, stride: u32) {
    workgroupBarrier();

    if thread_id < stride {
        workspace[thread_id] += workspace[thread_id + stride];
    }
}

@compute @workgroup_size(WORKGROUP_SIZE, 1, 1)
fn main(@builtin(global_invocation_id) invocation_id: vec3<u32>) {
    let thread_id = invocation_id.x;

    // Compute the MEAN
    let data_len = in_shape.nrows;
    workspace[thread_id] = 0.0;
    for (var i = thread_id; i < data_len; i += WORKGROUP_SIZE) {
        let val_i = in_vec[Shape::iv(in_shape, i)];
        workspace[thread_id] += val_i;
    }

    reduce_sum(thread_id, 64u);
    reduce_sum(thread_id, 32u);
    reduce_sum(thread_id, 16u);
    reduce_sum(thread_id, 8u);
    reduce_sum(thread_id, 4u);
    reduce_sum(thread_id, 2u);
    reduce_sum(thread_id, 1u);

    if (thread_id == 0) {
        the_mean = workspace[0] / f32(data_len);
    }

    workgroupBarrier();

    // Compute the SQUARED NORM
    workspace[thread_id] = 0.0;
    for (var i = thread_id; i < data_len; i += WORKGROUP_SIZE) {
        let val_i = in_vec[Shape::iv(in_shape, i)] - the_mean;
        workspace[thread_id] += val_i * val_i;
    }

    reduce_sum(thread_id, 64u);
    reduce_sum(thread_id, 32u);
    reduce_sum(thread_id, 16u);
    reduce_sum(thread_id, 8u);
    reduce_sum(thread_id, 4u);
    reduce_sum(thread_id, 2u);
    reduce_sum(thread_id, 1u);

    if (thread_id == 0) {
        let variance = workspace[0] / f32(data_len);
        scale = 1.0 / sqrt(variance + NUDGE_FACTOR);
    }

    workgroupBarrier();

    // Apply the scale.
    for (var i = thread_id; i < data_len; i += WORKGROUP_SIZE) {
        let ii = Shape::iv(in_shape, i);
        let iout = Shape::iv(out_shape, i);
        out_vec[iout] = (in_vec[ii] - the_mean) * scale;
    }
}