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
37.4 KiB1070 linesraw
1#include "stdafx.h"
2#include "ML/Tensor.h"
3#include "API/iMediaFoundation.cl.h"
4#include "API/iContext.cl.h"
5#include "API/sFullParams.h"
6#include "Utils/ReadStream.h"
7#include "ML/testUtils.h"
8#include "Utils/Trace/tracing.h"
9#include "modelFactory.h"
10#if BUILD_BOTH_VERSIONS
11
12namespace
13{
14	LPCTSTR traceFilePath = LR"(C:\Temp\2remove\Whisper\ref.bin)";
15	using ComLight::iReadStream;
16}
17
18struct whisper_context;
19struct ggml_tensor;
20
21class GpuEncTest
22{
23	DirectCompute::Tensor mel, gpuResult;
24
25	DirectCompute::Tensor tempGpu;
26	const ggml_tensor* tempRef = nullptr;
27public:
28	GpuEncTest( const whisper_context& wctx, const int mel_offset );
29	void compare( const ggml_tensor* expected ) const;
30	void compareMel( const ggml_tensor* expected ) const;
31};
32
33class GpuDecTest
34{
35	std::vector<float> logits, probs;
36	const ggml_tensor* tempRef = nullptr;
37
38public:
39
40	GpuDecTest( const whisper_context& wctx, const int* tokens, const int n_tokens, const int n_past );
41
42	void postpone( const ggml_tensor* t );
43	void comparePostponed();
44	void compare( const std::vector<float>& cpuLogits, const std::vector<float>& cpuProbs ) const;
45};
46
47static DirectCompute::Tensor gpuEncode( const whisper_context& wctx, const int mel_offset );
48
49#include "source/whisper.cpp"
50#include "API/iContext.cl.h"
51#include "../ComLightLib/comLightServer.h"
52#include "ML/mlStartup.h"
53#include "Whisper/WhisperContext.h"
54#include "Whisper/ModelLoader.h"
55#include "Whisper/WhisperModel.h"
56#include "source.compat/convertThings.h"
57
58namespace Whisper
59{
60	inline HRESULT isZero( int i )
61	{
62		return ( 0 == i ) ? S_OK : E_FAIL;
63	}
64
65	class Context : public ComLight::ObjectRoot<iContext>,
66		public iModel
67	{
68		virtual HRESULT COMLIGHTCALL isMultilingual() override final
69		{
70			return whisper_is_multilingual( &ctx ) ? S_OK : S_FALSE;
71		}
72		virtual const char* COMLIGHTCALL stringFromToken( whisper_token token ) override final
73		{
74			return whisper_token_to_str( &ctx, token );
75		}
76		virtual HRESULT COMLIGHTCALL getSpecialTokens( SpecialTokens& rdi )
77		{
78			rdi.TranscriptionEnd = whisper_token_eot( &ctx );
79			rdi.TranscriptionStart = whisper_token_sot( &ctx );
80			rdi.PreviousWord = whisper_token_prev( &ctx );
81			rdi.SentenceStart = whisper_token_solm( &ctx );
82			rdi.Not = whisper_token_not( &ctx );
83			rdi.TranscriptionBegin = whisper_token_beg( &ctx );
84			rdi.TaskTranslate = whisper_token_translate();
85			rdi.TaskTranscribe = whisper_token_transcribe();
86			return S_OK;
87		}
88
89		// Performance information
90		virtual HRESULT COMLIGHTCALL timingsPrint() override final
91		{
92			whisper_print_timings( &ctx );
93			return S_OK;
94		}
95		virtual HRESULT COMLIGHTCALL timingsReset() override final
96		{
97			whisper_reset_timings( &ctx );
98			return S_OK;
99		}
100
101		virtual HRESULT COMLIGHTCALL fullDefaultParams( eSamplingStrategy strategy, sFullParams* rdi )
102		{
103			static_assert( (int)eSamplingStrategy::Greedy == whisper_sampling_strategy::WHISPER_SAMPLING_GREEDY );
104			static_assert( (int)eSamplingStrategy::BeamSearch == whisper_sampling_strategy::WHISPER_SAMPLING_BEAM_SEARCH );
105			const whisper_sampling_strategy wss = (whisper_sampling_strategy)(int)strategy;
106			whisper_full_params wfp = whisper_full_default_params( wss );
107
108			*rdi = makeNewParams( wfp );
109			return S_OK;
110		}
111
112		HRESULT COMLIGHTCALL runFull( const sFullParams& params, const iAudioBuffer* buffer ) override final
113		{
114			whisper_full_params wfp = makeOldParams( params, this );
115			const float* const samples = buffer->getPcmMono();
116			const uint32_t n_samples = buffer->countSamples();
117			return isZero( whisper_full( &ctx, wfp, samples, (int)n_samples ) );
118		}
119
120		HRESULT COMLIGHTCALL runStreamed( const sFullParams& params, const sProgressSink& progress, const iAudioReader* reader ) override final
121		{
122			logError( u8"The CPU reference implementation doesn’t support streaming" );
123			return E_NOTIMPL;
124		}
125		HRESULT COMLIGHTCALL runCapture( const sFullParams& params, const sCaptureCallbacks& callbacks, const iAudioCapture* reader ) override final
126		{
127			logError( u8"The CPU reference implementation doesn’t support audio capture" );
128			return E_NOTIMPL;
129		}
130
131		HRESULT COMLIGHTCALL getResults( eResultFlags flags, iTranscribeResult** pp ) const override final
132		{
133			makeNewResults( &ctx, flags, pp );
134			return S_OK;
135		}
136
137		HRESULT loadImpl( iReadStream* stm );
138
139		virtual HRESULT COMLIGHTCALL createContext( iContext** pp ) override final
140		{
141			if( nullptr == pp )
142				return E_POINTER;
143			*pp = this;
144			( *pp )->AddRef();
145			return S_OK;
146		}
147
148		virtual HRESULT COMLIGHTCALL getModel( iModel** pp ) override final
149		{
150			if( nullptr == pp )
151				return E_POINTER;
152			*pp = this;
153			( *pp )->AddRef();
154			return S_OK;
155		}
156
157	public:
158
159		Context()
160		{
161			if( nullptr != traceFilePath )
162				Tracing::traceCreate( traceFilePath );
163		}
164
165		mutable whisper_context ctx;
166
167		HRESULT load( iReadStream* stm );
168
169		~Context()
170		{
171			Tracing::traceClose();
172
173			if( ctx.model.ctx )
174			{
175				ggml_free( ctx.model.ctx );
176				ctx.model.ctx = nullptr;
177			}
178			if( ctx.model.ctx_mem )
179			{
180				ggml_free( ctx.model.ctx_mem );
181				ctx.model.ctx_mem = nullptr;
182			}
183			if( ctx.buf_model )
184			{
185				delete ctx.buf_model;
186				ctx.buf_model = nullptr;
187			}
188		}
189
190		BEGIN_COM_MAP()
191			COM_INTERFACE_ENTRY( iModel );
192		END_COM_MAP()
193	};
194
195	inline HRESULT readBytes( iReadStream* stm, void* rdi, size_t cb )
196	{
197		if( cb > INT_MAX )
198			return DISP_E_OVERFLOW;
199		if( cb == 0 )
200			return S_FALSE;
201		int n;
202		CHECK( stm->read( rdi, (int)cb, n ) );
203		if( n != (int)cb )
204			return E_EOF;
205		return S_OK;
206	}
207
208	template<typename T>
209	inline HRESULT readStruct( iReadStream* stm, T& dest )
210	{
211		return readBytes( stm, &dest, sizeof( T ) );
212	}
213	template<typename E>
214	inline HRESULT readVector( iReadStream* stm, std::vector<E>& vec )
215	{
216		const size_t cb = sizeof( E ) * vec.size();
217		if( cb > 0 )
218			return readBytes( stm, vec.data(), cb );
219		return S_FALSE;
220	}
221
222	inline HRESULT readString( iReadStream* stm, std::string& str )
223	{
224		uint32_t len;
225		CHECK( readStruct( stm, len ) );
226		if( len > 0 )
227		{
228			str.resize( len );
229			return readBytes( stm, str.data(), len );
230		}
231		else
232		{
233			str.clear();
234			return S_FALSE;
235		}
236	}
237
238	// load the model from a ggml file
239	// file format:
240	//   - hparams
241	//   - pre-computed mel filters
242	//   - vocab
243	//   - weights
244	// see the convert-pt-to-ggml.py script for details
245	HRESULT Context::loadImpl( iReadStream* stm )
246	{
247		// WhisperModel wm;
248		// return wm.load( stm );
249
250		// Copy-pasted from whisper_model_load() function
251		auto& model = ctx.model;
252		auto& vocab = ctx.vocab;
253
254		// verify magic
255		{
256			uint32_t magic;
257			int cbRead;
258			CHECK( stm->read( &magic, 4, cbRead ) );
259			if( magic != 0x67676d6c )
260			{
261				logError( u8"Invalid model file, bad magic" );
262				return E_INVALIDARG;
263			}
264		}
265
266		//load hparams
267		{
268			auto& hparams = model.hparams;
269			CHECK( readStruct( stm, hparams ) );
270			assert( hparams.n_text_state == hparams.n_audio_state );
271
272			if( hparams.n_audio_layer == 4 )
273				model.type = e_model::MODEL_TINY;
274			if( hparams.n_audio_layer == 6 )
275				model.type = e_model::MODEL_BASE;
276			if( hparams.n_audio_layer == 12 )
277				model.type = e_model::MODEL_SMALL;
278			if( hparams.n_audio_layer == 24 )
279				model.type = e_model::MODEL_MEDIUM;
280			if( hparams.n_audio_layer == 32 )
281				model.type = e_model::MODEL_LARGE;
282
283			logDebug( u8"%s: n_vocab       = %d", __func__, hparams.n_vocab );
284			logDebug( u8"%s: n_audio_ctx   = %d", __func__, hparams.n_audio_ctx );
285			logDebug( u8"%s: n_audio_state = %d", __func__, hparams.n_audio_state );
286			logDebug( u8"%s: n_audio_head  = %d", __func__, hparams.n_audio_head );
287			logDebug( u8"%s: n_audio_layer = %d", __func__, hparams.n_audio_layer );
288			logDebug( u8"%s: n_text_ctx    = %d", __func__, hparams.n_text_ctx );
289			logDebug( u8"%s: n_text_state  = %d", __func__, hparams.n_text_state );
290			logDebug( u8"%s: n_text_head   = %d", __func__, hparams.n_text_head );
291			logDebug( u8"%s: n_text_layer  = %d", __func__, hparams.n_text_layer );
292			logDebug( u8"%s: n_mels        = %d", __func__, hparams.n_mels );
293			logDebug( u8"%s: f16           = %d", __func__, hparams.f16 );
294			logDebug( u8"%s: type          = %d", __func__, model.type );
295
296			ctx.buf_model = new std::vector<uint8_t>();
297			ctx.buf_model->resize( MEM_REQ_MODEL.at( model.type ) );
298			ctx.buf_memory.resize( MEM_REQ_MEMORY.at( model.type ) );
299			ctx.buf_compute.resize( std::max( MEM_REQ_ENCODE.at( model.type ), MEM_REQ_DECODE.at( model.type ) ) );
300			ctx.buf_compute_layer.resize( std::max( MEM_REQ_ENCODE_LAYER.at( model.type ), MEM_REQ_DECODE_LAYER.at( model.type ) ) );
301		}
302
303		// load mel filters
304		{
305			auto& filters = ctx.model.filters;
306			CHECK( readStruct( stm, filters.n_mel ) );
307			CHECK( readStruct( stm, filters.n_fft ) );
308			filters.data.resize( filters.n_mel * filters.n_fft );
309			CHECK( readVector( stm, filters.data ) );
310		}
311
312		// load vocab
313		{
314			int32_t n_vocab = 0;
315			CHECK( readStruct( stm, n_vocab ) );
316
317			//if (n_vocab != model.hparams.n_vocab) {
318			//    fprintf(stderr, "%s: invalid model file '%s' (bad vocab size %d != %d)\n",
319			//            __func__, fname.c_str(), n_vocab, model.hparams.n_vocab);
320			//    return false;
321			//}
322
323			std::string word;
324			for( int i = 0; i < n_vocab; i++ )
325			{
326				CHECK( readString( stm, word ) );
327				vocab.token_to_id[ word ] = i;
328				vocab.id_to_token[ i ] = word;
329			}
330
331			vocab.n_vocab = model.hparams.n_vocab;
332			if( vocab.is_multilingual() )
333			{
334				vocab.token_eot++;
335				vocab.token_sot++;
336				vocab.token_prev++;
337				vocab.token_solm++;
338				vocab.token_not++;
339				vocab.token_beg++;
340			}
341
342			if( n_vocab < model.hparams.n_vocab )
343			{
344				logDebug( u8"%s: adding %d extra tokens", __func__, model.hparams.n_vocab - n_vocab );
345				for( int i = n_vocab; i < model.hparams.n_vocab; i++ )
346				{
347					if( i > vocab.token_beg )
348						word = "[_TT_" + std::to_string( i - vocab.token_beg ) + "]";
349					else if( i == vocab.token_eot )
350						word = "[_EOT_]";
351					else if( i == vocab.token_sot )
352						word = "[_SOT_]";
353					else if( i == vocab.token_prev )
354						word = "[_PREV_]";
355					else if( i == vocab.token_not )
356						word = "[_NOT_]";
357					else if( i == vocab.token_beg )
358						word = "[_BEG_]";
359					else
360						word = "[_extra_token_" + std::to_string( i ) + "]";
361
362					vocab.token_to_id[ word ] = i;
363					vocab.id_to_token[ i ] = word;
364				}
365			}
366		}
367
368		{
369			// this is the total memory required to run the inference
370			const size_t mem_required =
371				ctx.buf_model->size() +
372				ctx.buf_memory.size() +
373				ctx.buf_compute.size() +
374				ctx.buf_compute_layer.size();
375			logDebug( u8"%s: mem_required  = %7.2f MB", __func__, mem_required / 1024.0 / 1024.0 );
376		}
377
378		// for the big tensors, we have the option to store the data in 16-bit floats
379		// in order to save memory and also to speed up the computation
380		const ggml_type wtype = model.hparams.f16 ? GGML_TYPE_F16 : GGML_TYPE_F32;
381
382		size_t ctx_size = 0;
383		size_t ctx_mem_size = 0;
384
385		{
386			const auto& hparams = model.hparams;
387
388			const int n_vocab = hparams.n_vocab;
389
390			const int n_audio_ctx = hparams.n_audio_ctx;
391			const int n_audio_state = hparams.n_audio_state;
392			const int n_audio_layer = hparams.n_audio_layer;
393
394			const int n_text_ctx = hparams.n_text_ctx;
395			const int n_text_state = hparams.n_text_state;
396			const int n_text_layer = hparams.n_text_layer;
397
398			const int n_mels = hparams.n_mels;
399
400			// encoder
401			{
402				// TODO: F16 .. maybe not?
403				ctx_size += n_audio_ctx * n_audio_state * ggml_type_size( GGML_TYPE_F32 ); // e_pe;
404
405				ctx_size += 3 * n_mels * n_audio_state * ggml_type_size( wtype );         // e_conv_1_w
406				ctx_size += n_audio_state * ggml_type_size( GGML_TYPE_F32 ); // e_conv_1_b
407
408				ctx_size += 3 * n_audio_state * n_audio_state * ggml_type_size( wtype );         // e_conv_2_w
409				ctx_size += n_audio_state * ggml_type_size( GGML_TYPE_F32 ); // e_conv_2_b
410
411				ctx_size += n_audio_state * ggml_type_size( GGML_TYPE_F32 ); // e_ln_w;
412				ctx_size += n_audio_state * ggml_type_size( GGML_TYPE_F32 ); // e_ln_b;
413			}
414
415			// decoder
416			{
417				// TODO: F16 .. maybe not?
418				ctx_size += n_text_ctx * n_text_state * ggml_type_size( GGML_TYPE_F32 ); // d_pe;
419
420				ctx_size += n_vocab * n_text_state * ggml_type_size( wtype ); // d_te;
421
422				ctx_size += n_text_state * ggml_type_size( GGML_TYPE_F32 ); // d_ln_w;
423				ctx_size += n_text_state * ggml_type_size( GGML_TYPE_F32 ); // d_ln_b;
424			}
425
426			// encoder layers
427			{
428				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_ln_w
429				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_ln_b
430
431				ctx_size += n_audio_layer * ( 4 * n_audio_state * n_audio_state * ggml_type_size( wtype ) );         // mlp_0_w
432				ctx_size += n_audio_layer * ( 4 * n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_0_b
433
434				ctx_size += n_audio_layer * ( 4 * n_audio_state * n_audio_state * ggml_type_size( wtype ) );         // mlp_1_w
435				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_1_b
436
437				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_0_w
438				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_0_b
439
440				ctx_size += n_audio_layer * ( n_audio_state * n_audio_state * ggml_type_size( wtype ) );         // attn_q_w
441				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_q_b
442
443				ctx_size += n_audio_layer * ( n_audio_state * n_audio_state * ggml_type_size( wtype ) ); // attn_k_w
444
445				ctx_size += n_audio_layer * ( n_audio_state * n_audio_state * ggml_type_size( wtype ) );         // attn_v_w
446				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_v_b
447
448				ctx_size += n_audio_layer * ( n_audio_state * n_audio_state * ggml_type_size( wtype ) );         // attn_ln_1_w
449				ctx_size += n_audio_layer * ( n_audio_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_1_b
450			}
451
452			// decoder layers
453			{
454				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_ln_w
455				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_ln_b
456
457				ctx_size += n_text_layer * ( 4 * n_text_state * n_text_state * ggml_type_size( wtype ) );         // mlp_0_w
458				ctx_size += n_text_layer * ( 4 * n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_0_b
459
460				ctx_size += n_text_layer * ( 4 * n_text_state * n_text_state * ggml_type_size( wtype ) );         // mlp_1_w
461				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // mlp_1_b
462
463				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_0_w
464				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_0_b
465
466				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // attn_q_w
467				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_q_b
468
469				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) ); // attn_k_w
470
471				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // attn_v_w
472				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_v_b
473
474				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // attn_ln_1_w
475				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // attn_ln_1_b
476				//
477				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // cross_attn_ln_0_w
478				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // cross_attn_ln_0_b
479
480				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // cross_attn_q_w
481				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // cross_attn_q_b
482
483				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) ); // cross_attn_k_w
484
485				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // cross_attn_v_w
486				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // cross_attn_v_b
487
488				ctx_size += n_text_layer * ( n_text_state * n_text_state * ggml_type_size( wtype ) );         // cross_attn_ln_1_w
489				ctx_size += n_text_layer * ( n_text_state * ggml_type_size( GGML_TYPE_F32 ) ); // cross_attn_ln_1_b
490			}
491
492			ctx_mem_size += n_text_layer * n_text_ctx * n_text_state * ggml_type_size( GGML_TYPE_F16 ); // memory_k
493			ctx_mem_size += n_text_layer * n_text_ctx * n_text_state * ggml_type_size( GGML_TYPE_F16 ); // memory_v
494
495			ctx_mem_size += n_text_layer * n_audio_ctx * n_text_state * ggml_type_size( GGML_TYPE_F16 ); // memory_cross_k
496			ctx_mem_size += n_text_layer * n_audio_ctx * n_text_state * ggml_type_size( GGML_TYPE_F16 ); // memory_cross_v
497
498			ctx_size += ( 15 + 15 * n_audio_layer + 24 * n_text_layer ) * 256; // object overhead
499
500			logDebug( u8"%s: ggml ctx size = %7.2f MB", __func__, ctx_size / ( 1024.0 * 1024.0 ) );
501		}
502
503		// create the ggml context
504		{
505			struct ggml_init_params params;
506			params.mem_size = ctx.buf_model->size();
507			params.mem_buffer = ctx.buf_model->data();
508
509			model.ctx = ggml_init( params );
510			if( !model.ctx )
511			{
512				logError( u8"%s: ggml_init() failed", __func__ );
513				return E_INVALIDARG;
514			}
515		}
516
517		std::map<std::string, struct ggml_tensor*> tensors;
518		DirectCompute::ModelLoader loader{ model.hparams.n_audio_layer, model.hparams.n_text_layer };
519
520		// prepare memory for the weights
521		{
522			auto& ctx = model.ctx;
523			const auto& hparams = model.hparams;
524			const int n_vocab = hparams.n_vocab;
525
526			const int n_audio_ctx = hparams.n_audio_ctx;
527			const int n_audio_state = hparams.n_audio_state;
528			const int n_audio_layer = hparams.n_audio_layer;
529
530			const int n_text_ctx = hparams.n_text_ctx;
531			const int n_text_state = hparams.n_text_state;
532			const int n_text_layer = hparams.n_text_layer;
533
534			const int n_mels = hparams.n_mels;
535
536			model.layers_encoder.resize( n_audio_layer );
537			model.layers_decoder.resize( n_text_layer );
538
539			// encoder
540			{
541				model.e_pe = ggml_new_tensor_2d( ctx, GGML_TYPE_F32, n_audio_state, n_audio_ctx );
542				loader.add( model.e_pe, loader.model.enc.positionalEmbedding );
543
544				model.e_conv_1_w = ggml_new_tensor_3d( ctx, wtype, 3, n_mels, n_audio_state );
545				model.e_conv_1_b = ggml_new_tensor_2d( ctx, GGML_TYPE_F32, 1, n_audio_state );
546				loader.add( model.e_conv_1_w, model.e_conv_1_b, loader.model.enc.conv1 );
547
548				model.e_conv_2_w = ggml_new_tensor_3d( ctx, wtype, 3, n_audio_state, n_audio_state );
549				model.e_conv_2_b = ggml_new_tensor_2d( ctx, GGML_TYPE_F32, 1, n_audio_state );
550				loader.add( model.e_conv_2_w, model.e_conv_2_b, loader.model.enc.conv2 );
551
552				model.e_ln_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
553				model.e_ln_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
554				loader.add( model.e_ln_w, model.e_ln_b, loader.model.enc.lnPost );
555
556				// map by name
557				tensors[ "encoder.positional_embedding" ] = model.e_pe;
558
559				tensors[ "encoder.conv1.weight" ] = model.e_conv_1_w;
560				tensors[ "encoder.conv1.bias" ] = model.e_conv_1_b;
561
562				tensors[ "encoder.conv2.weight" ] = model.e_conv_2_w;
563				tensors[ "encoder.conv2.bias" ] = model.e_conv_2_b;
564
565				tensors[ "encoder.ln_post.weight" ] = model.e_ln_w;
566				tensors[ "encoder.ln_post.bias" ] = model.e_ln_b;
567
568				for( int i = 0; i < n_audio_layer; ++i )
569				{
570					auto& layer = model.layers_encoder[ i ];
571					auto& gpu = loader.model.enc.layers[ i ];
572
573					layer.mlp_ln_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
574					layer.mlp_ln_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
575					loader.add( layer.mlp_ln_w, layer.mlp_ln_b, gpu.mlpLn );
576
577					layer.mlp_0_w = ggml_new_tensor_2d( ctx, wtype, n_audio_state, 4 * n_audio_state );
578					layer.mlp_0_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, 4 * n_audio_state );
579					loader.add( layer.mlp_0_w, layer.mlp_0_b, gpu.mlp0 );
580
581					layer.mlp_1_w = ggml_new_tensor_2d( ctx, wtype, 4 * n_audio_state, n_audio_state );
582					layer.mlp_1_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
583					loader.add( layer.mlp_1_w, layer.mlp_1_b, gpu.mlp1 );
584
585					layer.attn_ln_0_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
586					layer.attn_ln_0_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
587					loader.add( layer.attn_ln_0_w, layer.attn_ln_0_b, gpu.attnLn0 );
588
589					layer.attn_q_w = ggml_new_tensor_2d( ctx, wtype, n_audio_state, n_audio_state );
590					layer.attn_q_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
591					loader.add( layer.attn_q_w, layer.attn_q_b, gpu.attnQuery );
592
593					layer.attn_k_w = ggml_new_tensor_2d( ctx, wtype, n_audio_state, n_audio_state );
594					loader.add( layer.attn_k_w, gpu.attnKey );
595
596					layer.attn_v_w = ggml_new_tensor_2d( ctx, wtype, n_audio_state, n_audio_state );
597					layer.attn_v_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
598					loader.add( layer.attn_v_w, layer.attn_v_b, gpu.attnValue );
599
600					layer.attn_ln_1_w = ggml_new_tensor_2d( ctx, wtype, n_audio_state, n_audio_state );
601					layer.attn_ln_1_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_audio_state );
602					loader.add( layer.attn_ln_1_w, layer.attn_ln_1_b, gpu.attnLn1 );
603
604					// map by name
605					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp_ln.weight" ] = layer.mlp_ln_w;
606					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp_ln.bias" ] = layer.mlp_ln_b;
607
608					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp.0.weight" ] = layer.mlp_0_w;
609					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp.0.bias" ] = layer.mlp_0_b;
610
611					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp.2.weight" ] = layer.mlp_1_w;
612					tensors[ "encoder.blocks." + std::to_string( i ) + ".mlp.2.bias" ] = layer.mlp_1_b;
613
614					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn_ln.weight" ] = layer.attn_ln_0_w;
615					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn_ln.bias" ] = layer.attn_ln_0_b;
616
617					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.query.weight" ] = layer.attn_q_w;
618					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.query.bias" ] = layer.attn_q_b;
619
620					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.key.weight" ] = layer.attn_k_w;
621
622					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.value.weight" ] = layer.attn_v_w;
623					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.value.bias" ] = layer.attn_v_b;
624
625					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.out.weight" ] = layer.attn_ln_1_w;
626					tensors[ "encoder.blocks." + std::to_string( i ) + ".attn.out.bias" ] = layer.attn_ln_1_b;
627				}
628			}
629
630			// decoder
631			{
632				model.d_pe = ggml_new_tensor_2d( ctx, GGML_TYPE_F32, n_text_state, n_text_ctx );
633				loader.add( model.d_pe, loader.model.dec.positionalEmbedding );
634
635				model.d_te = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_vocab );
636				loader.add( model.d_te, loader.model.dec.tokenEmbedding );
637
638				model.d_ln_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
639				model.d_ln_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
640				loader.add( model.d_ln_w, model.d_ln_b, loader.model.dec.ln );
641
642				// map by name
643				tensors[ "decoder.positional_embedding" ] = model.d_pe;
644
645				tensors[ "decoder.token_embedding.weight" ] = model.d_te;
646
647				tensors[ "decoder.ln.weight" ] = model.d_ln_w;
648				tensors[ "decoder.ln.bias" ] = model.d_ln_b;
649
650				for( int i = 0; i < n_text_layer; ++i ) {
651					auto& layer = model.layers_decoder[ i ];
652					auto& gpu = loader.model.dec.layers[ i ];
653
654					layer.mlp_ln_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
655					layer.mlp_ln_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
656					loader.add( layer.mlp_ln_w, layer.mlp_ln_b, gpu.mlpLn );
657
658					layer.mlp_0_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, 4 * n_text_state );
659					layer.mlp_0_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, 4 * n_text_state );
660					loader.add( layer.mlp_0_w, layer.mlp_0_b, gpu.mlp0 );
661
662					layer.mlp_1_w = ggml_new_tensor_2d( ctx, wtype, 4 * n_text_state, n_text_state );
663					layer.mlp_1_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
664					loader.add( layer.mlp_1_w, layer.mlp_1_b, gpu.mlp1 );
665
666					layer.attn_ln_0_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
667					layer.attn_ln_0_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
668					loader.add( layer.attn_ln_0_w, layer.attn_ln_0_b, gpu.attnLn0 );
669
670					layer.attn_q_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
671					layer.attn_q_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
672					loader.add( layer.attn_q_w, layer.attn_q_b, gpu.attnQuery );
673
674					layer.attn_k_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
675					loader.add( layer.attn_k_w, gpu.attnKey );
676
677					layer.attn_v_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
678					layer.attn_v_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
679					loader.add( layer.attn_v_w, layer.attn_v_b, gpu.attnValue );
680
681					layer.attn_ln_1_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
682					layer.attn_ln_1_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
683					loader.add( layer.attn_ln_1_w, layer.attn_ln_1_b, gpu.attnLn1 );
684
685					layer.cross_attn_ln_0_w = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
686					layer.cross_attn_ln_0_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
687					loader.add( layer.cross_attn_ln_0_w, layer.cross_attn_ln_0_b, gpu.crossAttnLn0 );
688
689					layer.cross_attn_q_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
690					layer.cross_attn_q_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
691					loader.add( layer.cross_attn_q_w, layer.cross_attn_q_b, gpu.crossAttnQuery );
692
693					layer.cross_attn_k_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
694					loader.add( layer.cross_attn_k_w, gpu.crossAttnKey );
695
696					layer.cross_attn_v_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
697					layer.cross_attn_v_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
698					loader.add( layer.cross_attn_v_w, layer.cross_attn_v_b, gpu.crossAttnValue );
699
700					layer.cross_attn_ln_1_w = ggml_new_tensor_2d( ctx, wtype, n_text_state, n_text_state );
701					layer.cross_attn_ln_1_b = ggml_new_tensor_1d( ctx, GGML_TYPE_F32, n_text_state );
702					loader.add( layer.cross_attn_ln_1_w, layer.cross_attn_ln_1_b, gpu.crossAttnLn1 );
703
704					// map by name
705					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp_ln.weight" ] = layer.mlp_ln_w;
706					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp_ln.bias" ] = layer.mlp_ln_b;
707
708					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp.0.weight" ] = layer.mlp_0_w;
709					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp.0.bias" ] = layer.mlp_0_b;
710
711					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp.2.weight" ] = layer.mlp_1_w;
712					tensors[ "decoder.blocks." + std::to_string( i ) + ".mlp.2.bias" ] = layer.mlp_1_b;
713
714					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn_ln.weight" ] = layer.attn_ln_0_w;
715					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn_ln.bias" ] = layer.attn_ln_0_b;
716
717					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.query.weight" ] = layer.attn_q_w;
718					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.query.bias" ] = layer.attn_q_b;
719
720					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.key.weight" ] = layer.attn_k_w;
721
722					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.value.weight" ] = layer.attn_v_w;
723					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.value.bias" ] = layer.attn_v_b;
724
725					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.out.weight" ] = layer.attn_ln_1_w;
726					tensors[ "decoder.blocks." + std::to_string( i ) + ".attn.out.bias" ] = layer.attn_ln_1_b;
727
728					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn_ln.weight" ] = layer.cross_attn_ln_0_w;
729					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn_ln.bias" ] = layer.cross_attn_ln_0_b;
730
731					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.query.weight" ] = layer.cross_attn_q_w;
732					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.query.bias" ] = layer.cross_attn_q_b;
733
734					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.key.weight" ] = layer.cross_attn_k_w;
735
736					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.value.weight" ] = layer.cross_attn_v_w;
737					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.value.bias" ] = layer.cross_attn_v_b;
738
739					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.out.weight" ] = layer.cross_attn_ln_1_w;
740					tensors[ "decoder.blocks." + std::to_string( i ) + ".cross_attn.out.bias" ] = layer.cross_attn_ln_1_b;
741				}
742			}
743		}
744
745		// create the ggml memory context
746		{
747			struct ggml_init_params params;
748			params.mem_size = ctx.buf_memory.size();
749			params.mem_buffer = ctx.buf_memory.data();
750			model.ctx_mem = ggml_init( params );
751			if( !model.ctx_mem )
752			{
753				logError( u8"%s: ggml_init() failed", __func__ );
754				return E_INVALIDARG;
755			}
756		}
757
758		// key + value memory
759		{
760			auto& ctx = model.ctx_mem;
761
762			const auto& hparams = model.hparams;
763
764			const int n_text_state = hparams.n_text_state;
765			const int n_text_layer = hparams.n_text_layer;
766			const int n_text_ctx = hparams.n_text_ctx;
767
768			// key/value memory for the self-attention layer
769			{
770				const int n_mem = n_text_layer * n_text_ctx;
771				const int n_elements = n_text_state * n_mem;
772
773				model.memory_k = ggml_new_tensor_1d( ctx, GGML_TYPE_F16, n_elements );
774				model.memory_v = ggml_new_tensor_1d( ctx, GGML_TYPE_F16, n_elements );
775			}
776
777			// key/value memory for the cross-attention layer
778			{
779				const int n_audio_ctx = hparams.n_audio_ctx;
780
781				const int n_mem = n_text_layer * n_audio_ctx;
782				const int n_elements = n_text_state * n_mem;
783
784				model.memory_cross_k = ggml_new_tensor_1d( ctx, GGML_TYPE_F16, n_elements );
785				model.memory_cross_v = ggml_new_tensor_1d( ctx, GGML_TYPE_F16, n_elements );
786			}
787
788			const size_t memory_size =
789				ggml_nbytes( model.memory_k ) + ggml_nbytes( model.memory_v ) +
790				ggml_nbytes( model.memory_cross_k ) + ggml_nbytes( model.memory_cross_v );
791
792			logDebug( u8"%s: memory size   = %7.2f MB", __func__, memory_size / 1024.0 / 1024.0 );
793		}
794
795		// load weights
796		{
797			size_t total_size = 0;
798			int n_loaded = 0;
799			std::string name;
800
801			while( true )
802			{
803				int32_t n_dims;
804				int32_t length;
805				int32_t ftype;
806
807				HRESULT hr = readStruct( stm, n_dims );
808				if( hr == E_EOF )
809					break;
810				CHECK( hr );
811				CHECK( readStruct( stm, length ) );
812				CHECK( readStruct( stm, ftype ) );
813
814				int32_t nelements = 1;
815				int32_t ne[ 3 ] = { 1, 1, 1 };
816				for( int i = 0; i < n_dims; ++i )
817				{
818					CHECK( readStruct( stm, ne[ i ] ) );
819					nelements *= ne[ i ];
820				}
821
822				name.resize( length );
823				CHECK( readBytes( stm, name.data(), length ) );
824
825				if( tensors.find( name.data() ) == tensors.end() )
826				{
827					logError( u8"%s: unknown tensor '%s' in model file", __func__, name.data() );
828					return E_INVALIDARG;
829				}
830
831				auto tensor = tensors[ name.data() ];
832				if( ggml_nelements( tensor ) != nelements )
833				{
834					logError( u8"%s: tensor '%s' has wrong size in model file", __func__, name.data() );
835					return E_INVALIDARG;
836				}
837
838				if( tensor->ne[ 0 ] != ne[ 0 ] || tensor->ne[ 1 ] != ne[ 1 ] || tensor->ne[ 2 ] != ne[ 2 ] )
839				{
840					logError( u8"%s: tensor '%s' has wrong shape in model file: got [%d, %d, %d], expected [%d, %d, %d]",
841						__func__, name.data(), tensor->ne[ 0 ], tensor->ne[ 1 ], tensor->ne[ 2 ], ne[ 0 ], ne[ 1 ], ne[ 2 ] );
842					return E_INVALIDARG;
843				}
844
845				const size_t bpe = ( ftype == 0 ) ? sizeof( float ) : sizeof( ggml_fp16_t );
846
847				if( nelements * bpe != ggml_nbytes( tensor ) )
848				{
849					logError( u8"%s: tensor '%s' has wrong size in model file: got %zu, expected %zu",
850						__func__, name.data(), ggml_nbytes( tensor ), nelements * bpe );
851					return E_INVALIDARG;
852				}
853
854				CHECK( readBytes( stm, tensor->data, ggml_nbytes( tensor ) ) );
855
856				//printf("%48s - [%5d, %5d, %5d], type = %6s, %6.2f MB\n", name.data(), ne[0], ne[1], ne[2], ftype == 0 ? "float" : "f16", ggml_nbytes(tensor)/1024.0/1024.0);
857				total_size += ggml_nbytes( tensor );
858				n_loaded++;
859				// loader.tryLoad( tensor );
860			}
861
862			logDebug( u8"%s: model size    = %7.2f MB", __func__, total_size / 1024.0 / 1024.0 );
863			if( n_loaded == 0 )
864			{
865				logError( u8"%s: no tensors loaded from model file", __func__ );
866				return E_INVALIDARG;
867			}
868			else if( n_loaded != (int)tensors.size() )
869			{
870				logError( u8"%s: not all tensors loaded from model file - expected %zu, got %d", __func__, tensors.size(), n_loaded );
871				return E_INVALIDARG;
872			}
873			model.n_loaded = n_loaded;
874		}
875
876		return S_OK;
877	}
878
879	HRESULT Context::load( iReadStream* stm )
880	{
881		const int64_t t_start_us = ggml_time_us();
882		ctx.t_start_us = t_start_us;
883		HRESULT hr = loadImpl( stm );
884		ctx.t_load_us = ggml_time_us() - t_start_us;
885		return hr;
886	}
887
888	HRESULT __stdcall loadReferenceCpuModel( const wchar_t* path, iModel** pp )
889	{
890		if( nullptr == path || nullptr == pp )
891			return E_POINTER;
892
893		ComLight::Object<ReadStream> stream;
894		CHECK( stream.open( path ) );
895
896		ggml_time_init();
897		ComLight::CComPtr<ComLight::Object<Context>> obj;
898		CHECK( ComLight::Object<Context>::create( obj ) );
899		CHECK( obj->load( &stream ) );
900		obj.detach( pp );
901		return S_OK;
902	}
903}
904
905#include "Whisper/WhisperContext.h"
906#include "Whisper/ModelBuffers.h"
907#include "ML/testUtils.h"
908using namespace DirectCompute;
909
910static DirectCompute::Tensor gpuEncode( const whisper_context& wctx, const int mel_offset )
911{
912	return DirectCompute::Tensor{};
913#if 0
914	using namespace DirectCompute;
915	WhisperContext& ctx = WhisperContext::current();
916
917	Tensor cur;
918	sEncodeParams whisperParams;
919	const auto& mel_inp = wctx.mel;
920	{
921		const auto& model = wctx.model;
922		const auto& hparams = model.hparams;
923		whisperParams.n_len = (uint32_t)mel_inp.n_len;
924		whisperParams.n_mel = (uint32_t)mel_inp.n_mel;
925
926		const int n_ctx = wctx.exp_n_audio_ctx > 0 ? wctx.exp_n_audio_ctx : wctx.model.hparams.n_audio_ctx;
927		assert( n_ctx > 0 );
928		whisperParams.n_ctx = (uint32_t)n_ctx;
929
930		const int n_mels = hparams.n_mels;
931		assert( n_mels > 0 );
932		whisperParams.n_mels = (uint32_t)n_mels;
933
934		assert( mel_offset >= 0 );
935		whisperParams.mel_offset = (uint32_t)mel_offset;
936
937		const int layersCount = hparams.n_audio_layer;
938		assert( layersCount > 0 );
939		whisperParams.layersCount = (uint32_t)layersCount;
940
941		const int n_state = hparams.n_audio_state;
942		const int n_head = hparams.n_audio_head;
943		assert( n_state >= 0 );
944		assert( n_head >= 0 );
945
946		whisperParams.n_state = (uint32_t)n_state;
947		whisperParams.n_head = (uint32_t)n_head;
948
949		int n_audio_ctx = hparams.n_audio_ctx;
950		assert( n_audio_ctx > 0 );
951		whisperParams.n_audio_ctx = (uint32_t)n_audio_ctx;
952
953		int n_text_state = hparams.n_text_state;
954		assert( n_text_state > 0 );
955		whisperParams.n_text_state = (uint32_t)n_text_state;
956
957		int n_text_layer = hparams.n_text_layer;
958		assert( n_text_layer > 0 );
959		whisperParams.n_text_layer = (uint32_t)n_text_layer;
960
961		int n_text_ctx = hparams.n_text_ctx;
962		assert( n_text_ctx > 0 );
963		whisperParams.n_text_ctx = (uint32_t)n_text_ctx;
964	}
965
966	return ctx.encode( mel_inp.data, whisperParams );
967#endif
968}
969
970GpuEncTest::GpuEncTest( const whisper_context& wctx, const int mel_offset )
971{
972	return;
973	gpuResult = gpuEncode( wctx, mel_offset );
974}
975
976void GpuEncTest::compare( const ggml_tensor* expected ) const
977{
978	return;
979	WhisperContext& ctx = WhisperContext::current();
980	ctx.dbgPrintDifference( expected, gpuResult, "GpuEncTest.compare", false );
981}
982
983void GpuEncTest::compareMel( const ggml_tensor* expected ) const
984{
985	return;
986	WhisperContext& ctx = WhisperContext::current();
987	ctx.dbgPrintDifference( expected, mel, "GpuEncTest.compareMel", false );
988}
989
990/*
991void GpuEncTest::comparePostponed()
992{
993	if( nullptr == tempRef )
994		return;
995
996	WhisperContext& ctx = WhisperContext::current();
997	ctx.dbgPrintDifference( tempRef, tempGpu, "comparePostponed" );
998	tempRef = nullptr;
999} */
1000
1001__declspec( noinline ) GpuDecTest::GpuDecTest( const whisper_context& wctx, const int* tokens, const int n_tokens, const int n_past )
1002{
1003#if 1
1004	return;
1005#else
1006	sDecodeParams dp;
1007	{
1008		WhisperContext& ctx = WhisperContext::current();
1009		const auto& model = wctx.model;
1010		const auto& hparams = model.hparams;
1011		dp.n_state = hparams.n_text_state;
1012		dp.n_head = hparams.n_text_head;
1013		dp.n_ctx = hparams.n_text_ctx;
1014		dp.n_past = n_past;
1015		dp.M = wctx.exp_n_audio_ctx > 0 ? wctx.exp_n_audio_ctx : hparams.n_audio_ctx;
1016		dp.n_text_layer = hparams.n_text_layer;
1017		dp.n_vocab = hparams.n_vocab;
1018	}
1019
1020	WhisperContext& ctx = WhisperContext::current();
1021	ctx.decode( tokens, n_tokens, dp, logits, probs );
1022#endif
1023}
1024
1025void __declspec( noinline ) GpuDecTest::compare( const std::vector<float>& cpuLogits, const std::vector<float>& cpuProbs ) const
1026{
1027	return;
1028
1029	if( cpuLogits.size() != logits.size() )
1030	{
1031		printf( "GpuDecTest.compare fail, size different\n" );
1032		return;
1033	}
1034
1035	computeDiff( logits.data(), cpuLogits.data(), logits.size() ).print( "GpuDecTest.compare logits" );
1036	computeDiff( probs.data(), cpuProbs.data(), probs.size() ).print( "GpuDecTest.compare probs" );
1037}
1038
1039void __declspec( noinline ) GpuDecTest::postpone( const ggml_tensor* t )
1040{
1041	return;
1042
1043	if( nullptr != tempRef )
1044		return;
1045	tempRef = t;
1046}
1047
1048void __declspec( noinline ) GpuDecTest::comparePostponed()
1049{
1050#if 1
1051	return;
1052#else
1053	if( nullptr == tempRef )
1054		return;
1055	WhisperContext& ctx = WhisperContext::current();
1056	ID3D11ShaderResourceView* srv = ctx.dbgDecodeTest;
1057	if( nullptr == srv )
1058		return;
1059
1060	ctx.dbgPrintDifference( tempRef, ctx.dbgDecodeTest, "GpuDecTest.comparePostponed" );
1061	tempRef = nullptr;
1062#endif
1063}
1064#else
1065HRESULT __stdcall Whisper::loadReferenceCpuModel( const wchar_t* path, Whisper::iModel** pp )
1066{
1067	logError( u8"This build of the DLL doesn’t implement the reference CPU-running Whisper model." );
1068	return E_NOTIMPL;
1069}
1070#endif