char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
b22da2588
char/aliceai-t5-moe
1#ifdef DST_Q8_0 2#define BLOCK_SIZE 32u 3#define BLOCK_BYTES 34u 4#define QS_WORDS 8u 5#elif defined(DST_Q4_0) 6#define BLOCK_SIZE 32u 7#define BLOCK_BYTES 18u 8#define QS_WORDS 4u 9#endif 10 11@group(0) @binding(0) 12var<storage, read_write> src: array<f32>; 13 14@group(0) @binding(1) 15var<storage, read_write> idx: array<u32>; 16 17@group(0) @binding(2) 18#ifdef PAIR_BLOCKS 19var<storage, read_write> dst: array<u32>; 20#else 21var<storage, read_write> dst: array<atomic<u32>>; 22#endif 23 24#ifdef I64_IDX 25@group(0) @binding(3) 26var<storage, read_write> error: atomic<u32>; 27#define PARAMS_BINDING 4 28#else 29#define PARAMS_BINDING 3 30#endif 31 32struct Params { 33 offset_src: u32, // in elements 34 offset_idx: u32, // in elements 35 offset_dst: u32, // in blocks 36 37 // Strides (in elements / blocks) 38 stride_src1: u32, 39 stride_src2: u32, 40 stride_src3: u32, 41 42 stride_idx0: u32, 43 stride_idx1: u32, 44 stride_idx2: u32, 45 46 stride_dst1: u32, 47 stride_dst2: u32, 48 stride_dst3: u32, 49 50 // Shape of src 51 ne0: u32, 52 n_rows: u32, 53 ne2: u32, 54 ne3: u32, 55 56 // Shape of idx 57 idx1: u32, 58 idx2: u32, 59}; 60 61@group(0) @binding(PARAMS_BINDING) 62var<uniform> params: Params; 63 64// if the quantization type is unaligned and there are an odd number of blocks per row, we need to store atomically 65#ifndef PAIR_BLOCKS 66fn merge_store_dst_word(word_idx: u32, mask: u32, bits: u32) { 67 loop { 68 let old = atomicLoad(&dst[word_idx]); 69 let merged = (old & ~mask) | (bits & mask); 70 let result = atomicCompareExchangeWeak(&dst[word_idx], old, merged); 71 if (result.exchanged) { 72 return; 73 } 74 } 75} 76#else 77fn merge_store_dst_word(word_idx: u32, mask: u32, bits: u32) { 78 let old = dst[word_idx]; 79 dst[word_idx] = (old & ~mask) | (bits & mask); 80} 81#endif 82 83fn store_u16(dst_word_idx: u32, block_byte_offset: u32, byte_offset: u32, value: u32) { 84 let total_byte_offset = block_byte_offset + byte_offset; 85 let word_idx = dst_word_idx + total_byte_offset / 4u; 86 let shift = (total_byte_offset & 2u) * 8u; 87 let mask = 0xFFFFu << shift; 88 merge_store_dst_word(word_idx, mask, (value & 0xFFFFu) << shift); 89} 90 91fn store_u32(dst_word_idx: u32, block_byte_offset: u32, byte_offset: u32, value: u32) { 92 let total_byte_offset = block_byte_offset + byte_offset; 93 let word_idx = dst_word_idx + total_byte_offset / 4u; 94 let shift = (total_byte_offset & 3u) * 8u; 95 96 if (shift == 0u) { 97#ifdef PAIR_BLOCKS 98 dst[word_idx] = value; 99#else 100 atomicStore(&dst[word_idx], value); 101#endif 102 return; 103 } 104 105 let lo_mask = 0xFFFFFFFFu << shift; 106 let hi_mask = (1u << shift) - 1u; 107 merge_store_dst_word(word_idx, lo_mask, value << shift); 108 merge_store_dst_word(word_idx + 1u, hi_mask, value >> (32u - shift)); 109} 110 111fn quantize_block_params(src_block: u32) -> vec2<f32> { 112#ifdef DST_Q8_0 113 var amax = 0.0; 114 for (var j: u32 = 0u; j < BLOCK_SIZE; j++) { 115 amax = max(amax, abs(src[src_block + j])); 116 } 117 118 let d = amax / 127.0; 119 let id = select(0.0, 1.0 / d, d > 0.0); 120 return vec2(d, id); 121#elif defined(DST_Q4_0) 122 var amax = 0.0; 123 var max_val = 0.0; 124 for (var j: u32 = 0u; j < BLOCK_SIZE; j++) { 125 let v = src[src_block + j]; 126 let av = abs(v); 127 if (amax < av) { 128 amax = av; 129 max_val = v; 130 } 131 } 132 133 let d = max_val / -8.0; 134 let id = select(0.0, 1.0 / d, d != 0.0); 135 return vec2(d, id); 136#endif 137} 138 139fn quantize_block_word(src_block: u32, j: u32, id: f32) -> u32 { 140#ifdef DST_Q8_0 141 let base = src_block + j * 4u; 142 return (u32(i32(round(src[base + 0u] * id)) & 0xFF) << 0u) | 143 (u32(i32(round(src[base + 1u] * id)) & 0xFF) << 8u) | 144 (u32(i32(round(src[base + 2u] * id)) & 0xFF) << 16u) | 145 (u32(i32(round(src[base + 3u] * id)) & 0xFF) << 24u); 146#elif defined(DST_Q4_0) 147 var packed_q = 0u; 148 for (var k: u32 = 0u; k < 4u; k++) { 149 let x0 = src[src_block + j * 4u + k] * id; 150 let x1 = src[src_block + 16u + j * 4u + k] * id; 151 let q0 = u32(clamp(i32(x0 + 8.5), 0, 15)); 152 let q1 = u32(clamp(i32(x1 + 8.5), 0, 15)); 153 packed_q |= (q0 & 0xFu) << (8u * k); 154 packed_q |= (q1 & 0xFu) << (8u * k + 4u); 155 } 156 return packed_q; 157#endif 158} 159 160fn quantize_block(src_block: u32, dst_word_idx: u32, block_byte_offset: u32) { 161 let params = quantize_block_params(src_block); 162 let d = params.x; 163 let id = params.y; 164 let packed_d = pack2x16float(vec2(d, 0.0)) & 0xFFFFu; 165 store_u16(dst_word_idx, block_byte_offset, 0u, packed_d); 166 167 for (var j: u32 = 0u; j < QS_WORDS; j++) { 168 store_u32(dst_word_idx, block_byte_offset, 2u + j * 4u, quantize_block_word(src_block, j, id)); 169 } 170} 171 172@compute @workgroup_size(WG_SIZE) 173fn main(@builtin(global_invocation_id) gid: vec3<u32>) { 174 let blocks_per_row = params.ne0 / BLOCK_SIZE; 175#ifdef PAIR_BLOCKS 176 let blocks_per_invocation = 2u; 177#else 178 let blocks_per_invocation = 1u; 179#endif 180 let invocations_per_row = blocks_per_row / blocks_per_invocation; 181 let total_invocations = params.ne3 * params.ne2 * params.n_rows * invocations_per_row; 182 if (gid.x >= total_invocations) { 183 return; 184 } 185 186 var i = gid.x / invocations_per_row; 187 let block_in_row = (gid.x % invocations_per_row) * blocks_per_invocation; 188 189 let i_src3 = i / (params.ne2 * params.n_rows); 190 i = i % (params.ne2 * params.n_rows); 191 let i_src2 = i / params.n_rows; 192 let i_src1 = i % params.n_rows; 193 194 let i_idx2 = i_src3 % params.idx2; 195 let i_idx1 = i_src2 % params.idx1; 196 let i_idx0 = i_src1; 197 198#ifdef I64_IDX 199 let idx_high = (params.offset_idx + i_idx0 * params.stride_idx0 + i_idx1 * params.stride_idx1 + i_idx2 * params.stride_idx2) * 2u; 200 let idx_val = idx[idx_high]; 201 let idx_low_val = idx[idx_high + 1u]; 202 203 if (idx_low_val != 0u) { 204 atomicStore(&error, 1u); 205 return; 206 } 207#else 208 let idx_i = params.offset_idx + i_idx0 * params.stride_idx0 + i_idx1 * params.stride_idx1 + i_idx2 * params.stride_idx2; 209 let idx_val = idx[idx_i]; 210#endif 211 212 let dst_row_blocks = params.offset_dst + idx_val * params.stride_dst1 + i_src2 * params.stride_dst2 + i_src3 * params.stride_dst3; 213 let src_row = params.offset_src + i_src1 * params.stride_src1 + i_src2 * params.stride_src2 + i_src3 * params.stride_src3; 214 let src_block = src_row + block_in_row * BLOCK_SIZE; 215 let dst_block_byte = (dst_row_blocks + block_in_row) * BLOCK_BYTES; 216 217 let dst_word_idx = dst_block_byte / 4u; 218#ifdef PAIR_BLOCKS 219 quantize_block(src_block, dst_word_idx, 0u); 220 quantize_block(src_block + BLOCK_SIZE, dst_word_idx, BLOCK_BYTES); 221#else 222 quantize_block(src_block, dst_word_idx, dst_block_byte & 3u); 223#endif 224}