#ifdef MNN_SUPPORT_FP16 #pragma OPENCL EXTENSION cl_khr_fp16 : enable #endif #define GLOBAL_SIZE_3_DIMS \ __private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, #define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ return; \ } #define DEAL_HEAD_DIM_NOT_ALIGN \ if(hd * 4 + 3 >= head_dim) {\ temp_0.w = (FLOAT)0;\ temp_1.w = (FLOAT)0;\ temp_2.w = (FLOAT)0;\ temp_3.w = (FLOAT)0;\ }\ if(hd * 4 + 2 >= head_dim) {\ temp_0.z = (FLOAT)0;\ temp_1.z = (FLOAT)0;\ temp_2.z = (FLOAT)0;\ temp_3.z = (FLOAT)0;\ }\ if(hd * 4 + 1 >= head_dim) {\ temp_0.y = (FLOAT)0;\ temp_1.y = (FLOAT)0;\ temp_2.y = (FLOAT)0;\ temp_3.y = (FLOAT)0;\ } #define DEAL_SEQ_LEN_NOT_ALIGN \ if(4 * sl + 3 >= seq_len) {\ temp_3 = (FLOAT4)0;\ }\ if(4 * sl + 2 >= seq_len) {\ temp_2 = (FLOAT4)0;\ }\ if(4 * sl + 1 >= seq_len) {\ temp_1 = (FLOAT4)0;\ } __kernel void split_transpose_qkv(GLOBAL_SIZE_3_DIMS __global const FLOAT *input, // [Batch, seqLen/4, mNumHead * 3 * mHeadDim, 4] __global FLOAT *output_q, // [Batch * mNumHead, head_dim_pack_k, seq_len_pack_mn / qSeqSplitNum] __global FLOAT *output_k, // [Batch * mNumHead, head_dim_pack_k, seq_len_pack_mn] __global FLOAT *output_v, // [Batch * mNumHead, ROUND_UP(seqLen, tile), head_dim_pack_mn] __private const int seq_len_pack_mn, __private const int seq_len_piece, __private const int head_dim_pack_mn, __private const int head_dim_pack_k, __private const int seq_len, __private const int head_num, __private const int head_dim, __private const int batch, __private const int seq_index ) { const int sl = get_global_id(0); // seqLen_4 const int hd = get_global_id(1); // mHeadDim_4 const int z = get_global_id(2); // Batch * mNumHead DEAL_NON_UNIFORM_DIM3(sl, hd, z); const int b = z / head_num; const int hn = z % head_num; const int offset_q = ((b * head_num + hn) * head_dim_pack_k + 4 * hd) * seq_len_piece + 4 * sl; if(seq_index > 0) { // fill output_q only if(sl * 4 >= seq_len || hd * 4 >= head_dim) { if(hd * 4 < head_dim_pack_k) { if(sl * 4 < seq_len_piece) { vstore4((FLOAT4)0, 0, output_q + offset_q); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece + seq_len_piece); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece + seq_len_piece + seq_len_piece); } } return; } const int offset_inp = ((((seq_index * seq_len_piece / 4 + sl) * batch + b) * head_num + hn) * 3 * head_dim + 4 * hd) * 4; if(sl * 4 < seq_len_piece) { FLOAT4 temp_0 = vload4(0, input + offset_inp); FLOAT4 temp_1 = vload4(0, input + offset_inp + 4); FLOAT4 temp_2 = vload4(0, input + offset_inp + 8); FLOAT4 temp_3 = vload4(0, input + offset_inp + 12); #ifdef HEADDIM_LEAVE DEAL_HEAD_DIM_NOT_ALIGN #endif #ifdef SEQLEN_LEAVE DEAL_SEQ_LEN_NOT_ALIGN #endif vstore4(temp_0, 0, output_q + offset_q); vstore4(temp_1, 0, output_q + offset_q + seq_len_piece); vstore4(temp_2, 0, output_q + offset_q + seq_len_piece + seq_len_piece); vstore4(temp_3, 0, output_q + offset_q + seq_len_piece + seq_len_piece + seq_len_piece); } return; } const int offset_k = ((b * head_num + hn) * head_dim_pack_k + 4 * hd) * seq_len_pack_mn + 4 * sl; const int offset_v = ((b * head_num + hn) * seq_len_pack_mn + 4 * sl) * head_dim_pack_mn + 4 * hd; if(sl * 4 >= seq_len || hd * 4 >= head_dim) { if(hd * 4 < head_dim_pack_k) { if(sl * 4 < seq_len_piece) { vstore4((FLOAT4)0, 0, output_q + offset_q); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece + seq_len_piece); vstore4((FLOAT4)0, 0, output_q + offset_q + seq_len_piece + seq_len_piece + seq_len_piece); } vstore4((FLOAT4)0, 0, output_k + offset_k); vstore4((FLOAT4)0, 0, output_k + offset_k + seq_len_pack_mn); vstore4((FLOAT4)0, 0, output_k + offset_k + seq_len_pack_mn + seq_len_pack_mn); vstore4((FLOAT4)0, 0, output_k + offset_k + seq_len_pack_mn + seq_len_pack_mn + seq_len_pack_mn); } vstore4((FLOAT4)0, 0, output_v + offset_v); vstore4((FLOAT4)0, 0, output_v + offset_v + head_dim_pack_mn); vstore4((FLOAT4)0, 0, output_v + offset_v + head_dim_pack_mn + head_dim_pack_mn); vstore4((FLOAT4)0, 0, output_v + offset_v + head_dim_pack_mn + head_dim_pack_mn + head_dim_pack_mn); return; } const int offset_inp = (((sl * batch + b) * head_num + hn) * 3 * head_dim + 4 * hd) * 4; if(sl * 4 < seq_len_piece) { FLOAT4 temp_0 = vload4(0, input + offset_inp); FLOAT4 temp_1 = vload4(0, input + offset_inp + 4); FLOAT4 temp_2 = vload4(0, input + offset_inp + 8); FLOAT4 temp_3 = vload4(0, input + offset_inp + 12); #ifdef HEADDIM_LEAVE DEAL_HEAD_DIM_NOT_ALIGN #endif #ifdef SEQLEN_LEAVE DEAL_SEQ_LEN_NOT_ALIGN #endif vstore4(temp_0, 0, output_q + offset_q); vstore4(temp_1, 0, output_q + offset_q + seq_len_piece); vstore4(temp_2, 0, output_q + offset_q + seq_len_piece + seq_len_piece); vstore4(temp_3, 0, output_q + offset_q + seq_len_piece + seq_len_piece + seq_len_piece); } { // K FLOAT4 temp_0 = vload4(0, input + offset_inp + 4*head_dim); FLOAT4 temp_1 = vload4(0, input + offset_inp + 4*head_dim + 4); FLOAT4 temp_2 = vload4(0, input + offset_inp + 4*head_dim + 8); FLOAT4 temp_3 = vload4(0, input + offset_inp + 4*head_dim + 12); #ifdef HEADDIM_LEAVE DEAL_HEAD_DIM_NOT_ALIGN #endif #ifdef SEQLEN_LEAVE DEAL_SEQ_LEN_NOT_ALIGN #endif vstore4(temp_0, 0, output_k + offset_k); vstore4(temp_1, 0, output_k + offset_k + seq_len_pack_mn); vstore4(temp_2, 0, output_k + offset_k + seq_len_pack_mn + seq_len_pack_mn); vstore4(temp_3, 0, output_k + offset_k + seq_len_pack_mn + seq_len_pack_mn + seq_len_pack_mn); // V temp_0 = vload4(0, input + offset_inp + 8 * head_dim); temp_1 = vload4(0, input + offset_inp + 8 * head_dim + 4); temp_2 = vload4(0, input + offset_inp + 8 * head_dim + 8); temp_3 = vload4(0, input + offset_inp + 8 * head_dim + 12); #ifdef HEADDIM_LEAVE DEAL_HEAD_DIM_NOT_ALIGN #endif #ifdef SEQLEN_LEAVE DEAL_SEQ_LEN_NOT_ALIGN #endif vstore4((FLOAT4){temp_0.x, temp_1.x, temp_2.x, temp_3.x}, 0, output_v + offset_v); vstore4((FLOAT4){temp_0.y, temp_1.y, temp_2.y, temp_3.y}, 0, output_v + offset_v + head_dim_pack_mn); vstore4((FLOAT4){temp_0.z, temp_1.z, temp_2.z, temp_3.z}, 0, output_v + offset_v + head_dim_pack_mn + head_dim_pack_mn); vstore4((FLOAT4){temp_0.w, temp_1.w, temp_2.w, temp_3.w}, 0, output_v + offset_v + head_dim_pack_mn + head_dim_pack_mn + head_dim_pack_mn); } } #ifndef SOFTMAX_LOCAL_SIZE #define SOFTMAX_LOCAL_SIZE 512 #endif // [outside, axis, inside] -> reduce: inside __kernel void softmax_inside(GLOBAL_SIZE_3_DIMS __global const FLOAT *input, // [batch * mNumHead, ROUND_UP(seqLen, tile), ROUND_UP(seqLen, tile)] __global FLOAT *output, __private const int inside_len, __private const int4 shape // [batch * mNumHead, ROUND_UP(seqLen, tile), ROUND_UP(seqLen, tile)] ) { const int inside = get_global_id(0); const int axis = get_global_id(1); const int outside = get_global_id(2); DEAL_NON_UNIFORM_DIM3(inside, axis, outside); const int offset = (outside * shape.y + axis) * shape.z + 0; #if SOFTMAX_LOCAL_SIZE >= 4 int lid = get_local_id(0); float local sum_mnn[SOFTMAX_LOCAL_SIZE]; float local max_mnn[SOFTMAX_LOCAL_SIZE]; /*Compute Max */ float maxValue = (float)(-FLT_MAX); // clip to seq_len for (int i=lid; i 0; i >>= 1){ if (lid < i) max_mnn[lid] = fmax(max_mnn[lid], max_mnn[lid + i]); barrier(CLK_LOCAL_MEM_FENCE); } maxValue = max_mnn[0]; /*Compute Exp Sum*/ float sumValue = 0; for (int i=lid; i 0; i >>= 1){ if (lid < i) sum_mnn[lid] = sum_mnn[lid] + sum_mnn[lid + i]; barrier(CLK_LOCAL_MEM_FENCE); } sumValue = sum_mnn[0]; #ifdef OUTPUT_TRANSPOSE const int out_offset = (outside * shape.z + 0) * shape.y + axis; #endif /*Compute Result */ for (int i=lid; i inside_len){ for(int i = lid + inside_len; i < shape.z; i+=SOFTMAX_LOCAL_SIZE){ #ifdef OUTPUT_TRANSPOSE output[out_offset+ i*shape.y] = (FLOAT)0; #else output[offset+ i] = (FLOAT)0; #endif } } #else /*Compute Max */ float maxValue = (float)(-FLT_MAX); // clip to seq_len for (int i=0; i inside_len){ for(int i = inside_len; i < shape.z; i++){ #ifdef OUTPUT_TRANSPOSE output[out_offset+ i*shape.y] = (FLOAT)0; #else output[offset+ i] = (FLOAT)0; #endif } } #endif } // [N X Y4 4] -> [N Y X] __kernel void trans_3d_buf(GLOBAL_SIZE_3_DIMS __global const FLOAT* input, __global FLOAT* output, __private const int batch, __private const int width, __private const int height ) { int b = get_global_id(2); int w = get_global_id(0); int h = get_global_id(1); DEAL_NON_UNIFORM_DIM3(w, h, b); w = w << 3; h = h << 3; const int inp_offset = (b * width + w) * height + h; const int out_offset = (b * height + h) * width + w; FLOAT8 value_0 = vload8(0, input+inp_offset); FLOAT8 value_1 = vload8(0, input+inp_offset + height); FLOAT8 value_2 = vload8(0, input+inp_offset + height + height); FLOAT8 value_3 = vload8(0, input+inp_offset + height + height + height); FLOAT8 value_4 = vload8(0, input+inp_offset + (height << 2)); FLOAT8 value_5 = vload8(0, input+inp_offset + height * 5); FLOAT8 value_6 = vload8(0, input+inp_offset + height * 6); FLOAT8 value_7 = vload8(0, input+inp_offset + height * 7); vstore8((FLOAT8){value_0.s0, value_1.s0, value_2.s0, value_3.s0, value_4.s0, value_5.s0, value_6.s0, value_7.s0}, 0, output + out_offset); vstore8((FLOAT8){value_0.s1, value_1.s1, value_2.s1, value_3.s1, value_4.s1, value_5.s1, value_6.s1, value_7.s1}, 0, output + out_offset + width); vstore8((FLOAT8){value_0.s2, value_1.s2, value_2.s2, value_3.s2, value_4.s2, value_5.s2, value_6.s2, value_7.s2}, 0, output + out_offset + width + width); vstore8((FLOAT8){value_0.s3, value_1.s3, value_2.s3, value_3.s3, value_4.s3, value_5.s3, value_6.s3, value_7.s3}, 0, output + out_offset + width + width + width); vstore8((FLOAT8){value_0.s4, value_1.s4, value_2.s4, value_3.s4, value_4.s4, value_5.s4, value_6.s4, value_7.s4}, 0, output + out_offset + (width << 2)); vstore8((FLOAT8){value_0.s5, value_1.s5, value_2.s5, value_3.s5, value_4.s5, value_5.s5, value_6.s5, value_7.s5}, 0, output + out_offset + width * 5); vstore8((FLOAT8){value_0.s6, value_1.s6, value_2.s6, value_3.s6, value_4.s6, value_5.s6, value_6.s6, value_7.s6}, 0, output + out_offset + width * 6); vstore8((FLOAT8){value_0.s7, value_1.s7, value_2.s7, value_3.s7, value_4.s7, value_5.s7, value_6.s7, value_7.s7}, 0, output + out_offset + width * 7); } __kernel void clip_transpose_qkv(GLOBAL_SIZE_3_DIMS __global const FLOAT *input, // [Batch * mNumHead, ROUND_UP(mHeadDim, tile), ROUND_UP(seqLen, tile)] __global FLOAT *output, // [Batch, seqLen/4, mNumHead * mHeadDim, 4] __private const int tile, __private const int seq_len, __private const int seq_len_piece, __private const int head_num, __private const int head_dim, __private const int batch, __private const int seq_index ) { const int sl = get_global_id(0); // seqLen_Piece_4 const int hd = get_global_id(1); // mHeadDim_4 const int z = get_global_id(2); // Batch * mNumHead DEAL_NON_UNIFORM_DIM3(sl, hd, z); const int b = z / head_num; const int hn = z % head_num; const int seq_len_4 = (seq_len + 3) / 4; if(seq_index * seq_len_piece / 4 + sl >= seq_len_4) { return; } const int seq_len_pack = seq_len_piece;//((seq_len + tile - 1) / tile) * tile; const int head_dim_pack = ((head_dim + tile - 1) / tile) * tile; const int offset_inp = ((b * head_num + hn) * head_dim_pack + 4 * hd) * seq_len_pack + 4 * sl; const int offset_out = ((((seq_index * seq_len_piece / 4 + sl) * batch + b) * head_num + hn) * head_dim + 4 * hd) * 4; // Q FLOAT4 temp_0 = vload4(0, input + offset_inp); FLOAT4 temp_1 = vload4(0, input + offset_inp + seq_len_pack); FLOAT4 temp_2 = vload4(0, input + offset_inp + 2 * seq_len_pack); FLOAT4 temp_3 = vload4(0, input + offset_inp + 3 * seq_len_pack); vstore4(temp_0, 0, output + offset_out); if(4 * hd + 1 > head_dim) return; vstore4(temp_1, 0, output + offset_out + 4); if(4 * hd + 2 > head_dim) return; vstore4(temp_2, 0, output + offset_out + 8); if(4 * hd + 3 > head_dim) return; vstore4(temp_3, 0, output + offset_out + 12); }