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

KonstantinSource codes8c4603c

master
3.1 KiB105 linesraw
1// This shader reshapes a matrix into the shape expected by mulMatTiledEx.hlsl and mulMatByRowTiledEx.hlsl compute shaders
2// It's called in runtime, also while loading models from disk.
3// So far, it's only used when running on AMD GPUs.
4#ifndef TILE_SIZE
5static const uint TILE_SIZE = 32;
6#endif
7
8// Input tensor
9Buffer<float> source: register( t0 );
10// Output tensor
11RWBuffer<float> result: register( u0 );
12
13cbuffer Constants: register( b0 )
14{
15	uint4 arg0Size: packoffset( c0 );
16	uint4 arg0Strides: packoffset( c1 );
17	// Count of elements per panel
18	uint panelSize : packoffset( c2.y );
19	// Layer strides of the output matrix
20	uint2 layerStrides: packoffset( c2.z );
21}
22
23inline uint hadd( uint2 v2 ) { return v2.x + v2.y; }
24
25groupshared float tileBuffer[ TILE_SIZE ][ TILE_SIZE ];
26
27[ numthreads( TILE_SIZE, 1, 1 ) ]
28void main( const uint3 group: SV_GroupID, const uint thread : SV_GroupIndex )
29{
30	uint rdi = hadd( group.yz * layerStrides );
31	rdi += group.x * panelSize;
32	rdi += thread;
33
34	uint rsi = hadd( group.yz * arg0Strides.zw );
35	const uint baseY = group.x * TILE_SIZE;
36	const uint dispatchThread = baseY + thread;
37	// Reshaping into a column major horizontal panel, height = TILE_SIZE, width = width of the source matrix
38	uint width = arg0Size.x;
39	// Usually TILE_SIZE; can be less for the last panel on the matrix when we need to generate zeros instead of loading these numbers
40	const uint height = min( TILE_SIZE, arg0Size.y - baseY );
41
42	if( arg0Strides.x == 1 )
43	{
44		// The input matrix is row major, can improve performance with coalesced loads and group shared buffer.
45		rsi += baseY * arg0Strides.y;
46
47		const uint widthCompleteTiles = width / TILE_SIZE;
48
49		if( height < TILE_SIZE )
50		{
51			// This thread group was dispatched for the last panel of the matrix, it doesn't have enough rows
52			// Write zeros to the corresponding elements of the groupshared buffer
53			for( uint j = height; j < TILE_SIZE; j++ )
54				tileBuffer[ thread ][ j ] = 0.0;
55		}
56
57		for( uint i = 0; i < widthCompleteTiles; i++, rsi += TILE_SIZE )
58		{
59			// Load [ TILE_SIZE ] * [ TILE_SIZE ] block with fully coalesced loads, store to group shared buffer in transposed order
60			uint rsiTile = rsi + thread;
61			uint j;
62			for( j = 0; j < height; j++, rsiTile += arg0Strides.y )
63			{
64				// Each iteration of the loop loads a row of [ TILE_SIZE ] elements from the corresponding row of the source tensor
65				// Fully coalesced load
66				float f = source[ rsiTile ];
67				// Random store but the local memory's fast, this works rather well in practice
68				tileBuffer[ thread ][ j ] = f;
69			}
70
71			GroupMemoryBarrierWithGroupSync();
72
73			// Copy from group shared buffer to output tensor
74			for( j = 0; j < TILE_SIZE; j++, rdi += TILE_SIZE )
75			{
76				// Fully coalesced loads and stores
77				float f = tileBuffer[ j ][ thread ];
78				result[ rdi ] = f;
79			}
80
81			GroupMemoryBarrierWithGroupSync();
82		}
83
84		width %= TILE_SIZE;
85		if( 0 == width )
86			return;
87		rsi += thread * arg0Strides.y;
88	}
89	else
90		rsi += dispatchThread * arg0Strides.y;
91
92	for( uint i = 0; i < width; i++ )
93	{
94		float f;
95		[branch]
96		if( thread < height )
97			f = source[ rsi ];
98		else
99			f = 0.0;
100		rsi += arg0Strides.x;
101
102		result[ rdi ] = f;
103		rdi += TILE_SIZE;
104	}
105}