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
20.9 KiB737 linesraw
1#pragma once
2
3//
4// GGML Tensor Library
5//
6// This documentation is still a work in progress.
7// If you wish some specific topics to be covered, feel free to drop a comment:
8//
9//   https://github.com/ggerganov/whisper.cpp/issues/40
10//
11// ## Overview
12//
13// This library implements:
14//
15//  - a set of tensor operations
16//  - automatic differentiation
17//  - basic optimization algorithms
18//
19// The aim of this library is to provide a minimalistic approach for various machine learning tasks. This includes,
20// but is not limited to, the following:
21//
22//  - linear regression
23//  - support vector machines
24//  - neural networks
25//
26// The library allows the user to define a certain function using the available tensor operations. This function
27// definition is represented internally via a computation graph. Each tensor operation in the function definition
28// corresponds to a node in the graph. Having the computation graph defined, the user can choose to compute the
29// function's value and/or its gradient with respect to the input variables. Optionally, the function can be optimized
30// using one of the available optimization algorithms.
31//
32// For example, here we define the function: f(x) = a*x^2 + b
33//
34//   {
35//       struct ggml_init_params params = {
36//           .mem_size   = 16*1024*1024,
37//           .mem_buffer = NULL,
38//       };
39//
40//       // memory allocation happens here
41//       struct ggml_context * ctx = ggml_init(params);
42//
43//       struct ggml_tensor * x = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
44//
45//       ggml_set_param(ctx, x); // x is an input variable
46//
47//       struct ggml_tensor * a  = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
48//       struct ggml_tensor * b  = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, 1);
49//       struct ggml_tensor * x2 = ggml_mul(ctx, x, x);
50//       struct ggml_tensor * f  = ggml_add(ctx, ggml_mul(ctx, a, x2), b);
51//
52//       ...
53//   }
54//
55// Notice that the function definition above does not involve any actual computation. The computation is performed only
56// when the user explicitly requests it. For example, to compute the function's value at x = 2.0:
57//
58//   {
59//       ...
60//
61//       struct ggml_cgraph gf = ggml_build_forward(f);
62//
63//       // set the input variable and parameter values
64//       ggml_set_f32(x, 2.0f);
65//       ggml_set_f32(a, 3.0f);
66//       ggml_set_f32(b, 4.0f);
67//
68//       ggml_graph_compute(ctx0, &gf);
69//
70//       printf("f = %f\n", ggml_get_f32_1d(f, 0));
71//
72//       ...
73//   }
74//
75// The actual computation is performed in the ggml_graph_compute() function.
76//
77// The ggml_new_tensor_...() functions create new tensors. They are allocated in the memory buffer provided to the
78// ggml_init() function. You have to be careful not to exceed the memory buffer size. Therefore, you have to know
79// in advance how much memory you need for your computation. Alternatively, you can allocate a large enough memory
80// and after defining the computation graph, call the ggml_used_mem() function to find out how much memory was
81// actually needed.
82//
83// The ggml_set_param() function marks a tensor as an input variable. This is used by the automatic
84// differentiation and optimization algorithms.
85//
86// The described approach allows to define the function graph once and then compute its forward or backward graphs
87// multiple times. All computations will use the same memory buffer allocated in the ggml_init() function. This way
88// the user can avoid the memory allocation overhead at runtime.
89//
90// The library supports multi-dimensional tensors - up to 4 dimensions. The FP16 and FP32 data types are first class
91// citizens, but in theory the library can be extended to support FP8 and integer data types.
92//
93// Each tensor operation produces a new tensor. Initially the library was envisioned to support only the use of unary
94// and binary operations. Most of the available operations fall into one of these two categories. With time, it became
95// clear that the library needs to support more complex operations. The way to support these operations is not clear
96// yet, but a few examples are demonstrated in the following operations:
97//
98//   - ggml_permute()
99//   - ggml_conv_1d_1s()
100//   - ggml_conv_1d_2s()
101//
102// For each tensor operator, the library implements a forward and backward computation function. The forward function
103// computes the output tensor value given the input tensor values. The backward function computes the adjoint of the
104// input tensors given the adjoint of the output tensor. For a detailed explanation of what this means, take a
105// calculus class, or watch the following video:
106//
107//   What is Automatic Differentiation?
108//   https://www.youtube.com/watch?v=wG_nF1awSSY
109//
110//
111// ## Tensor data (struct ggml_tensor)
112//
113// The tensors are stored in memory via the ggml_tensor struct. The structure provides information about the size of
114// the tensor, the data type, and the memory buffer where the tensor data is stored. Additionally, it contains
115// pointers to the "source" tensors - i.e. the tensors that were used to compute the current tensor. For example:
116//
117//   {
118//       struct ggml_tensor * c = ggml_add(ctx, a, b);
119//
120//       assert(c->src[0] == a);
121//       assert(c->src[1] == b);
122//   }
123//
124// The multi-dimensional tensors are stored in row-major order. The ggml_tensor struct contains fields for the
125// number of elements in each dimension ("ne") as well as the number of bytes ("nb", a.k.a. stride). This allows
126// to store tensors that are not contiguous in memory, which is useful for operations such as transposition and
127// permutation. All tensor operations have to take the stride into account and not assume that the tensor is
128// contiguous in memory.
129//
130// The data of the tensor is accessed via the "data" pointer. For example:
131//
132//   {
133//       struct ggml_tensor * a = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, 2, 3);
134//
135//       // a[1, 2] = 1.0f;
136//       *(float *) ((char *) a->data + 2*a->nb[1] + 1*a->nb[0]) = 1.0f;
137//
138//       // a[2, 0] = 2.0f;
139//       *(float *) ((char *) a->data + 0*a->nb[1] + 2*a->nb[0]) = 2.0f;
140//
141//       ...
142//   }
143//
144// Alternatively, there are helper functions, such as ggml_get_f32_1d() and ggml_set_f32_1d() that can be used.
145//
146// ## The matrix multiplication operator (ggml_mul_mat)
147//
148// TODO
149//
150//
151// ## Multi-threading
152//
153// TODO
154//
155//
156// ## Overview of ggml.c
157//
158// TODO
159//
160//
161// ## SIMD optimizations
162//
163// TODO
164//
165//
166// ## Debugging ggml
167//
168// TODO
169//
170//
171
172#ifdef  __cplusplus
173extern "C" {
174#endif
175
176#include <stdint.h>
177#include <stddef.h>
178#include <stdbool.h>
179
180#define GGML_MAX_DIMS     4
181#define GGML_MAX_NODES    4096
182#define GGML_MAX_PARAMS   16
183#define GGML_MAX_CONTEXTS 64
184#define GGML_MAX_OPT      4
185
186#ifdef __ARM_NEON
187// we use the built-in 16-bit float type
188typedef __fp16 ggml_fp16_t;
189#else
190typedef uint16_t ggml_fp16_t;
191#endif
192
193// convert FP16 <-> FP32
194float       ggml_fp16_to_fp32(ggml_fp16_t x);
195ggml_fp16_t ggml_fp32_to_fp16(float x);
196
197struct ggml_object;
198struct ggml_context;
199
200enum ggml_type {
201    GGML_TYPE_I8,
202    GGML_TYPE_I16,
203    GGML_TYPE_I32,
204    GGML_TYPE_F16,
205    GGML_TYPE_F32,
206    GGML_TYPE_COUNT,
207};
208
209// available tensor operations:
210enum ggml_op {
211    GGML_OP_NONE = 0,
212
213    GGML_OP_DUP,
214    GGML_OP_ADD,
215    GGML_OP_SUB,
216    GGML_OP_MUL,
217    GGML_OP_DIV,
218    GGML_OP_SQR,
219    GGML_OP_SQRT,
220    GGML_OP_SUM,
221    GGML_OP_MEAN,
222    GGML_OP_REPEAT,
223    GGML_OP_ABS,
224    GGML_OP_SGN,
225    GGML_OP_NEG,
226    GGML_OP_STEP,
227    GGML_OP_RELU,
228    GGML_OP_GELU,
229    GGML_OP_NORM, // normalize
230
231    GGML_OP_MUL_MAT,
232
233    GGML_OP_SCALE,
234    GGML_OP_CPY,
235    GGML_OP_RESHAPE,
236    GGML_OP_VIEW,
237    GGML_OP_PERMUTE,
238    GGML_OP_TRANSPOSE,
239    GGML_OP_GET_ROWS,
240    GGML_OP_DIAG_MASK_INF,
241    GGML_OP_SOFT_MAX,
242    GGML_OP_ROPE,
243    GGML_OP_CONV_1D_1S,
244    GGML_OP_CONV_1D_2S,
245
246    GGML_OP_FLASH_ATTN,
247    GGML_OP_FLASH_FF,
248
249    GGML_OP_COUNT,
250};
251
252// n-dimensional tensor
253struct ggml_tensor {
254    enum ggml_type type;
255
256    int    n_dims;
257    int    ne[GGML_MAX_DIMS]; // number of elements
258    size_t nb[GGML_MAX_DIMS]; // stride in bytes:
259                              // nb[0] = sizeof(type)
260                              // nb[1] = nb[0]   * ne[0] + padding
261                              // nb[i] = nb[i-1] * ne[i-1]
262
263    // compute data
264    enum ggml_op op;
265
266    bool is_param;
267
268    struct ggml_tensor * grad;
269    struct ggml_tensor * src0;
270    struct ggml_tensor * src1;
271    struct ggml_tensor * opt[GGML_MAX_OPT];
272
273    // thread scheduling
274    int n_tasks;
275
276    // performance
277    int     perf_runs;
278    int64_t perf_cycles;
279    int64_t perf_time_us;
280
281    void * data;
282    char padding[8];
283};
284
285// computation graph
286struct ggml_cgraph {
287    int n_nodes;
288    int n_leafs;
289    int n_threads;
290
291    size_t work_size;
292    struct ggml_tensor * work;
293
294    struct ggml_tensor * nodes[GGML_MAX_NODES];
295    struct ggml_tensor * grads[GGML_MAX_NODES];
296    struct ggml_tensor * leafs[GGML_MAX_NODES];
297
298    // performance
299    int     perf_runs;
300    int64_t perf_cycles;
301    int64_t perf_time_us;
302};
303
304struct ggml_init_params {
305    // memory pool
306    size_t mem_size;   // bytes
307    void * mem_buffer; // if NULL, memory will be allocated internally
308};
309
310void    ggml_time_init(void); // call this once at the beginning of the program
311int64_t ggml_time_ms(void);
312int64_t ggml_time_us(void);
313int64_t ggml_cycles(void);
314int64_t ggml_cycles_per_ms(void);
315
316void ggml_print_object (const struct ggml_object * obj);
317void ggml_print_objects(const struct ggml_context * ctx);
318
319int    ggml_nelements(const struct ggml_tensor * tensor);
320size_t ggml_nbytes   (const struct ggml_tensor * tensor);
321
322size_t ggml_type_size   (enum ggml_type type);
323size_t ggml_element_size(const struct ggml_tensor * tensor);
324
325struct ggml_context * ggml_init(struct ggml_init_params params);
326void ggml_free(struct ggml_context * ctx);
327
328size_t ggml_used_mem(const struct ggml_context * ctx);
329
330struct ggml_tensor * ggml_new_tensor(
331        struct ggml_context * ctx,
332        enum   ggml_type type,
333        int    n_dims,
334        const int *ne);
335
336struct ggml_tensor * ggml_new_tensor_1d(
337        struct ggml_context * ctx,
338        enum   ggml_type type,
339        int    ne0);
340
341struct ggml_tensor * ggml_new_tensor_2d(
342        struct ggml_context * ctx,
343        enum   ggml_type type,
344        int    ne0,
345        int    ne1);
346
347struct ggml_tensor * ggml_new_tensor_3d(
348        struct ggml_context * ctx,
349        enum   ggml_type type,
350        int    ne0,
351        int    ne1,
352        int    ne2);
353
354struct ggml_tensor * ggml_new_tensor_4d(
355        struct ggml_context * ctx,
356        enum   ggml_type type,
357        int    ne0,
358        int    ne1,
359        int    ne2,
360        int    ne3);
361
362struct ggml_tensor * ggml_new_i32(struct ggml_context * ctx, int32_t value);
363struct ggml_tensor * ggml_new_f32(struct ggml_context * ctx, float value);
364
365struct ggml_tensor * ggml_dup_tensor (struct ggml_context * ctx, const struct ggml_tensor * src);
366struct ggml_tensor * ggml_view_tensor(struct ggml_context * ctx, const struct ggml_tensor * src);
367
368struct ggml_tensor * ggml_set_zero(struct ggml_tensor * tensor);
369struct ggml_tensor * ggml_set_i32 (struct ggml_tensor * tensor, int32_t value);
370struct ggml_tensor * ggml_set_f32 (struct ggml_tensor * tensor, float value);
371
372int32_t ggml_get_i32_1d(const struct ggml_tensor * tensor, int i);
373void    ggml_set_i32_1d(const struct ggml_tensor * tensor, int i, int32_t value);
374
375float ggml_get_f32_1d(const struct ggml_tensor * tensor, int i);
376void  ggml_set_f32_1d(const struct ggml_tensor * tensor, int i, float value);
377
378 void * ggml_get_data    (const struct ggml_tensor * tensor);
379float * ggml_get_data_f32(const struct ggml_tensor * tensor);
380
381//
382// operations on tensors with backpropagation
383//
384
385struct ggml_tensor * ggml_dup(
386        struct ggml_context * ctx,
387        struct ggml_tensor  * a);
388
389struct ggml_tensor * ggml_add(
390        struct ggml_context * ctx,
391        struct ggml_tensor  * a,
392        struct ggml_tensor  * b);
393
394struct ggml_tensor * ggml_sub(
395        struct ggml_context * ctx,
396        struct ggml_tensor  * a,
397        struct ggml_tensor  * b);
398
399struct ggml_tensor * ggml_mul(
400        struct ggml_context * ctx,
401        struct ggml_tensor  * a,
402        struct ggml_tensor  * b);
403
404struct ggml_tensor * ggml_div(
405        struct ggml_context * ctx,
406        struct ggml_tensor  * a,
407        struct ggml_tensor  * b);
408
409struct ggml_tensor * ggml_sqr(
410        struct ggml_context * ctx,
411        struct ggml_tensor  * a);
412
413struct ggml_tensor * ggml_sqrt(
414        struct ggml_context * ctx,
415        struct ggml_tensor  * a);
416
417// return scalar
418// TODO: compute sum along rows
419struct ggml_tensor * ggml_sum(
420        struct ggml_context * ctx,
421        struct ggml_tensor  * a);
422
423// mean along rows
424struct ggml_tensor * ggml_mean(
425        struct ggml_context * ctx,
426        struct ggml_tensor  * a);
427
428// if a is the same shape as b, and a is not parameter, return a
429// otherwise, return a new tensor: repeat(a) to fit in b
430struct ggml_tensor * ggml_repeat(
431        struct ggml_context * ctx,
432        struct ggml_tensor  * a,
433        struct ggml_tensor  * b);
434
435struct ggml_tensor * ggml_abs(
436        struct ggml_context * ctx,
437        struct ggml_tensor  * a);
438
439struct ggml_tensor * ggml_sgn(
440        struct ggml_context * ctx,
441        struct ggml_tensor  * a);
442
443struct ggml_tensor * ggml_neg(
444        struct ggml_context * ctx,
445        struct ggml_tensor  * a);
446
447struct ggml_tensor * ggml_step(
448        struct ggml_context * ctx,
449        struct ggml_tensor  * a);
450
451struct ggml_tensor * ggml_relu(
452        struct ggml_context * ctx,
453        struct ggml_tensor  * a);
454
455// TODO: double-check this computation is correct
456struct ggml_tensor * ggml_gelu(
457        struct ggml_context * ctx,
458        struct ggml_tensor  * a);
459
460// normalize along rows
461// TODO: eps is hardcoded to 1e-5 for now
462struct ggml_tensor * ggml_norm(
463        struct ggml_context * ctx,
464        struct ggml_tensor  * a);
465
466// A: m rows, n columns
467// B: p rows, n columns (i.e. we transpose it internally)
468// result is m columns, p rows
469struct ggml_tensor * ggml_mul_mat(
470        struct ggml_context * ctx,
471        struct ggml_tensor  * a,
472        struct ggml_tensor  * b);
473
474//
475// operations on tensors without backpropagation
476//
477
478// in-place, returns view(a)
479struct ggml_tensor * ggml_scale(
480        struct ggml_context * ctx,
481        struct ggml_tensor  * a,
482        struct ggml_tensor  * b);
483
484// a -> b, return view(b)
485struct ggml_tensor * ggml_cpy(
486        struct ggml_context * ctx,
487        struct ggml_tensor  * a,
488        struct ggml_tensor  * b);
489
490// return view(a), b specifies the new shape
491// TODO: when we start computing gradient, make a copy instead of view
492struct ggml_tensor * ggml_reshape(
493        struct ggml_context * ctx,
494        struct ggml_tensor  * a,
495        struct ggml_tensor  * b);
496
497// return view(a)
498// TODO: when we start computing gradient, make a copy instead of view
499struct ggml_tensor * ggml_reshape_2d(
500        struct ggml_context * ctx,
501        struct ggml_tensor  * a,
502        int                   ne0,
503        int                   ne1);
504
505// return view(a)
506// TODO: when we start computing gradient, make a copy instead of view
507struct ggml_tensor * ggml_reshape_3d(
508        struct ggml_context * ctx,
509        struct ggml_tensor  * a,
510        int                   ne0,
511        int                   ne1,
512        int                   ne2);
513
514// offset in bytes
515struct ggml_tensor * ggml_view_1d(
516        struct ggml_context * ctx,
517        struct ggml_tensor  * a,
518        int                   ne0,
519        size_t                offset);
520
521struct ggml_tensor * ggml_view_2d(
522        struct ggml_context * ctx,
523        struct ggml_tensor  * a,
524        int                   ne0,
525        int                   ne1,
526        size_t                nb1, // row stride in bytes
527        size_t                offset);
528
529struct ggml_tensor * ggml_permute(
530        struct ggml_context * ctx,
531        struct ggml_tensor  * a,
532        int                   axis0,
533        int                   axis1,
534        int                   axis2,
535        int                   axis3);
536
537// alias for ggml_permute(ctx, a, 1, 0, 2, 3)
538struct ggml_tensor * ggml_transpose(
539        struct ggml_context * ctx,
540        struct ggml_tensor  * a);
541
542struct ggml_tensor * ggml_get_rows(
543        struct ggml_context * ctx,
544        struct ggml_tensor  * a,
545        struct ggml_tensor  * b);
546
547// set elements above the diagonal to -INF
548// in-place, returns view(a)
549struct ggml_tensor * ggml_diag_mask_inf(
550        struct ggml_context * ctx,
551        struct ggml_tensor  * a,
552        int                   n_past);
553
554// in-place, returns view(a)
555struct ggml_tensor * ggml_soft_max(
556        struct ggml_context * ctx,
557        struct ggml_tensor  * a);
558
559// rotary position embedding
560// in-place, returns view(a)
561// if mode == 1, skip n_past elements
562// TODO: avoid creating a new tensor every time
563struct ggml_tensor * ggml_rope(
564        struct ggml_context * ctx,
565        struct ggml_tensor  * a,
566        int                   n_past,
567        int                   n_dims,
568        int                   mode);
569
570// padding = 1
571// TODO: we don't support extra parameters for now
572//       that's why we are hard-coding the stride, padding, and dilation
573//       not great ..
574struct ggml_tensor * ggml_conv_1d_1s(
575        struct ggml_context * ctx,
576        struct ggml_tensor  * a,
577        struct ggml_tensor  * b);
578
579struct ggml_tensor * ggml_conv_1d_2s(
580        struct ggml_context * ctx,
581        struct ggml_tensor  * a,
582        struct ggml_tensor  * b);
583
584struct ggml_tensor * ggml_flash_attn(
585        struct ggml_context * ctx,
586        struct ggml_tensor  * q,
587        struct ggml_tensor  * k,
588        struct ggml_tensor  * v,
589        bool                  masked);
590
591struct ggml_tensor * ggml_flash_ff(
592        struct ggml_context * ctx,
593        struct ggml_tensor  * a,
594        struct ggml_tensor  * b0,
595        struct ggml_tensor  * b1,
596        struct ggml_tensor  * c0,
597        struct ggml_tensor  * c1);
598
599//
600// automatic differentiation
601//
602
603void ggml_set_param(
604        struct ggml_context * ctx,
605        struct ggml_tensor * tensor);
606
607void ggml_build_forward_expand(struct ggml_cgraph * cgraph, struct ggml_tensor * tensor);
608
609struct ggml_cgraph ggml_build_forward (struct ggml_tensor * tensor);
610struct ggml_cgraph ggml_build_backward(struct ggml_context * ctx, struct ggml_cgraph * gf, bool keep);
611
612void ggml_graph_compute(struct ggml_context * ctx, struct ggml_cgraph * cgraph);
613void ggml_graph_reset  (struct ggml_cgraph * cgraph);
614
615// print info and performance information for the graph
616void ggml_graph_print(const struct ggml_cgraph * cgraph);
617
618// dump the graph into a file using the dot format
619void ggml_graph_dump_dot(const struct ggml_cgraph * gb, const struct ggml_cgraph * gf, const char * filename);
620
621//
622// optimization
623//
624
625// optimization methods
626enum ggml_opt_type {
627    GGML_OPT_ADAM,
628    GGML_OPT_LBFGS,
629};
630
631// linesearch methods
632enum ggml_linesearch {
633    GGML_LINESEARCH_DEFAULT = 1,
634
635    GGML_LINESEARCH_BACKTRACKING_ARMIJO       = 0,
636    GGML_LINESEARCH_BACKTRACKING_WOLFE        = 1,
637    GGML_LINESEARCH_BACKTRACKING_STRONG_WOLFE = 2,
638};
639
640// optimization return values
641enum ggml_opt_result {
642    GGML_OPT_OK = 0,
643    GGML_OPT_DID_NOT_CONVERGE,
644    GGML_OPT_NO_CONTEXT,
645    GGML_OPT_INVALID_WOLFE,
646    GGML_OPT_FAIL,
647
648    GGML_LINESEARCH_FAIL = -128,
649    GGML_LINESEARCH_MINIMUM_STEP,
650    GGML_LINESEARCH_MAXIMUM_STEP,
651    GGML_LINESEARCH_MAXIMUM_ITERATIONS,
652    GGML_LINESEARCH_INVALID_PARAMETERS,
653};
654
655// optimization parameters
656//
657//   see ggml.c (ggml_opt_default_params) for default values
658//
659struct ggml_opt_params {
660    enum ggml_opt_type type;
661
662    int n_threads;
663
664    // delta-based convergence test
665    //
666    //   if past == 0 - disabled
667    //   if past > 0:
668    //     stop if |f(x) - f(x_past)| < delta * max(1, |f(x)|)
669    //
670    int past;
671    float delta;
672
673    // maximum number of iterations without improvement
674    //
675    //   if 0 - disabled
676    //   if > 0:
677    //     assume convergence if no cost improvement in this number of iterations
678    //
679    int max_no_improvement;
680
681    bool print_forward_graph;
682    bool print_backward_graph;
683
684    // ADAM parameters
685    struct {
686        int n_iter;
687
688        float alpha; // learning rate
689        float beta1;
690        float beta2;
691        float eps;   // epsilon for numerical stability
692        float eps_f; // epsilon for convergence test
693        float eps_g; // epsilon for convergence test
694    } adam;
695
696    // LBFGS parameters
697    struct {
698        int m; // number of corrections to approximate the inv. Hessian
699        int n_iter;
700        int max_linesearch;
701
702        float eps;      // convergence tolerance
703        float ftol;     // line search tolerance
704        float wolfe;
705        float min_step;
706        float max_step;
707
708        enum ggml_linesearch linesearch;
709    } lbfgs;
710};
711
712struct ggml_opt_params ggml_opt_default_params(enum ggml_opt_type type);
713
714// optimize the function defined by the tensor f
715enum ggml_opt_result ggml_opt(
716        struct ggml_context * ctx,
717        struct ggml_opt_params params,
718        struct ggml_tensor * f);
719
720//
721// system info
722//
723
724int ggml_cpu_has_avx(void);
725int ggml_cpu_has_avx2(void);
726int ggml_cpu_has_avx512(void);
727int ggml_cpu_has_fma(void);
728int ggml_cpu_has_neon(void);
729int ggml_cpu_has_arm_fma(void);
730int ggml_cpu_has_f16c(void);
731int ggml_cpu_has_fp16_va(void);
732int ggml_cpu_has_wasm_simd(void);
733int ggml_cpu_has_blas(void);
734
735#ifdef  __cplusplus
736}
737#endif