char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Neo Zhangsycl : fix the failed UT cases of conv_3d (#24900)9c1095486

char/aliceai-t5-moe
8.5 KiB224 linesraw
1#include "conv3d.hpp"
2
3static inline int64_t ggml_sycl_conv3d_calc_patch_total(const ggml_tensor * dst, int32_t n) {
4    return (int64_t) n * dst->ne[0] * dst->ne[1] * dst->ne[2];
5}
6
7static inline int64_t ggml_sycl_conv3d_calc_knl_n_total(const ggml_tensor * src0, int32_t c) {
8    return (int64_t) src0->ne[0] * src0->ne[1] * src0->ne[2] * c;
9}
10
11static inline void ggml_sycl_conv3d_write_output(
12        const ggml_tensor * dst,
13        const float * src, float * dst_data,
14        int64_t patch_total, int64_t oc,
15        int64_t dst_w, int64_t dst_h, int64_t dst_d,
16        dpct::queue_ptr stream) {
17    const int64_t dst_nb0 = dst->nb[0];
18    const int64_t dst_nb1 = dst->nb[1];
19    const int64_t dst_nb2 = dst->nb[2];
20    const int64_t dst_nb3 = dst->nb[3];
21    const int64_t total = patch_total * oc;
22    const int64_t block_size = 256;
23    const int64_t num_work_items = ((total + block_size - 1) / block_size) * block_size;
24
25    stream->parallel_for(sycl::range<1>(num_work_items), [=](sycl::id<1> id) {
26        const int64_t i = id[0];
27        if (i >= total) {
28            return;
29        }
30
31        const int64_t patch_idx = i / oc;
32        const int64_t out_ch = i % oc;
33        const int64_t p_in_batch = patch_idx % (dst_w * dst_h * dst_d);
34        const int64_t batch_idx = patch_idx / (dst_w * dst_h * dst_d);
35        const int64_t dst_z = p_in_batch / (dst_w * dst_h);
36        const int64_t dst_y = (p_in_batch % (dst_w * dst_h)) / dst_w;
37        const int64_t dst_x = p_in_batch % dst_w;
38        const int64_t ocn_idx = batch_idx * oc + out_ch;
39
40        const int64_t dst_offset = dst_x * dst_nb0 + dst_y * dst_nb1 + dst_z * dst_nb2 + ocn_idx * dst_nb3;
41        // `src` is a column-major (m x n) GEMM output where m == patch_total, n == oc.
42        // GEMM stores element (row, col) at index `row + col*m`, so compute index accordingly.
43        const int64_t src_index = patch_idx + out_ch * patch_total;
44        const float value = src[src_index];
45        *(float *)((char *)dst_data + dst_offset) = value;
46    });
47}
48
49void ggml_sycl_op_conv_3d(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
50    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/2);
51
52    const ggml_tensor * src0 = dst->src[0];
53    const ggml_tensor * src1 = dst->src[1];
54
55    GGML_ASSERT(src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_F32);
56    GGML_ASSERT(src1->type == GGML_TYPE_F32);
57    GGML_ASSERT(dst->type == GGML_TYPE_F32);
58    GGML_ASSERT(ggml_is_contiguous(src0));
59    GGML_ASSERT(ggml_is_contiguous(src1));
60
61    const int32_t * opts = (const int32_t *) dst->op_params;
62    const int32_t s0 = opts[0];
63    const int32_t s1 = opts[1];
64    const int32_t s2 = opts[2];
65    const int32_t p0 = opts[3];
66    const int32_t p1 = opts[4];
67    const int32_t p2 = opts[5];
68    const int32_t d0 = opts[6];
69    const int32_t d1 = opts[7];
70    const int32_t d2 = opts[8];
71    const int32_t c  = opts[9];
72    const int32_t n  = opts[10];
73    const int32_t oc = opts[11];
74
75    const int64_t knl_w = src0->ne[0];
76    const int64_t knl_h = src0->ne[1];
77    const int64_t knl_d = src0->ne[2];
78
79    const int64_t patch_total = ggml_sycl_conv3d_calc_patch_total(dst, n);
80    const int64_t knl_n_total = ggml_sycl_conv3d_calc_knl_n_total(src0, c);
81
82    const size_t kernel_type_size = ggml_element_size(src0);
83
84    ggml_sycl_pool_alloc<float> gemm_output(ctx.pool());
85    gemm_output.alloc((size_t) patch_total * oc);
86
87    ggml_tensor dst_mat = {};
88    dst_mat.type = GGML_TYPE_F32;
89    dst_mat.ne[0] = patch_total;
90    dst_mat.ne[1] = oc;
91    dst_mat.ne[2] = 1;
92    dst_mat.ne[3] = 1;
93    dst_mat.nb[0] = sizeof(float);
94    dst_mat.nb[1] = dst_mat.nb[0] * dst_mat.ne[0];
95    dst_mat.nb[2] = dst_mat.nb[1];
96    dst_mat.nb[3] = dst_mat.nb[2];
97    dst_mat.data = gemm_output.get();
98    dst_mat.buffer = dst->buffer;
99    dst_mat.extra = dst->extra;
100
101    dpct::queue_ptr stream = ctx.stream();
102
103    // allocate packed arrays: A_packed (k x m), B_packed (k x n)
104    ggml_sycl_pool_alloc<float> A_packed_alloc(ctx.pool());
105    ggml_sycl_pool_alloc<float> B_packed_alloc(ctx.pool());
106    A_packed_alloc.alloc((size_t) knl_n_total * patch_total);
107    B_packed_alloc.alloc((size_t) knl_n_total * oc);
108
109    float * A_packed = A_packed_alloc.get();
110    float * B_packed = B_packed_alloc.get();
111
112    const int m = (int) patch_total;
113    const int n_gemm = (int) oc;
114    const int k = (int) knl_n_total;
115
116    // Combined kernel: im2col -> pack A, and pack B simultaneously
117    const char * src1_base = (const char *) src1->data;
118    const char * src0_base = (const char *) src0->data;
119    const int64_t src1_nb0 = src1->nb[0];
120    const int64_t src1_nb1 = src1->nb[1];
121    const int64_t src1_nb2 = src1->nb[2];
122    const int64_t src1_nb3 = src1->nb[3];
123    const int64_t src1_w = src1->ne[0];
124    const int64_t src1_h = src1->ne[1];
125    const int64_t src1_d = src1->ne[2];
126
127    const bool src0_is_f32 = (src0->type == GGML_TYPE_F32);
128
129    // Compute correct strides for src0 as (knl_n_total, oc) matrix
130    const int64_t src0_packed_nb0 = kernel_type_size;
131    const int64_t src0_packed_nb1 = kernel_type_size * knl_n_total;
132
133    const int64_t KW = knl_w;
134    const int64_t KH = knl_h;
135    const int64_t KD = knl_d;
136    const int64_t PW = dst->ne[0];
137    const int64_t PH = dst->ne[1];
138    const int64_t PD = dst->ne[2];
139
140    // Pack A (with inline im2col): for each (row, col) in k x m matrix
141    const int64_t A_total = (int64_t)k * m;
142    const int64_t A_block_size = 256;
143    const int64_t A_num_work = ((A_total + A_block_size - 1) / A_block_size) * A_block_size;
144
145    stream->parallel_for(sycl::range<1>(A_num_work), [=](sycl::id<1> id) {
146        const int64_t t = id[0];
147        if (t >= A_total) return;
148
149        const int64_t row = t % k;
150        const int64_t col = t / k;
151
152        // Inline im2col for this element
153        const int64_t k_index = row;
154        const int64_t patch_idx = col;
155
156        const int64_t ic = k_index / (KD * KH * KW);
157        const int64_t rem = k_index - ic * (KD * KH * KW);
158        const int64_t kz = rem / (KH * KW);
159        const int64_t rem2 = rem - kz * (KH * KW);
160        const int64_t ky = rem2 / KW;
161        const int64_t kx = rem2 % KW;
162
163        const int64_t p_in_batch = patch_idx % (PW * PH * PD);
164        const int64_t batch_idx = patch_idx / (PW * PH * PD);
165        const int64_t dst_z = p_in_batch / (PW * PH);
166        const int64_t dst_y = (p_in_batch % (PW * PH)) / PW;
167        const int64_t dst_x = p_in_batch % PW;
168
169        const int64_t sx = dst_x * s0 + kx * d0 - p0;
170        const int64_t sy = dst_y * s1 + ky * d1 - p1;
171        const int64_t sz = dst_z * s2 + kz * d2 - p2;
172
173        float val = 0.0f;
174        if (sx >= 0 && sx < src1_w && sy >= 0 && sy < src1_h && sz >= 0 && sz < src1_d) {
175            const int64_t channel_idx = batch_idx * c + ic;
176            const char * ptr = src1_base + sx * src1_nb0 + sy * src1_nb1 + sz * src1_nb2 + channel_idx * src1_nb3;
177            val = *(const float *) ptr;
178        }
179        A_packed[row + col * (int64_t)k] = val;
180    });
181
182    // Pack B: for each (row, col) in k x n_gemm matrix
183    const int64_t B_total = (int64_t)k * n_gemm;
184    const int64_t B_block_size = 256;
185    const int64_t B_num_work = ((B_total + B_block_size - 1) / B_block_size) * B_block_size;
186
187    stream->parallel_for(sycl::range<1>(B_num_work), [=](sycl::id<1> id) {
188        const int64_t t = id[0];
189        if (t >= B_total) return;
190
191        const int64_t row = t % k;
192        const int64_t col = t / k;
193        const char * src_ptr = src0_base + row * src0_packed_nb0 + col * src0_packed_nb1;
194        float v;
195        if (src0_is_f32) {
196            v = *(const float *) src_ptr;
197        } else {
198            v = sycl::vec<sycl::half, 1>(*(const sycl::half *) src_ptr).convert<float, sycl::rounding_mode::automatic>()[0];
199        }
200        B_packed[row + col * (int64_t)k] = v;
201    });
202
203    // GEMM: C = A^T * B where A is (k x m), B is (k x n), C is (m x n)
204    const float alpha = 1.0f;
205    const float beta  = 0.0f;
206    const int lda = k;
207    const int ldb = k;
208    const int ldc = m;
209
210    SYCL_CHECK(CHECK_TRY_ERROR(oneapi::mkl::blas::column_major::gemm(
211        *stream, oneapi::mkl::transpose::trans, oneapi::mkl::transpose::nontrans,
212        m, n_gemm, k,
213        dpct::get_value(&alpha, *stream),
214        (const float *) A_packed, lda,
215        (const float *) B_packed, ldb,
216        dpct::get_value(&beta, *stream),
217        (float *) dst_mat.data, ldc)));
218
219    const float * gemm_data = (const float *) dst_mat.data;
220    float * dst_data = (float *) dst->data;
221
222    ggml_sycl_conv3d_write_output(dst, gemm_data, dst_data, patch_total, oc,
223                                  dst->ne[0], dst->ne[1], dst->ne[2], stream);
224}