char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
a7a6d0d26
char/aliceai-t5-moe
1#version 450 2 3#extension GL_EXT_control_flow_attributes : require 4#extension GL_KHR_shader_subgroup_basic : enable 5#extension GL_KHR_shader_subgroup_arithmetic : enable 6#extension GL_KHR_shader_subgroup_shuffle : enable 7 8#include "types.glsl" 9 10#define GATING_FUNC_SOFTMAX 0 11#define GATING_FUNC_SIGMOID 1 12#define GATING_FUNC_SOFTMAX_WEIGHT 2 13#define GATING_FUNC_SQRT_SOFTPLUS 3 14 15layout (push_constant) uniform parameter 16{ 17 uint n_rows; 18 uint n_experts_push; 19 uint n_expert_used; 20 float clamp_min; 21 float clamp_max; 22 uint gating_func; 23 uint has_bias; 24 uint with_norm; 25 float output_scale; 26 float output_bias; 27}; 28 29layout(local_size_x_id = 0, local_size_y = 4, local_size_z = 1) in; 30 31layout(constant_id = 0) const uint WARP_SIZE = 32; 32layout(constant_id = 1) const uint n_experts_spec = 512; 33layout(constant_id = 2) const bool nexperts_use_push = false; 34 35uint n_experts = nexperts_use_push ? n_experts_push : n_experts_spec; 36 37#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b)) 38 39const uint experts_per_thread = CEIL_DIV(n_experts_spec, WARP_SIZE); 40 41layout (binding = 0, std430) readonly buffer Logits {float logits[];}; 42layout (binding = 1, std430) readonly buffer BiasProbs {float bias[];}; 43layout (binding = 2, std430) writeonly buffer Weights {float weights[];}; 44layout (binding = 3, std430) writeonly buffer Ids {uint ids[];}; 45 46const float INFINITY = 1.0 / 0.0; 47 48// Warp-local softmax used for both the pre-top-k logits and the post-top-k delayed path. 49void softmax_warp_inplace(inout float vals[experts_per_thread], const uint limit, const uint lane, const bool use_limit) { 50 float max_val = -INFINITY; 51 52 [[unroll]] 53 for (int i = 0; i < experts_per_thread; i++) { 54 const uint idx = lane + i * WARP_SIZE; 55 const bool is_active = !use_limit || (idx < limit); 56 if (is_active) { 57 max_val = max(max_val, vals[i]); 58 } 59 } 60 61 max_val = subgroupMax(max_val); 62 63 float sum = 0.f; 64 65 [[unroll]] 66 for (int i = 0; i < experts_per_thread; i++) { 67 const uint idx = lane + i * WARP_SIZE; 68 const bool is_active = !use_limit || (idx < limit); 69 if (is_active) { 70 const float val = exp(vals[i] - max_val); 71 vals[i] = val; 72 sum += val; 73 } else { 74 vals[i] = 0.f; 75 } 76 } 77 78 sum = subgroupAdd(sum); 79 80 const float inv_sum = 1.0f / sum; 81 82 [[unroll]] 83 for (int i = 0; i < experts_per_thread; i++) { 84 const uint idx = lane + i * WARP_SIZE; 85 const bool is_active = !use_limit || (idx < limit); 86 if (is_active) { 87 vals[i] *= inv_sum; 88 } 89 } 90} 91 92void main() { 93 const uint row = gl_WorkGroupID.x * gl_WorkGroupSize.y + gl_SubgroupID; 94 if (row >= n_rows) { 95 return; 96 } 97 98 const uint logits_offset = n_experts * row; 99 const uint bias_offset = 0; // 1D 100 const uint weights_offset = n_expert_used * row; 101 const uint ids_offset = n_experts * row; 102 const uint lane = gl_SubgroupInvocationID; 103 104 float probs[experts_per_thread]; 105 [[unroll]] 106 for (int i = 0; i < experts_per_thread; i++) { 107 probs[i] = -INFINITY; 108 } 109 110 [[unroll]] 111 for (uint i = 0; i < n_experts; i += WARP_SIZE) { 112 const uint expert = i + lane; 113 probs[i / WARP_SIZE] = (n_experts % WARP_SIZE == 0 || expert < n_experts) ? logits[logits_offset + expert] : -INFINITY; 114 } 115 116 if (gating_func == GATING_FUNC_SOFTMAX) { 117 softmax_warp_inplace(probs, n_experts, lane, nexperts_use_push); 118 } else if (gating_func == GATING_FUNC_SIGMOID) { 119 [[unroll]] 120 for (uint i = 0; i < n_experts; i += WARP_SIZE) { 121 const uint expert = i + lane; 122 probs[i / WARP_SIZE] = (n_experts % WARP_SIZE == 0 || expert < n_experts) ? 1.f / (1.f + exp(-probs[i / WARP_SIZE])) : -INFINITY; 123 } 124 } else if (gating_func == GATING_FUNC_SQRT_SOFTPLUS) { 125 [[unroll]] 126 for (uint i = 0; i < n_experts; i += WARP_SIZE) { 127 const uint expert = i + lane; 128 const float val = probs[i / WARP_SIZE]; 129 probs[i / WARP_SIZE] = (n_experts % WARP_SIZE == 0 || expert < n_experts) ? sqrt(val > 20.0f ? val : log(1.0f + exp(val))) : -INFINITY; 130 } 131 } 132 133 float selection_probs[experts_per_thread]; 134 if (has_bias != 0) { 135 [[unroll]] 136 for (uint i = 0; i < n_experts; i += WARP_SIZE) { 137 const uint expert = i + lane; 138 selection_probs[i / WARP_SIZE] = (n_experts % WARP_SIZE == 0 || expert < n_experts) ? probs[i / WARP_SIZE] + bias[bias_offset + expert] : -INFINITY; 139 } 140 } else { 141 [[unroll]] 142 for (int i = 0; i < experts_per_thread; i++) { 143 selection_probs[i] = probs[i]; 144 } 145 } 146 147 // at this point, each thread holds a portion of softmax, 148 // we do the argmax reduce over n_expert_used, each time marking 149 // the expert weight as -inf to exclude from the next iteration 150 151 float wt_sum = 0.f; 152 153 float output_weights[experts_per_thread]; 154 155 [[unroll]] 156 for (int i = 0; i < experts_per_thread; i++) { 157 output_weights[i] = 0.f; 158 } 159 160 for (int k = 0; k < n_expert_used; k++) { 161 float max_val = probs[0]; 162 float max_val_s = selection_probs[0]; 163 uint max_expert = lane; 164 165 [[unroll]] 166 for (uint i = WARP_SIZE; i < n_experts; i += WARP_SIZE) { 167 const uint expert = i + lane; 168 if ((n_experts % WARP_SIZE == 0 || expert < n_experts) && selection_probs[i / WARP_SIZE] > max_val_s) { 169 max_val = probs[i / WARP_SIZE]; 170 max_val_s = selection_probs[i / WARP_SIZE]; 171 max_expert = expert; 172 } 173 } 174 175 [[unroll]] 176 for (uint mask = WARP_SIZE / 2; mask > 0; mask /= 2) { 177 const float val = subgroupShuffleXor(max_val, mask); 178 const float val_s = subgroupShuffleXor(max_val_s, mask); 179 const uint expert = subgroupShuffleXor(max_expert, mask); 180 if (val_s > max_val_s || (val_s == max_val_s && expert < max_expert)) { 181 max_val = val; 182 max_val_s = val_s; 183 max_expert = expert; 184 } 185 } 186 187 if ((k & (WARP_SIZE - 1)) == lane) { 188 output_weights[k / WARP_SIZE] = max_val; 189 } 190 191 if ((max_expert & (WARP_SIZE - 1)) == lane) { 192 selection_probs[max_expert / WARP_SIZE] = -INFINITY; 193 194 ids[ids_offset + k] = max_expert; 195 wt_sum += max_val; 196 } 197 } 198 199 if (with_norm != 0) { 200 wt_sum = subgroupAdd(wt_sum); 201 wt_sum = clamp(wt_sum, clamp_min, clamp_max); 202 const float inv_sum = 1.0f / wt_sum; 203 204 [[unroll]] 205 for (uint i = 0; i < experts_per_thread; ++i) { 206 output_weights[i] *= inv_sum; 207 } 208 } 209 210 if (gating_func == GATING_FUNC_SOFTMAX_WEIGHT) { 211 softmax_warp_inplace(output_weights, n_expert_used, lane, true); 212 } 213 214 [[unroll]] 215 for (uint i = 0; i < experts_per_thread; ++i) { 216 uint idx = i * WARP_SIZE + lane; 217 if (idx < n_expert_used) { 218 weights[weights_offset + idx] = output_scale * output_weights[i] + output_bias; 219 } 220 } 221}