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
5.8 KiB224 linesraw
1#include "stdafx.h"
2#include "../../Whisper/ML/testUtils.h"
3#include <immintrin.h>
4using namespace DirectCompute;
5
6namespace
7{
8	using DirectCompute::sTensorDiff;
9
10	__forceinline __m256 load( const float* rsi )
11	{
12		return _mm256_loadu_ps( rsi );
13	}
14
15	__forceinline __m256 load( const uint16_t* rsi )
16	{
17		const __m128i iv = _mm_load_si128( ( const __m128i* )rsi );
18		return _mm256_cvtph_ps( iv );
19	}
20
21	__forceinline void loadPartial( const uint16_t* x, const uint16_t* y, size_t count, __m256& fx, __m256& fy )
22	{
23		__m128i ix, iy;
24		switch( count )
25		{
26		case 1: // load 2 bytes
27			ix = _mm_cvtsi32_si128( *x );
28			iy = _mm_cvtsi32_si128( *y );
29			break;
30		case 2: // load 4 bytes
31			ix = _mm_cvtsi32_si128( *(const int*)x );
32			iy = _mm_cvtsi32_si128( *(const int*)y );
33			break;
34		case 3: // load 6 bytes
35			ix = _mm_cvtsi32_si128( *(const int*)x );
36			iy = _mm_cvtsi32_si128( *(const int*)y );
37			ix = _mm_insert_epi16( ix, x[ 2 ], 2 );
38			iy = _mm_insert_epi16( iy, y[ 2 ], 2 );
39			break;
40		case 4: // load 8 bytes
41			ix = _mm_cvtsi64_si128( *(const int64_t*)x );
42			iy = _mm_cvtsi64_si128( *(const int64_t*)y );
43			break;
44		case 5: // load 10 bytes
45			ix = _mm_cvtsi64_si128( *(const int64_t*)x );
46			iy = _mm_cvtsi64_si128( *(const int64_t*)y );
47			ix = _mm_insert_epi16( ix, x[ 4 ], 4 );
48			iy = _mm_insert_epi16( iy, y[ 4 ], 4 );
49			break;
50		case 6: // load 12 bytes
51			ix = _mm_cvtsi64_si128( *(const int64_t*)x );
52			iy = _mm_cvtsi64_si128( *(const int64_t*)y );
53			ix = _mm_insert_epi32( ix, *(const int*)( x + 4 ), 2 );
54			iy = _mm_insert_epi32( iy, *(const int*)( y + 4 ), 2 );
55			break;
56		case 7: // load 14 bytes
57			ix = _mm_cvtsi64_si128( *(const int64_t*)x );
58			iy = _mm_cvtsi64_si128( *(const int64_t*)y );
59			ix = _mm_insert_epi32( ix, *(const int*)( x + 4 ), 2 );
60			iy = _mm_insert_epi32( iy, *(const int*)( y + 4 ), 2 );
61			ix = _mm_insert_epi16( ix, x[ 6 ], 6 );
62			iy = _mm_insert_epi16( iy, y[ 6 ], 6 );
63			break;
64		default:
65			fx = fy = _mm256_setzero_ps();
66			return;
67		}
68
69		fx = _mm256_cvtph_ps( ix );
70		fy = _mm256_cvtph_ps( iy );
71	}
72
73	inline __m128 loadFloat2( const float* rsi )
74	{
75		return _mm_castpd_ps( _mm_load_sd( (const double*)rsi ) );
76	}
77	inline __m128 loadFloat3( const float* rsi )
78	{
79		__m128 f = loadFloat2( rsi );
80		f = _mm_insert_ps( f, _mm_load_ss( rsi + 2 ), 0x20 );
81		return f;
82	}
83	__forceinline void loadPartial( const float* x, const float* y, size_t count, __m256& fx, __m256& fy )
84	{
85		__m128 low1, high1;
86		__m128 low2, high2;
87		high1 = high2 = _mm_setzero_ps();
88		switch( count )
89		{
90		case 1:
91			low1 = _mm_load_ss( x );
92			low2 = _mm_load_ss( y );
93			break;
94		case 2:
95			low1 = loadFloat2( x );
96			low2 = loadFloat2( y );
97			break;
98		case 3:
99			low1 = loadFloat3( x );
100			low2 = loadFloat3( y );
101			break;
102		case 4:
103			low1 = _mm_loadu_ps( x );
104			low2 = _mm_loadu_ps( y );
105			break;
106		case 5:
107			low1 = _mm_loadu_ps( x );
108			low2 = _mm_loadu_ps( y );
109			high1 = _mm_load_ss( x + 4 );
110			high2 = _mm_load_ss( y + 4 );
111			break;
112		case 6:
113			low1 = _mm_loadu_ps( x );
114			low2 = _mm_loadu_ps( y );
115			high1 = loadFloat2( x + 4 );
116			high2 = loadFloat2( y + 4 );
117			break;
118		case 7: // load 14 bytes
119			low1 = _mm_loadu_ps( x );
120			low2 = _mm_loadu_ps( y );
121			high1 = loadFloat3( x + 4 );
122			high2 = loadFloat3( y + 4 );
123			break;
124		default:
125			fx = fy = _mm256_setzero_ps();
126			return;
127		}
128
129		fx = _mm256_setr_m128( low1, high1 );
130		fy = _mm256_setr_m128( low2, high2 );
131	}
132
133	__forceinline float horizontalMaximum( __m256 v )
134	{
135		__m128 s = _mm256_extractf128_ps( v, 1 );
136		s = _mm_max_ps( s, _mm256_castps256_ps128( v ) );
137		s = _mm_max_ps( s, _mm_movehl_ps( s, s ) );
138		s = _mm_max_ss( s, _mm_movehdup_ps( s ) );
139		return _mm_cvtss_f32( s );
140	}
141
142	__forceinline double horizontalSum( __m256 v )
143	{
144		__m256d d = _mm256_cvtps_pd( _mm256_extractf128_ps( v, 1 ) );
145		d = _mm256_add_pd( d, _mm256_cvtps_pd( _mm256_castps256_ps128( v ) ) );
146
147		__m128d s = _mm256_extractf128_pd( d, 1 );
148		s = _mm_add_pd( s, _mm256_castpd256_pd128( d ) );
149		s = _mm_add_sd( s, _mm_unpackhi_pd( s, s ) );
150		return _mm_cvtsd_f64( s );
151	}
152
153	__m256 maskInfNan( __m256 diff, __m256 a, __m256 b )
154	{
155		__m256i ai = _mm256_castps_si256( a );
156		__m256i bi = _mm256_castps_si256( b );
157		__m256i eqi = _mm256_cmpeq_epi32( ai, bi );
158		__m256 eq = _mm256_castsi256_ps( eqi );
159		return _mm256_andnot_ps( eq, diff );
160	}
161
162	class DiffAcc
163	{
164		__m256 maxAbs = _mm256_setzero_ps();
165		__m256 sumSquares = _mm256_setzero_ps();
166
167	public:
168
169		__forceinline void add( __m256 a, __m256 b )
170		{
171			const __m256 neg0 = _mm256_set1_ps( -0.0f );
172			__m256 diff = _mm256_sub_ps( b, a );
173			diff = maskInfNan( diff, a, b );
174			sumSquares = _mm256_fmadd_ps( diff, diff, sumSquares );
175			const __m256 absDiff = _mm256_andnot_ps( neg0, diff );
176			maxAbs = _mm256_max_ps( maxAbs, absDiff );
177		}
178
179		__forceinline sTensorDiff reduce( size_t count )
180		{
181			sTensorDiff res;
182			res.maxAbsDiff = horizontalMaximum( maxAbs );
183			res.avgDiffSquared = (float)( horizontalSum( sumSquares ) / (double)(int64_t)count );
184			res.length = count;
185			return res;
186		}
187	};
188
189	template<class E>
190	static sTensorDiff __declspec( noinline ) diffVectors( const E* a, const E* b, size_t length )
191	{
192		// const E* const aEnd = a + length;
193		const E* const aEndAligned = a + ( length / 8 ) * 8;
194		const size_t remainder = length % 8;
195
196		DiffAcc acc;
197		for( ; a < aEndAligned; a += 8, b += 8 )
198			acc.add( load( a ), load( b ) );
199
200		if( remainder != 0 )
201		{
202			__m256 va, vb;
203			loadPartial( a, b, remainder, va, vb );
204			acc.add( va, vb );
205		}
206
207		return acc.reduce( length );
208	}
209}
210
211sTensorDiff DirectCompute::computeDiff( const float* a, const float* b, size_t length )
212{
213	return diffVectors( a, b, length );
214}
215
216sTensorDiff DirectCompute::computeDiff( const uint16_t* a, const uint16_t* b, size_t length )
217{
218	return diffVectors( a, b, length );
219}
220
221void DirectCompute::sTensorDiff::print() const
222{
223	printf( "%zu elements, maxAbsDiff = %g, avgDiffSquared = %g\n", length, maxAbsDiff, avgDiffSquared );
224}