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
8c4603c
master
1#include "stdafx.h" 2#include "testUtils.h" 3#include <immintrin.h> 4#include <atlfile.h> 5#include <atlpath.h> 6 7namespace 8{ 9using DirectCompute ::sTensorDiff ; 10 11 __forceinline__m256 load (const float * rsi ) 12 { 13return _mm256_loadu_ps (rsi ); 14 } 15 16 __forceinline__m256 load (const uint16_t * rsi ) 17 { 18const __m128i iv = _mm_load_si128 ( (const __m128i * )rsi ); 19return _mm256_cvtph_ps (iv ); 20 } 21 22 __forceinlinevoid loadPartial (const uint16_t * x ,const uint16_t * y ,size_t count ,__m256 & fx ,__m256 & fy ) 23 { 24__m128i ix ,iy ; 25switch (count ) 26 { 27case 1 :// load 2 bytes 28ix = _mm_cvtsi32_si128 (* x ); 29iy = _mm_cvtsi32_si128 (* y ); 30break ; 31case 2 :// load 4 bytes 32ix = _mm_cvtsi32_si128 (* (const int * )x ); 33iy = _mm_cvtsi32_si128 (* (const int * )y ); 34break ; 35case 3 :// load 6 bytes 36ix = _mm_cvtsi32_si128 (* (const int * )x ); 37iy = _mm_cvtsi32_si128 (* (const int * )y ); 38ix = _mm_insert_epi16 (ix ,x [2 ],2 ); 39iy = _mm_insert_epi16 (iy ,y [2 ],2 ); 40break ; 41case 4 :// load 8 bytes 42ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 43iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 44break ; 45case 5 :// load 10 bytes 46ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 47iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 48ix = _mm_insert_epi16 (ix ,x [4 ],4 ); 49iy = _mm_insert_epi16 (iy ,y [4 ],4 ); 50break ; 51case 6 :// load 12 bytes 52ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 53iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 54ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 55iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 56break ; 57case 7 :// load 14 bytes 58ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 59iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 60ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 61iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 62ix = _mm_insert_epi16 (ix ,x [6 ],6 ); 63iy = _mm_insert_epi16 (iy ,y [6 ],6 ); 64break ; 65default : 66fx = fy = _mm256_setzero_ps (); 67return ; 68 } 69 70fx = _mm256_cvtph_ps (ix ); 71fy = _mm256_cvtph_ps (iy ); 72 } 73 74inline __m128 loadFloat2 (const float * rsi ) 75 { 76return _mm_castpd_ps (_mm_load_sd ( (const double * )rsi ) ); 77 } 78inline __m128 loadFloat3 (const float * rsi ) 79 { 80__m128 f = loadFloat2 (rsi ); 81f = _mm_insert_ps (f ,_mm_load_ss (rsi + 2 ),0x20 ); 82return f ; 83 } 84 __forceinlinevoid loadPartial (const float * x ,const float * y ,size_t count ,__m256 & fx ,__m256 & fy ) 85 { 86__m128 low1 ,high1 ; 87__m128 low2 ,high2 ; 88high1 = high2 = _mm_setzero_ps (); 89switch (count ) 90 { 91case 1 : 92low1 = _mm_load_ss (x ); 93low2 = _mm_load_ss (y ); 94break ; 95case 2 : 96low1 = loadFloat2 (x ); 97low2 = loadFloat2 (y ); 98break ; 99case 3 : 100low1 = loadFloat3 (x ); 101low2 = loadFloat3 (y ); 102break ; 103case 4 : 104low1 = _mm_loadu_ps (x ); 105low2 = _mm_loadu_ps (y ); 106break ; 107case 5 : 108low1 = _mm_loadu_ps (x ); 109low2 = _mm_loadu_ps (y ); 110high1 = _mm_load_ss (x + 4 ); 111high2 = _mm_load_ss (y + 4 ); 112break ; 113case 6 : 114low1 = _mm_loadu_ps (x ); 115low2 = _mm_loadu_ps (y ); 116high1 = loadFloat2 (x + 4 ); 117high2 = loadFloat2 (y + 4 ); 118break ; 119case 7 :// load 14 bytes 120low1 = _mm_loadu_ps (x ); 121low2 = _mm_loadu_ps (y ); 122high1 = loadFloat3 (x + 4 ); 123high2 = loadFloat3 (y + 4 ); 124break ; 125default : 126fx = fy = _mm256_setzero_ps (); 127return ; 128 } 129 130fx = _mm256_setr_m128 (low1 ,high1 ); 131fy = _mm256_setr_m128 (low2 ,high2 ); 132 } 133 134 __forceinlinefloat horizontalMaximum (__m256 v ) 135 { 136__m128 s = _mm256_extractf128_ps (v ,1 ); 137s = _mm_max_ps (s ,_mm256_castps256_ps128 (v ) ); 138s = _mm_max_ps (s ,_mm_movehl_ps (s ,s ) ); 139s = _mm_max_ss (s ,_mm_movehdup_ps (s ) ); 140return _mm_cvtss_f32 (s ); 141 } 142 143 __forceinlinedouble horizontalSum (__m256 v ) 144 { 145__m256d d = _mm256_cvtps_pd (_mm256_extractf128_ps (v ,1 ) ); 146d = _mm256_add_pd (d ,_mm256_cvtps_pd (_mm256_castps256_ps128 (v ) ) ); 147 148__m128d s = _mm256_extractf128_pd (d ,1 ); 149s = _mm_add_pd (s ,_mm256_castpd256_pd128 (d ) ); 150s = _mm_add_sd (s ,_mm_unpackhi_pd (s ,s ) ); 151return _mm_cvtsd_f64 (s ); 152 } 153 154__m256 maskInfNan (__m256 diff ,__m256 a ,__m256 b ) 155 { 156__m256i ai = _mm256_castps_si256 (a ); 157__m256i bi = _mm256_castps_si256 (b ); 158__m256i eqi = _mm256_cmpeq_epi32 (ai ,bi ); 159__m256 eq = _mm256_castsi256_ps (eqi ); 160return _mm256_andnot_ps (eq ,diff ); 161 } 162 163class DiffAcc 164 { 165__m256 maxAbs = _mm256_setzero_ps (); 166__m256 sumSquares = _mm256_setzero_ps (); 167 168public : 169 170 __forceinlinevoid add (__m256 a ,__m256 b ) 171 { 172const __m256 neg0 = _mm256_set1_ps (-0.0f ); 173__m256 diff = _mm256_sub_ps (b ,a ); 174diff = maskInfNan (diff ,a ,b ); 175sumSquares = _mm256_fmadd_ps (diff ,diff ,sumSquares ); 176const __m256 absDiff = _mm256_andnot_ps (neg0 ,diff ); 177maxAbs = _mm256_max_ps (maxAbs ,absDiff ); 178 } 179 180 __forceinlinesTensorDiff reduce (size_t count ) 181 { 182sTensorDiff res ; 183res .maxAbsDiff = horizontalMaximum (maxAbs ); 184res .avgDiffSquared = (float )(horizontalSum (sumSquares ) / (double )(int64_t )count ); 185res .length = count ; 186return res ; 187 } 188 }; 189 190template < class E > 191static sTensorDiff __declspec(noinline )diffVectors (const E * a ,const E * b ,size_t length ) 192 { 193// const E* const aEnd = a + length; 194const E * const aEndAligned = a + (length /8 )* 8 ; 195const size_t remainder = length %8 ; 196 197DiffAcc acc ; 198for ( ;a < aEndAligned ;a += 8 ,b += 8 ) 199acc .add (load (a ),load (b ) ); 200 201if (remainder != 0 ) 202 { 203__m256 va ,vb ; 204loadPartial (a ,b ,remainder ,va ,vb ); 205acc .add (va ,vb ); 206 } 207 208return acc .reduce (length ); 209 } 210} 211 212sTensorDiff DirectCompute ::computeDiff (const float * a ,const float * b ,size_t length ) 213{ 214return diffVectors (a ,b ,length ); 215} 216 217sTensorDiff DirectCompute ::computeDiff (const uint16_t * a ,const uint16_t * b ,size_t length ) 218{ 219return diffVectors (a ,b ,length ); 220} 221 222void DirectCompute ::sTensorDiff::const char * what )const 223{ 224logDebug (u8"%s: length %zu, maxAbsDiff = %g, avgDiffSquared = %g" ,what ,length ,maxAbsDiff ,avgDiffSquared ); 225} 226void DirectCompute ::sTensorDiff::const 227{ 228logDebug (u8"%zu elements, maxAbsDiff = %g, avgDiffSquared = %g" ,length ,maxAbsDiff ,avgDiffSquared ); 229} 230 231HRESULT DirectCompute ::dbgWriteBinaryFile (LPCTSTR fileName ,const void * rsi ,size_t cb ) 232{ 233CPath path ; 234path .m_strPath = LR"(C:\Temp\2remove\Whisper)" ; 235path .Append (fileName ); 236 237CAtlFile file ; 238CHECK (file .Create (path ,GENERIC_WRITE ,0 ,CREATE_ALWAYS ) ); 239CHECK (file .Write (rsi , (DWORD )cb ) ); 240CHECK (file .Flush () ); 241return S_OK ; 242} 243 244#include "Tensor.h" 245 246sTensorDiff DirectCompute ::computeDiff (const Tensor & a ,const Tensor & b ) 247{ 248assert (isSameShapeAndLayout (a ,b ) ); 249const eDataType dt = a .getType (); 250assert (dt == b .getType () ); 251switch (dt ) 252 { 253case eDataType::FP32 : 254 { 255 std::vector < float > v1 ,v2 ; 256a .download (v1 ); 257b .download (v2 ); 258assert (v1 .size ()== v2 .size () ); 259#if 0 260const size_t firstZero = std::find (v2 .begin (),v2 .end (),0.0f )- v2 .begin (); 261 262 std::vector < float > delta ; 263delta .resize (v1 .size () ); 264for (size_t i = 0 ;i < v1 .size ();i ++ ) 265delta [i ]= std::abs (v1 [i ]- v2 [i ] ); 266const size_t maxIndex = std::max_element (delta .begin (),delta .end () )- delta .begin (); 267#endif 268return computeDiff (v1 .data (),v2 .data (),v1 .size () ); 269 } 270 } 271throw E_NOTIMPL ; 272} 273 274using namespace DirectCompute ; 275 276void PrintUniqueTensorSizes ::printImpl (const std::array < uint32_t ,8 >& a ) 277{ 278auto pair = set .emplace (a ); 279if ( !pair .second ) 280return ;// was already there 281 282const __m128i rhs = _mm_loadu_si128 ( (const __m128i * ) (& a [4 ] ) ); 283 284if (_mm_testz_si128 (rhs ,rhs ) ) 285 { 286logDebug (u8"%s: [ %i, %i, %i, %i ]" ,what , 287a [0 ],a [1 ],a [2 ],a [3 ] ); 288 } 289else 290 { 291logDebug (u8"%s: [ %i, %i, %i, %i ], [ %i, %i, %i, %i ]" ,what , 292a [0 ],a [1 ],a [2 ],a [3 ],a [4 ],a [5 ],a [6 ],a [7 ] ); 293 } 294} 295 296void PrintUniqueTensorSizes ::const Tensor & lhs ,const Tensor & rhs ) 297{ 298 std::array < uint32_t ,8 > arr ; 299__m128i * const rdi = (__m128i * )arr .data (); 300_mm_storeu_si128 (rdi ,lhs .sizeVec () ); 301_mm_storeu_si128 (rdi + 1 ,rhs .sizeVec () ); 302 303printImpl (arr ); 304} 305 306void PrintUniqueTensorSizes ::const int * lhs ,const int * rhs ) 307{ 308 std::array < uint32_t ,8 > arr ; 309__m128i * const rdi = (__m128i * )arr .data (); 310_mm_storeu_si128 (rdi ,load16 (lhs ) ); 311_mm_storeu_si128 (rdi + 1 ,load16 (rhs ) ); 312 313printImpl (arr ); 314} 315 316void PrintUniqueTensorSizes ::const Tensor & lhs ) 317{ 318 std::array < uint32_t ,8 > arr ; 319__m128i * const rdi = (__m128i * )arr .data (); 320_mm_storeu_si128 (rdi ,lhs .sizeVec () ); 321_mm_storeu_si128 (rdi + 1 ,_mm_setzero_si128 () ); 322 323printImpl (arr ); 324} 325 326#include "testUtilsC.h" 327 328void printUniqueTensorSize (const char * name ,const int * lhs ,const int * rhs ) 329{ 330using TS = DirectCompute ::PrintUniqueTensorSizes ; 331static std::unordered_map < std::string ,TS > map ; 332TS & ts = map .try_emplace (name ,name ).first -> second ; 333ts .lhs ,rhs ); 334}