ggml-webgpu: FlashAttention refactor + standardize quantization support (#23834)
* Start work on flash_attn refactor * Refactor * Split k/v quantization * Refactor and abstract quantization logic for flash_attn and mul_mat * Add quantization support to tile path * formatting * Move to functions, add a check
This commit is contained in:
@@ -1,16 +1,29 @@
|
||||
enable f16;
|
||||
enable subgroups;
|
||||
|
||||
#define BYTE_HELPERS
|
||||
#include "common_decls.tmpl"
|
||||
|
||||
#ifdef Q_F16
|
||||
#define Q_TYPE f16
|
||||
#else
|
||||
#define Q_TYPE f32
|
||||
#endif
|
||||
|
||||
#ifdef KV_F32
|
||||
#define KV_TYPE f32
|
||||
#ifdef K_F32
|
||||
#define K_TYPE f32
|
||||
#elif defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_TYPE u32
|
||||
#else
|
||||
#define KV_TYPE f16
|
||||
#define K_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef V_F32
|
||||
#define V_TYPE f32
|
||||
#elif defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_TYPE u32
|
||||
#else
|
||||
#define V_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef DST_F16
|
||||
@@ -21,7 +34,6 @@ enable subgroups;
|
||||
|
||||
#define HEAD_DIM_QK 64
|
||||
#define HEAD_DIM_V 64
|
||||
#define KV_STAGE_STRIDE 64
|
||||
#define Q_TILE 4
|
||||
#define KV_TILE 64
|
||||
#define WG_SIZE 128
|
||||
@@ -64,11 +76,23 @@ struct Params {
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> Q: array<Q_TYPE>;
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<KV_TYPE>>;
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#define V K
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<KV_TYPE>>;
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<vec4<KV_TYPE>>;
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#if defined(V_Q4_0) || defined(V_Q8_0)
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<V_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<vec4<V_TYPE>>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MASK) && defined(SINKS)
|
||||
@@ -121,10 +145,50 @@ const Q_CHUNKS: u32 = HEAD_DIM_QK / 4u;
|
||||
const V_CHUNKS: u32 = HEAD_DIM_V / 4u;
|
||||
const SCORE_REGS_PER_LANE: u32 = (KV_TILE + MIN_SUBGROUP_SIZE - 1u) / MIN_SUBGROUP_SIZE;
|
||||
const OUT_REGS_PER_LANE: u32 = (V_CHUNKS + MIN_SUBGROUP_SIZE - 1u) / MIN_SUBGROUP_SIZE;
|
||||
const kv_shmem_size = KV_TILE * max(HEAD_DIM_QK, HEAD_DIM_V);
|
||||
|
||||
var<workgroup> q_shmem: array<Q_TYPE, Q_TILE * HEAD_DIM_QK>;
|
||||
var<workgroup> kv_shmem: array<KV_TYPE, KV_TILE * KV_STAGE_STRIDE>;
|
||||
var<workgroup> p_shmem: array<KV_TYPE, Q_TILE * KV_TILE>;
|
||||
var<workgroup> kv_shmem: array<f16, kv_shmem_size>;
|
||||
var<workgroup> p_shmem: array<f16, Q_TILE * KV_TILE>;
|
||||
|
||||
#define QUANT_SHMEM kv_shmem
|
||||
#define QUANT_OUT_TYPE f16
|
||||
#include "quant_inner_loops.tmpl"
|
||||
#include "flash_attn_quant_staging.tmpl"
|
||||
|
||||
#if !defined(K_Q4_0) && !defined(K_Q8_0)
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * Q_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / Q_CHUNKS;
|
||||
let chunk = vec_idx_local % Q_CHUNKS;
|
||||
let global_k_row = kv_tile + kv_local;
|
||||
let k_vec_index = (k_head_offset + global_k_row * params.stride_k1 + chunk * 4u) >> 2u;
|
||||
let k4 = K[k_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_QK + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = f16(k4.x);
|
||||
kv_shmem[kv_off + 1u] = f16(k4.y);
|
||||
kv_shmem[kv_off + 2u] = f16(k4.z);
|
||||
kv_shmem[kv_off + 3u] = f16(k4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(V_Q4_0) && !defined(V_Q8_0)
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * V_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / V_CHUNKS;
|
||||
let chunk = vec_idx_local % V_CHUNKS;
|
||||
let global_v_row = kv_tile + kv_local;
|
||||
let v_vec_index = (v_head_offset + global_v_row * params.stride_v1 + chunk * 4u) >> 2u;
|
||||
let v4 = V[v_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_V + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = f16(v4.x);
|
||||
kv_shmem[kv_off + 1u] = f16(v4.y);
|
||||
kv_shmem[kv_off + 2u] = f16(v4.z);
|
||||
kv_shmem[kv_off + 3u] = f16(v4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@compute @workgroup_size(WG_SIZE)
|
||||
fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
@@ -206,18 +270,9 @@ fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
local_scores[slot] = FLOAT_MIN;
|
||||
}
|
||||
|
||||
for (var vec_idx_local = local_id.x; vec_idx_local < kv_count * Q_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / Q_CHUNKS;
|
||||
let chunk = vec_idx_local % Q_CHUNKS;
|
||||
let global_k_row = kv_tile + kv_local;
|
||||
let k_vec_index = (k_head_offset + global_k_row * params.stride_k1 + chunk * 4u) >> 2u;
|
||||
let k4 = K[k_vec_index];
|
||||
let kv_off = kv_local * KV_STAGE_STRIDE + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = KV_TYPE(k4.x);
|
||||
kv_shmem[kv_off + 1u] = KV_TYPE(k4.y);
|
||||
kv_shmem[kv_off + 2u] = KV_TYPE(k4.z);
|
||||
kv_shmem[kv_off + 3u] = KV_TYPE(k4.w);
|
||||
}
|
||||
#ifndef KV_DIRECT
|
||||
load_k_tile_block(local_id.x, kv_count, kv_tile, k_head_offset);
|
||||
#endif
|
||||
|
||||
workgroupBarrier();
|
||||
|
||||
@@ -238,8 +293,8 @@ fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
q_shmem[q_off + 1u],
|
||||
q_shmem[q_off + 2u],
|
||||
q_shmem[q_off + 3u]);
|
||||
let kv_off = kv_local * KV_STAGE_STRIDE + chunk * 4u;
|
||||
let kv = vec4<KV_TYPE>(
|
||||
let kv_off = kv_local * HEAD_DIM_QK + chunk * 4u;
|
||||
let kv = vec4<f16>(
|
||||
kv_shmem[kv_off + 0u],
|
||||
kv_shmem[kv_off + 1u],
|
||||
kv_shmem[kv_off + 2u],
|
||||
@@ -271,25 +326,16 @@ fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
let kv_local = sg_inv_id + slot * subgroup_size;
|
||||
if (row_active && kv_local < kv_count) {
|
||||
let p = exp(local_scores[slot] - new_max);
|
||||
p_shmem[subgroup_p_offset + kv_local] = KV_TYPE(p);
|
||||
p_shmem[subgroup_p_offset + kv_local] = f16(p);
|
||||
local_sum += p;
|
||||
}
|
||||
}
|
||||
|
||||
workgroupBarrier();
|
||||
|
||||
for (var vec_idx_local = local_id.x; vec_idx_local < kv_count * V_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / V_CHUNKS;
|
||||
let chunk = vec_idx_local % V_CHUNKS;
|
||||
let global_v_row = kv_tile + kv_local;
|
||||
let v_vec_index = (v_head_offset + global_v_row * params.stride_v1 + chunk * 4u) >> 2u;
|
||||
let v4 = V[v_vec_index];
|
||||
let kv_off = kv_local * KV_STAGE_STRIDE + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = KV_TYPE(v4.x);
|
||||
kv_shmem[kv_off + 1u] = KV_TYPE(v4.y);
|
||||
kv_shmem[kv_off + 2u] = KV_TYPE(v4.z);
|
||||
kv_shmem[kv_off + 3u] = KV_TYPE(v4.w);
|
||||
}
|
||||
#ifndef KV_DIRECT
|
||||
load_v_tile_block(local_id.x, kv_count, kv_tile, v_head_offset);
|
||||
#endif
|
||||
|
||||
workgroupBarrier();
|
||||
|
||||
@@ -306,14 +352,14 @@ fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
|
||||
var acc = out_regs[reg_idx];
|
||||
for (var kv_local = 0u; kv_local < kv_count; kv_local += 1u) {
|
||||
let p = p_shmem[subgroup_p_offset + kv_local];
|
||||
let kv_off = kv_local * KV_STAGE_STRIDE + chunk * 4u;
|
||||
let v4 = vec4<KV_TYPE>(
|
||||
let p = f32(p_shmem[subgroup_p_offset + kv_local]);
|
||||
let kv_off = kv_local * HEAD_DIM_V + chunk * 4u;
|
||||
let v4 = vec4<f16>(
|
||||
kv_shmem[kv_off + 0u],
|
||||
kv_shmem[kv_off + 1u],
|
||||
kv_shmem[kv_off + 2u],
|
||||
kv_shmem[kv_off + 3u]);
|
||||
acc += f32(p) * vec4<f32>(v4);
|
||||
acc += p * vec4<f32>(v4);
|
||||
}
|
||||
out_regs[reg_idx] = acc;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user