char-fork/llama.cpp

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

Xuan-Son Nguyenmtmd: support pocket-tts (#26871)6e62ba538

char/aliceai-t5-moe
7.3 KiB162 linesraw
1#include "models.h"
2
3// SEANet convolution stack of the mimi codec, see pocket_tts/modules/seanet.py
4//
5// tensors are T-first here: [T, C]
6// the convs are causal: left context comes from a state slot, or from padding on a cold start
7
8static int64_t div_ceil(int64_t a, int64_t b) {
9    return a / b + (a % b ? 1 : 0);
10}
11
12// x: [T, IC], w: [K, IC, OC] -> [T / stride, OC]
13// the convs are causal, so the whole K - stride padding goes on the left
14ggml_tensor * clip_graph_pockettts_seanet::conv1d(ggml_tensor * x, ggml_tensor * w, ggml_tensor * b, int stride, int dilation,
15                                                  bool pad_replicate, const std::string & state_name) const {
16    const int64_t k_size  = (w->ne[0] - 1) * dilation + 1;
17    const int64_t p_total = k_size - stride;
18
19    // trailing padding so the last frame is not dropped, see pad_for_conv1d() in conv.py
20    const int64_t n_frames  = div_ceil(x->ne[0] - k_size + p_total, stride);
21    const int64_t ideal_len = n_frames * stride + k_size - p_total;
22    const int64_t p_extra   = ideal_len - x->ne[0];
23
24    if (!state_name.empty() && p_total > 0) {
25        // streaming: the left context is the tail of the previous call
26        ggml_tensor * left = state_in.at(state_name); // [p_total, IC]
27        x = ggml_concat(ctx0, left, x, 0);
28        state_out.push_back({state_name,
29            ggml_cont(ctx0, ggml_view_2d(ctx0, x, p_total, x->ne[1], x->nb[1],
30                                         (size_t) (x->ne[0] - p_total) * x->nb[0]))});
31    } else if (pad_replicate && p_total > 0) {
32        // the resamplers repeat the first frame instead of zero-padding
33        ggml_tensor * first = ggml_view_2d(ctx0, x, 1, x->ne[1], x->nb[1], 0);
34        ggml_tensor * left  = ggml_repeat_4d(ctx0, first, p_total, x->ne[1], 1, 1);
35        x = ggml_concat(ctx0, left, x, 0);
36        x = ggml_pad_ext(ctx0, x, 0, p_extra, 0, 0, 0, 0, 0, 0);
37    } else {
38        x = ggml_pad_ext(ctx0, x, p_total, p_extra, 0, 0, 0, 0, 0, 0);
39    }
40
41    ggml_tensor * y = ggml_conv_1d(ctx0, w, x, stride, 0, dilation);
42    y = ggml_reshape_2d(ctx0, y, y->ne[0], y->ne[1]);
43    if (b) {
44        y = ggml_add(ctx0, y, ggml_reshape_2d(ctx0, b, 1, b->ne[0]));
45    }
46    return y;
47}
48
49// x: [T, IC], w: [K, OC/groups, IC] -> [T * stride, OC]
50// the K - stride overlap tail belongs to the next call: added to its head when streaming, else dropped
51ggml_tensor * clip_graph_pockettts_seanet::conv_transpose1d(ggml_tensor * x, ggml_tensor * w, ggml_tensor * b, int stride,
52                                                            const std::string & state_name) const {
53    const int64_t K         = w->ne[0];
54    const int64_t T         = x->ne[0];
55    const int64_t p_total   = K - stride;
56    const bool    depthwise = w->ne[1] == 1 && w->ne[2] > 1;
57    const int64_t OC        = depthwise ? w->ne[2] : w->ne[1];
58    const int64_t emit_len  = T * stride;
59
60    // one column per input step, holding the [K, OC] window that col2im scatter-adds at t * stride
61    ggml_tensor * col;
62    if (depthwise) {
63        // one group per channel: a batched matmul over the channels scales the kernel by each step
64        ggml_tensor * krn = ggml_reshape_3d(ctx0, w, 1, K, OC);             // [1, K, OC]
65        ggml_tensor * xs  = ggml_reshape_3d(ctx0, x, 1, T, OC);             // [1, T, OC]
66        col = ggml_mul_mat(ctx0, krn, xs);                                  // [K, T, OC]
67        col = ggml_cont(ctx0, ggml_permute(ctx0, col, 0, 2, 1, 3));         // [K, OC, T]
68        col = ggml_reshape_2d(ctx0, col, K * OC, T);
69    } else {
70        ggml_tensor * w2 = ggml_reshape_2d(ctx0, w, K * OC, w->ne[2]);
71        w2               = ggml_cont(ctx0, ggml_transpose(ctx0, w2));       // [IC, K * OC]
72        ggml_tensor * xt = ggml_cont(ctx0, ggml_transpose(ctx0, x));        // [IC, T]
73        col = ggml_mul_mat(ctx0, w2, xt);
74    }
75    ggml_tensor * full = ggml_col2im_1d(ctx0, col, stride, OC, 0);          // [emit_len + p_total, OC]
76
77    ggml_tensor * out;
78    if (state_name.empty() || p_total == 0) {
79        out = ggml_cont(ctx0, ggml_view_2d(ctx0, full, emit_len, full->ne[1], full->nb[1], 0));
80    } else {
81        // overlap-add the tail the previous call held back
82        ggml_tensor * prev = state_in.at(state_name); // [p_total, OC]
83        ggml_tensor * head = ggml_add(ctx0, ggml_view_2d(ctx0, full, p_total, full->ne[1], full->nb[1], 0), prev);
84        if (emit_len > p_total) {
85            ggml_tensor * rest = ggml_view_2d(ctx0, full, emit_len - p_total, full->ne[1], full->nb[1],
86                                              (size_t) p_total * full->nb[0]);
87            out = ggml_concat(ctx0, head, rest, 0);
88        } else {
89            out = head;
90        }
91        state_out.push_back({state_name,
92            ggml_cont(ctx0, ggml_view_2d(ctx0, full, p_total, full->ne[1], full->nb[1],
93                                         (size_t) emit_len * full->nb[0]))});
94    }
95
96    if (b) {
97        out = ggml_add(ctx0, out, ggml_reshape_2d(ctx0, b, 1, b->ne[0]));
98    }
99    return out;
100}
101
102ggml_tensor * clip_graph_pockettts_seanet::res_unit(ggml_tensor * x, const clip_seanet::stage & stage, int dilation,
103                                                    const std::string & state_prefix) const {
104    ggml_tensor * h = ggml_elu(ctx0, x);
105    h = conv1d(h, stage.res_conv1_w, stage.res_conv1_b, 1, dilation, false, state_prefix);
106    h = ggml_elu(ctx0, h);
107    // the second conv is pointwise, it needs no left context
108    h = conv1d(h, stage.res_conv2_w, stage.res_conv2_b, 1, 1);
109    return ggml_add(ctx0, x, h);
110}
111
112ggml_tensor * clip_graph_pockettts_seanet::encode(ggml_tensor * x) const {
113    const auto & seanet = model.seanet;
114
115    ggml_tensor * cur = conv1d(x, seanet.conv_in_w, seanet.conv_in_b, 1, 1);
116    cb(cur, "seanet_enc_in", -1);
117
118    for (int i = 0; i < hparams.seanet_n_stage; i++) {
119        const auto & stage  = seanet.stages[i];
120        const int    stride = hparams.seanet_ratios[i];
121
122        cur = res_unit(cur, stage, 1);
123        cur = ggml_elu(ctx0, cur);
124        cur = conv1d(cur, stage.scale_conv_w, stage.scale_conv_b, stride, 1);
125        cb(cur, "seanet_enc_stage", i);
126    }
127
128    cur = ggml_elu(ctx0, cur);
129    cur = conv1d(cur, seanet.conv_out_w, seanet.conv_out_b, 1, 1);
130    cb(cur, "seanet_enc_out", -1);
131
132    return cur;
133}
134
135ggml_tensor * clip_graph_pockettts_seanet::decode(ggml_tensor * x) const {
136    const auto & seanet = model.seanet;
137    const bool   stream = !state_in.empty();
138
139    ggml_tensor * cur = conv1d(x, seanet.conv_in_w, seanet.conv_in_b, 1, 1, false,
140                               stream ? "dec_in" : "");
141    cb(cur, "seanet_dec_in", -1);
142
143    for (int i = 0; i < hparams.seanet_n_stage; i++) {
144        const auto & stage = seanet.stages[i];
145        // the decoder mirrors the encoder, so the ratios are walked backwards
146        const int    stride = hparams.seanet_ratios[hparams.seanet_n_stage - 1 - i];
147        const std::string id = std::to_string(i);
148
149        cur = ggml_elu(ctx0, cur);
150        cur = conv_transpose1d(cur, stage.scale_conv_w, stage.scale_conv_b, stride,
151                               stream ? "dec_up_" + id : "");
152        cur = res_unit(cur, stage, 1, stream ? "dec_res_" + id : "");
153        cb(cur, "seanet_dec_stage", i);
154    }
155
156    cur = ggml_elu(ctx0, cur);
157    cur = conv1d(cur, seanet.conv_out_w, seanet.conv_out_b, 1, 1, false,
158                 stream ? "dec_out" : "");
159    cb(cur, "seanet_dec_out", -1);
160
161    return cur;
162}