Files
2026-07-13 13:33:03 +08:00

146 lines
4.3 KiB
Plaintext

layout(set=0, binding=0) writeonly buffer s0 {
FLOAT data[];
} uOutput;
layout(set=0, binding=1) readonly buffer s1 {
FLOAT data[];
} uQuery;
layout(set=0, binding=2) readonly buffer s2 {
FLOAT data[];
} uKey;
layout(set=0, binding=3) readonly buffer s3 {
FLOAT data[];
} uValue;
layout(set=0, binding=4) readonly buffer s4 {
FLOAT data[];
} uCacheKey;
layout(set=0, binding=5) readonly buffer s5 {
FLOAT data[];
} uCacheValue;
layout(set=0, binding=6) readonly buffer s6 {
FLOAT data[];
} uMask;
layout(set=0, binding=7) readonly uniform constBuffer {
ivec4 s0; // qLen, kLen, headNum, kvHeadNum
ivec4 s1; // headDim, group, pastLen, totalLen
ivec4 s2; // maskQlen, maskKvlen, maskMode, cacheMaxLen
vec4 f0; // scale, 0, 0, 0
} uConst;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
const int MAX_D4 = 64; // headDim <= 256
const float NEG_INF = -3.402823466e38;
void main() {
const int h = int(gl_GlobalInvocationID.x);
const int q = int(gl_GlobalInvocationID.y);
const int qLen = uConst.s0.x;
const int kLen = uConst.s0.y;
const int headNum = uConst.s0.z;
const int kvHeadNum = uConst.s0.w;
if (h >= headNum || q >= qLen) {
return;
}
const int headDim = uConst.s1.x;
const int group = uConst.s1.y;
const int pastLen = uConst.s1.z;
const int totalLen = uConst.s1.w;
const int maskMode = uConst.s2.z;
const int maskQlen = uConst.s2.x;
const int maskKvlen = uConst.s2.y;
const float scale = uConst.f0.x;
const int kvh = h / group;
if (kvh >= kvHeadNum) {
return;
}
const int d4Size = headDim / 4;
if (d4Size > MAX_D4) {
return;
}
// query: [1, qLen, headNum, headDim]
const int qBase = (q * headNum + h) * headDim;
vec4 outVec[MAX_D4];
for (int i = 0; i < d4Size; ++i) {
outVec[i] = vec4(0.0);
}
float m = -3.402823466e38;
float s = 0.0;
const int kStart = (maskMode == 1 && maskKvlen > 0 && totalLen > maskKvlen) ? (totalLen - maskKvlen) : 0;
for (int k = 0; k < totalLen; ++k) {
float dotSum = 0.0;
for (int i = 0; i < d4Size; ++i) {
const int d = i * 4;
const int qOff = qBase + d;
const int kOff = ((k * kvHeadNum + kvh) * headDim) + d;
vec4 qv = vec4(float(uQuery.data[qOff + 0]), float(uQuery.data[qOff + 1]), float(uQuery.data[qOff + 2]),
float(uQuery.data[qOff + 3]));
vec4 kv = vec4(float(uCacheKey.data[kOff + 0]), float(uCacheKey.data[kOff + 1]), float(uCacheKey.data[kOff + 2]),
float(uCacheKey.data[kOff + 3]));
dotSum += dot(qv, kv);
}
float score = dotSum * scale;
if (maskMode == 1) {
if (q < maskQlen && maskKvlen > 0 && k >= kStart) {
const int mk = k - kStart;
if (mk >= 0 && mk < maskKvlen) {
score += float(uMask.data[q * maskKvlen + mk]);
}
}
} else if (maskMode == 2 && k > (pastLen + q)) {
score = NEG_INF;
}
float w = 0.0;
if (score > m) {
float factor = exp(m - score);
for (int i = 0; i < d4Size; ++i) {
outVec[i] *= factor;
}
s = s * factor + 1.0;
m = score;
w = 1.0;
} else {
w = exp(score - m);
s += w;
}
const int vOffBase = ((k * kvHeadNum + kvh) * headDim);
for (int i = 0; i < d4Size; ++i) {
const int d = i * 4;
const int vOff = vOffBase + d;
vec4 vv = vec4(float(uCacheValue.data[vOff + 0]), float(uCacheValue.data[vOff + 1]), float(uCacheValue.data[vOff + 2]),
float(uCacheValue.data[vOff + 3]));
outVec[i] += w * vv;
}
}
float invS = 1.0 / s;
// output: [1, qLen, headNum * headDim]
const int outBase = (q * headNum + h) * headDim;
for (int i = 0; i < d4Size; ++i) {
vec4 v = outVec[i] * invS;
const int d = i * 4;
uOutput.data[outBase + d + 0] = FLOAT(v.x);
uOutput.data[outBase + d + 1] = FLOAT(v.y);
uOutput.data[outBase + d + 2] = FLOAT(v.z);
uOutput.data[outBase + d + 3] = FLOAT(v.w);
}
}