yum-archive/TaSTT-Whisper
High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model
git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper
e78815d
master
1// matrix*row vector product, needs first argument reshaped into a sequence of horizontal column major panels 2#ifndef TILE_SIZE 3static const uint TILE_SIZE = 32 ; 4#endif 5#ifndef THREADS_Y 6static const uint THREADS_Y = 8 ; 7#endif 8 9// First tensor, reshaped into dense column major horizontal panels of size [ width, TILE_SIZE ] 10Buffer < float > arg0 :register ( t0 ); 11// Second tensor, reshaped into dense column major horizontal panels of size [ width, TILE_SIZE ] 12Buffer < float > arg1 :register ( t1 ); 13// FP32 output tensor, row major and continuous 14RWBuffer < float > result :register ( u0 ); 15 16cbuffer Constants :register ( b0 ) 17{ 18uint4 arg0Size :packoffset ( c0 ); 19uint arg0panel :packoffset ( c1 . y ); 20uint2 arg0LayerStrides :packoffset ( c1 . z ); 21// uint4 arg1Size: packoffset( c2 ); 22uint4 arg1Strides :packoffset ( c3 ); 23uint4 resultSize :packoffset ( c4 ); 24uint4 resultStrides :packoffset ( c5 ); 25} 26 27inline uint hadd4 ( const uint4 v ) 28{ 29const uint2 v2 = v . xy + v . zw ; 30return v2 . x + v2 . y ; 31} 32 33inline float hadd4 ( const float4 v ) 34{ 35const float2 v2 = v . xy + v . zw ; 36return v2 . x + v2 . y ; 37} 38 39groupsharedfloat reductionBuffer [ THREADS_Y ][ TILE_SIZE ]; 40 41[ numthreads ( TILE_SIZE , THREADS_Y , 1 )] 42void main ( const uint3 group : SV_GroupID , const uint3 thread : SV_GroupThreadID ) 43{ 44const uint2 layer = group . yz ; 45// Source offsets for the complete thread group 46uint2 rsi ; 47rsi . x = group . x * arg0panel + layer . x * arg0LayerStrides . x + layer . y * arg0LayerStrides . y ; 48rsi . y = layer . x * arg1Strides . z + layer . y * arg1Strides . w ; 49// Apply source offsets for this particular thread 50rsi . x += thread . y * TILE_SIZE + thread . x ; 51rsi . y += thread . y * arg1Strides . x ; 52 53const uint2 rsiInc = uint2 ( THREADS_Y * TILE_SIZE , THREADS_Y * arg1Strides . x ); 54 55const uint completeTiles = arg0Size . x / ( THREADS_Y * 4 ); 56uint i ; 57float4 acc = 0.0 ; 58for ( i = 0 ; i < completeTiles ; i ++ ) 59{ 60// Each iteration of this loop consumes THREADS_Y*4 columns from the arg0 panel, and THREADS_Y*4 values from arg1 61float4 v0 , v1 ; 62[ unroll ] 63for ( uint j = 0 ; j < 4 ; j ++ , rsi += rsiInc ) 64{ 65// Load [ TILE_SIZE, THREADS_Y ] block from the first source tensor 66v0 [ j ] = arg0 [ rsi . x ]; 67// Broadcast [ THREADS_Y ] row from the second source tensor 68v1 [ j ] = arg1 [ rsi . y ]; 69} 70 71// Now we have [ TILE_SIZE, THREADS_Y * 4 ] block from the first source tensor in the v0 vector, 72// and [ THREADS_Y * 4 ] row from the second one in the v1 vector 73// Multiply and accumulate. 74acc = mad ( v0 , v1 , acc ); 75} 76 77// Handle the remainder columns, if any. 78// When present, their count is in [ 1 .. THREADS_Y * 4 - 1 ] interval 79const uint rem = arg0Size . x % ( THREADS_Y * 4 ); 80if ( rem != 0 ) 81{ 82float4 v0 = 0.0 , v1 = 0.0 ; 83[ unroll ] 84for ( uint j = 0 ; j < 4 ; j ++ , rsi += rsiInc ) 85{ 86const uint x = ( j * THREADS_Y ) + thread . y ; 87if ( x < rem ) 88{ 89v0 [ j ] = arg0 [ rsi . x ]; 90v1 [ j ] = arg1 [ rsi . y ]; 91} 92} 93acc = mad ( v0 , v1 , acc ); 94} 95 96// We now have [ TILE_SIZE, THREADS_Y * 4 ] block in the local variables of this thread group 97// The group however only outputs [ TILE_SIZE ] elements max, need a reduction 98float acc1 = hadd4 ( acc ); 99reductionBuffer [ thread . y ][ thread . x ] = acc1 ; 100GroupMemoryBarrierWithGroupSync (); 101 102for ( i = THREADS_Y / 2 ; i > 1 ; i /= 2 ) 103{ 104if ( thread . y < i ) 105{ 106acc1 += reductionBuffer [ thread . y + i ][ thread . x ]; 107reductionBuffer [ thread . y ][ thread . x ] = acc1 ; 108} 109GroupMemoryBarrierWithGroupSync (); 110} 111 112if ( thread . y != 0 ) 113return ; 114 115const uint resultPos = group . x * TILE_SIZE ; 116const uint outputSize = min ( TILE_SIZE , resultSize . x - resultPos ); 117if ( thread . x >= outputSize ) 118return ; 119 120const uint4 resultPos4 = uint4 ( resultPos + thread . x , 0 , layer ); 121const uint rdi = hadd4 ( resultPos4 * resultStrides ); 122result [ rdi ] = acc1 + reductionBuffer [ 1 ][ thread . x ]; 123}