oarust 0.8.6

GPU-first semantic computing engine written in Rust
// Per-row cross-entropy adapted from OA crossEntropy.slang.

import storage;
import attributes;

struct PushConstants {
	uint logits_index;
	uint targets_index;
	uint output_index;
	uint rows;
	uint classes;
	uint target_dtype;
};

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

groupshared float partial[256];
static const uint PORTABLE_DISPATCH_WIDTH = 65535u;

[kernel_name("cross_entropy")]
[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 + group_id.y * PORTABLE_DISPATCH_WIDTH;
	if (row >= push.rows) {
		return;
	}
	uint lane = group_thread_id.x;
	uint base = row * push.classes;

	float local_maximum = -3.402823466e+38f;
	for (uint column = lane; column < push.classes; column += 256u) {
		local_maximum = max(local_maximum, load_f32(storage_buffers[push.logits_index], base + column));
	}
	partial[lane] = local_maximum;
	GroupMemoryBarrierWithGroupSync();
	for (uint stride = 128u; stride > 0u; stride >>= 1u) {
		if (lane < stride) {
			partial[lane] = max(partial[lane], partial[lane + stride]);
		}
		GroupMemoryBarrierWithGroupSync();
	}
	float row_maximum = partial[0];
	GroupMemoryBarrierWithGroupSync();

	float local_sum = 0.0f;
	for (uint column = lane; column < push.classes; column += 256u) {
		local_sum += exp(load_f32(storage_buffers[push.logits_index], base + column) - row_maximum);
	}
	partial[lane] = local_sum;
	GroupMemoryBarrierWithGroupSync();
	for (uint stride = 128u; stride > 0u; stride >>= 1u) {
		if (lane < stride) {
			partial[lane] += partial[lane + stride];
		}
		GroupMemoryBarrierWithGroupSync();
	}

	if (lane == 0u) {
		uint target = storage_buffers[push.targets_index].Load(row * 4u);
		float loss = 0.0f / 0.0f;
		if (push.target_dtype == 1u && target < push.classes) {
			loss = log(partial[0]) + row_maximum
				- load_f32(storage_buffers[push.logits_index], base + target);
		}
		store_f32(storage_buffers[push.output_index], row, loss);
	}
}