oarust 0.8.6

GPU-first semantic computing engine written in Rust
// FP32 LayerNorm forward over the last dimension. One workgroup owns one row.

import storage;
import attributes;

struct PushConstants {
	uint input_index;
	uint weight_index;
	uint bias_index;
	uint output_index;
	uint normalized_index;
	uint inverse_stddev_index;
	uint rows;
	uint columns;
	float epsilon;
};

[[vk::push_constant]] PushConstants push;
[[vk::binding(0, 0)]] RWByteAddressBuffer storage_buffers[];

groupshared float partial_sum[256];
groupshared float partial_square_sum[256];

[kernel_name("layer_norm")]
[domain("ml")]
[variant("generic")]
[dtype("f32")]
[status("experimental")]
[shader("compute")]
[numthreads(256, 1, 1)]
void main(uint3 group_id : SV_GroupID, uint3 group_thread_id : SV_GroupThreadID) {
	uint row = group_id.x;
	uint lane = group_thread_id.x;
	if (row >= push.rows) {
		return;
	}

	float sum = 0.0f;
	uint row_offset = row * push.columns;
	for (uint column = lane; column < push.columns; column += 256u) {
		float value = load_f32(storage_buffers[push.input_index], row_offset + column);
		sum += value;
	}
	partial_sum[lane] = sum;
	GroupMemoryBarrierWithGroupSync();

	for (uint stride = 128u; stride > 0u; stride >>= 1u) {
		if (lane < stride) {
			partial_sum[lane] += partial_sum[lane + stride];
		}
		GroupMemoryBarrierWithGroupSync();
	}

	float mean = partial_sum[0] / float(push.columns);
	float square_sum = 0.0f;
	for (uint column = lane; column < push.columns; column += 256u) {
		float centered = load_f32(storage_buffers[push.input_index], row_offset + column) - mean;
		square_sum += centered * centered;
	}
	partial_square_sum[lane] = square_sum;
	GroupMemoryBarrierWithGroupSync();
	for (uint stride = 128u; stride > 0u; stride >>= 1u) {
		if (lane < stride) {
			partial_square_sum[lane] += partial_square_sum[lane + stride];
		}
		GroupMemoryBarrierWithGroupSync();
	}
	float variance = partial_square_sum[0] / float(push.columns);
	float inverse_stddev = rsqrt(variance + push.epsilon);
	if (lane == 0u) {
		store_f32(storage_buffers[push.inverse_stddev_index], row, inverse_stddev);
	}
	for (uint column = lane; column < push.columns; column += 256u) {
		float value = load_f32(storage_buffers[push.input_index], row_offset + column);
		float weight = load_f32(storage_buffers[push.weight_index], column);
		float bias = load_f32(storage_buffers[push.bias_index], column);
		float normalized = (value - mean) * inverse_stddev;
		store_f32(storage_buffers[push.normalized_index], row_offset + column, normalized);
		store_f32(
			storage_buffers[push.output_index],
			row_offset + column,
			normalized * weight + bias
		);
	}
}