oarust 0.8.6

GPU-first semantic computing engine written in Rust
import attributes;
import storage;

struct PushConstants {
	uint latent_index;
	uint indices_index;
	uint embed_sum_input_index;
	uint cluster_size_input_index;
	uint codebook_input_index;
	uint embed_sum_output_index;
	uint cluster_size_output_index;
	uint codebook_output_index;
	uint rows;
	uint code_dim;
	uint num_codes;
	float decay;
	float epsilon;
	float dead_threshold;
	uint seed;
	uint normalize;
};

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

[kernel_name("vq_ema_update")]
[domain("ml")]
[variant("functional_state")]
[dtype("f32")]
[status("experimental")]
[shader("compute")]
[numthreads(256, 1, 1)]
void main(uint3 dispatch_thread_id : SV_DispatchThreadID) {
	uint code = dispatch_thread_id.x;
	if (code >= push.num_codes) {
		return;
	}
	uint count = 0;
	for (uint row = 0; row < push.rows; ++row) {
		if (load_i32(storage_buffers[push.indices_index], row) == int(code)) {
			++count;
		}
	}
	float cluster_size = push.decay
		* load_f32(storage_buffers[push.cluster_size_input_index], code)
		+ (1.0 - push.decay) * float(count);
	uint code_base = code * push.code_dim;
	float sum_of_squares = 0.0;
	for (uint column = 0; column < push.code_dim; ++column) {
		float sum = 0.0;
		for (uint row = 0; row < push.rows; ++row) {
			if (load_i32(storage_buffers[push.indices_index], row) == int(code)) {
				sum += load_f32(storage_buffers[push.latent_index], row * push.code_dim + column);
			}
		}
		float embed_sum = push.decay
			* load_f32(storage_buffers[push.embed_sum_input_index], code_base + column)
			+ (1.0 - push.decay) * sum;
		store_f32(storage_buffers[push.embed_sum_output_index], code_base + column, embed_sum);
		float value = embed_sum / max(cluster_size, push.epsilon);
		store_f32(storage_buffers[push.codebook_output_index], code_base + column, value);
		sum_of_squares += value * value;
	}
	store_f32(storage_buffers[push.cluster_size_output_index], code, cluster_size);
	if (push.normalize != 0) {
		float rms = sqrt(sum_of_squares / float(push.code_dim));
		if (rms > push.epsilon) {
			for (uint column = 0; column < push.code_dim; ++column) {
				uint index = code_base + column;
				store_f32(
					storage_buffers[push.codebook_output_index], index,
					load_f32(storage_buffers[push.codebook_output_index], index) / rms);
			}
		}
	}
	if (cluster_size < push.dead_threshold) {
		uint hash = ((code + 1u) * 2654435761u) ^ (push.seed * 2246822519u) ^ (push.seed >> 15u);
		hash ^= hash >> 13u;
		hash *= 3266489917u;
		hash ^= hash >> 16;
		uint revival_row = hash % push.rows;
		for (uint column = 0; column < push.code_dim; ++column) {
			float value = load_f32(
				storage_buffers[push.latent_index], revival_row * push.code_dim + column);
			store_f32(storage_buffers[push.codebook_output_index], code_base + column, value);
			store_f32(storage_buffers[push.embed_sum_output_index], code_base + column, value);
		}
		store_f32(storage_buffers[push.cluster_size_output_index], code, 1.0);
	}
}