CoolFace
Datasetpublic

echodict/llama.cpp

version https://git-lfs.github.com/spec/v1 oid sha256:cfc44b7ba25614df70e6b65e3341cae0310163bd32fd31a6b928a542df433faf size 30786

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes773downloads
mtmd-helper.cpp538 linesDownload Raw Back to mtmd
1// fix problem with std::min and std::max2#if defined(_WIN32)3#define WIN32_LEAN_AND_MEAN4#ifndef NOMINMAX5#   define NOMINMAX6#endif7#include <windows.h>8#endif9 10#include "mtmd.h"11#include "mtmd-helper.h"12#include "llama.h"13 14#include <algorithm>15#include <cinttypes>16#include <vector>17 18//#define MTMD_AUDIO_DEBUG19 20#define MINIAUDIO_IMPLEMENTATION21#ifndef MTMD_AUDIO_DEBUG22#   define MA_NO_ENCODING23#endif24#define MA_NO_DEVICE_IO25#define MA_NO_RESOURCE_MANAGER26#define MA_NO_NODE_GRAPH27#define MA_NO_ENGINE28#define MA_NO_GENERATION29#define MA_API static30#include "miniaudio/miniaudio.h"31 32#define STB_IMAGE_IMPLEMENTATION33#include "stb/stb_image.h"34 35#ifdef MTMD_INTERNAL_HEADER36#error "mtmd-helper is a public library outside of mtmd. it must not include internal headers"37#endif38 39//40// internal logging functions41//42 43struct mtmd_helper_logger {44    ggml_log_callback default_callback = [](ggml_log_level level, const char * text, void * user_data) {45        (void) level;46        (void) user_data;47        fputs(text, stderr);48        fflush(stderr);49    };50 51    ggml_log_callback log_callback = default_callback;52    void * log_callback_user_data;53 54    void log_v(enum ggml_log_level level, const char * format, va_list args) {55        if (format == NULL) {56            return;57        }58        va_list args_copy;59        va_copy(args_copy, args);60        char buffer[128];61        int len = vsnprintf(buffer, 128, format, args);62        if (len < 128) {63            log_callback(level, buffer, log_callback_user_data);64        } else {65            char * buffer2 = (char *) calloc(len + 1, sizeof(char));66            vsnprintf(buffer2, len + 1, format, args_copy);67            buffer2[len] = 0;68            log_callback(level, buffer2, log_callback_user_data);69            free(buffer2);70        }71        va_end(args_copy);72    }73 74    void log(enum ggml_log_level level, const char * format, ...) {75        va_list args;76        va_start(args, format);77        log_v(level, format, args);78        va_end(args);79    }80} g_logger;81 82#define LOG_INF(...) g_logger.log(GGML_LOG_LEVEL_INFO,  __VA_ARGS__)83#define LOG_WRN(...) g_logger.log(GGML_LOG_LEVEL_WARN,  __VA_ARGS__)84#define LOG_ERR(...) g_logger.log(GGML_LOG_LEVEL_ERROR, __VA_ARGS__)85 86void mtmd_helper_log_set(ggml_log_callback log_callback, void * user_data) {87    if (log_callback == nullptr) {88        log_callback = g_logger.default_callback;89    }90    g_logger.log_callback = log_callback;91    g_logger.log_callback_user_data = user_data;92    mtmd_log_set(log_callback, user_data);93}94 95//96// helper functions97//98 99size_t mtmd_helper_get_n_tokens(const mtmd_input_chunks * chunks) {100    size_t n_tokens = 0;101    for (size_t i = 0; i < mtmd_input_chunks_size(chunks); i++) {102        auto chunk = mtmd_input_chunks_get(chunks, i);103        n_tokens += mtmd_input_chunk_get_n_tokens(chunk);104    }105    return n_tokens;106}107 108llama_pos mtmd_helper_get_n_pos(const mtmd_input_chunks * chunks) {109    llama_pos n_pos = 0;110    for (size_t i = 0; i < mtmd_input_chunks_size(chunks); i++) {111        auto chunk = mtmd_input_chunks_get(chunks, i);112        n_pos += mtmd_input_chunk_get_n_pos(chunk);113    }114    return n_pos;115}116 117void mtmd_helper_image_get_decoder_pos(const mtmd_image_tokens * chunks, llama_pos pos_0, mtmd_decoder_pos * out_pos) {118    size_t n_tokens = mtmd_image_tokens_get_n_tokens(chunks);119    for (size_t i = 0; i < n_tokens; i++) {120        out_pos[i] = mtmd_image_tokens_get_decoder_pos(chunks, pos_0, i);121    }122}123 124// helper struct to make working with embd batch easier125// note: this will be removed after llama_batch_ext refactoring126struct decode_embd_batch {127    int n_pos_per_embd;128    int n_mmproj_embd;129    std::vector<llama_pos>      pos;130    std::vector<llama_pos>      pos_view; // used by mrope131    std::vector<int32_t>        n_seq_id;132    std::vector<llama_seq_id>   seq_id_0;133    std::vector<llama_seq_id *> seq_ids;134    std::vector<int8_t>         logits;135    llama_batch batch;136    decode_embd_batch(float * embd, int32_t n_tokens, int n_pos_per_embd, int n_mmproj_embd) : n_pos_per_embd(n_pos_per_embd), n_mmproj_embd(n_mmproj_embd) {137        GGML_ASSERT(n_tokens > 0 && n_pos_per_embd > 0 && n_mmproj_embd > 0);138        pos     .resize(n_tokens * n_pos_per_embd);139        n_seq_id.resize(n_tokens);140        seq_ids .resize(n_tokens + 1);141        logits  .resize(n_tokens);142        seq_id_0.resize(1);143        seq_ids [n_tokens] = nullptr;144        batch = {145            /*n_tokens       =*/ n_tokens,146            /*tokens         =*/ nullptr,147            /*embd           =*/ embd,148            /*pos            =*/ pos.data(),149            /*n_seq_id       =*/ n_seq_id.data(),150            /*seq_id         =*/ seq_ids.data(),151            /*logits         =*/ logits.data(),152        };153    }154 155    void set_position_normal(llama_pos pos_0, llama_seq_id seq_id) {156        seq_id_0[0] = seq_id;157        for (int i = 0; i < batch.n_tokens; i++) {158            batch.pos     [i] = pos_0 + i;159            batch.n_seq_id[i] = 1;160            batch.seq_id  [i] = seq_id_0.data();161            batch.logits  [i] = false;162        }163    }164 165    // M-RoPE for image166    void set_position_mrope_2d(const std::vector<mtmd_decoder_pos> & rel_pos, llama_seq_id seq_id) {167        GGML_ASSERT(n_pos_per_embd == 4);168        GGML_ASSERT(!rel_pos.empty() && (int32_t)rel_pos.size() == batch.n_tokens);169        seq_id_0[0] = seq_id;170        for (int32_t i = 0; i < batch.n_tokens; i++) {171            pos[i                     ] = rel_pos[i].t;172            pos[i + batch.n_tokens    ] = rel_pos[i].y;173            pos[i + batch.n_tokens * 2] = rel_pos[i].x;174            pos[i + batch.n_tokens * 3] = rel_pos[i].z;175        }176        for (int i = 0; i < batch.n_tokens; i++) {177            batch.n_seq_id[i] = 1;178            batch.seq_id  [i] = seq_id_0.data();179            batch.logits  [i] = false;180        }181    }182 183    // M-RoPE for audio184    void set_position_mrope_1d(llama_pos pos_0, llama_seq_id seq_id) {185        GGML_ASSERT(n_pos_per_embd == 4);186        seq_id_0[0] = seq_id;187        for (int i = 0; i < batch.n_tokens; i++) {188            pos[i                     ] = pos_0 + i;189            pos[i + batch.n_tokens    ] = pos_0 + i;190            pos[i + batch.n_tokens * 2] = pos_0 + i;191            pos[i + batch.n_tokens * 3] = pos_0 + i;192        }193        for (int i = 0; i < batch.n_tokens; i++) {194            batch.n_seq_id[i] = 1;195            batch.seq_id  [i] = seq_id_0.data();196            batch.logits  [i] = false;197        }198    }199 200    llama_batch get_view(int offset, int n_tokens) {201        GGML_ASSERT(offset >= 0 && n_tokens > 0 && offset + n_tokens <= batch.n_tokens);202        llama_pos * pos_ptr;203        pos_view.clear();204        pos_view.reserve(n_tokens * n_pos_per_embd);205        if (n_pos_per_embd > 1) {206            // mrope207            // for example, with layout of src: 1234...1234...1234...1234...208            //       offset 2 will give us dst: 34...34...34...34...209            for (int i = 0; i < n_pos_per_embd; i++) {210                // assume n_tokens is less than or equal to batch.n_tokens211                // batch.n_tokens is number of **total** tokens212                // n_tokens is number of viewed token213                size_t src_idx = i * batch.n_tokens + offset;214                pos_view.insert(pos_view.end(),215                    pos.data() + src_idx,216                    pos.data() + src_idx + n_tokens);217            }218            pos_ptr = pos_view.data();219        } else {220            // normal221            pos_ptr = pos.data() + offset;222        }223        return {224            /*n_tokens       =*/ n_tokens,225            /*tokens         =*/ nullptr,226            /*embd           =*/ batch.embd     + offset * n_mmproj_embd,227            /*pos            =*/ pos_ptr,228            /*n_seq_id       =*/ batch.n_seq_id + offset,229            /*seq_id         =*/ batch.seq_id   + offset,230            /*logits         =*/ batch.logits   + offset,231        };232    }233};234 235// Helper function for decoding an image whose embeddings have already been calculated236int32_t mtmd_helper_decode_image_chunk(237        mtmd_context * ctx,238        struct llama_context * lctx,239        const mtmd_input_chunk * chunk,240        float * encoded_embd,241        llama_pos n_past,242        llama_seq_id seq_id,243        int32_t n_batch,244        llama_pos * new_n_past) {245    GGML_ASSERT(n_batch > 0);246    auto chunk_type = mtmd_input_chunk_get_type(chunk);247    const char * name = chunk_type == MTMD_INPUT_CHUNK_TYPE_IMAGE ? "image" : "audio";248    if (chunk_type == MTMD_INPUT_CHUNK_TYPE_TEXT) {249        LOG_ERR("failed to decode chunk: input chunk not of image/audio type\n");250        return -1;251    }252 253    const llama_model * model = llama_get_model(lctx);254    int n_mmproj_embd = llama_model_n_embd_inp(model);255    int n_pos_per_embd = mtmd_decode_use_mrope(ctx) ? 4 : 1;256 257    int32_t n_tokens = mtmd_input_chunk_get_n_tokens(chunk);258    int32_t i_batch = 0;259    int32_t n_img_batches = (n_tokens + n_batch - 1) / n_batch;260    decode_embd_batch batch_embd(encoded_embd, n_tokens, n_pos_per_embd, n_mmproj_embd);261 262    if (mtmd_decode_use_mrope(ctx)) {263        if (chunk_type == MTMD_INPUT_CHUNK_TYPE_IMAGE) {264            const auto image_tokens = mtmd_input_chunk_get_tokens_image(chunk);265            if (!image_tokens) {266                LOG_ERR("failed to decode chunk: image tokens are null\n");267                return -1;268            }269            const auto n_tokens = mtmd_image_tokens_get_n_tokens(image_tokens);270            std::vector<mtmd_decoder_pos> rel_pos(n_tokens);271            mtmd_helper_image_get_decoder_pos(image_tokens, n_past, rel_pos.data());272            batch_embd.set_position_mrope_2d(rel_pos, seq_id);273        } else if (chunk_type == MTMD_INPUT_CHUNK_TYPE_AUDIO) {274            batch_embd.set_position_mrope_1d(n_past, seq_id);275        } else {276            GGML_ABORT("invalid chunk type for M-RoPE");277        }278    } else {279        batch_embd.set_position_normal(n_past, seq_id);280    }281 282    const bool use_non_causal = mtmd_decode_use_non_causal(ctx, chunk);283    if (use_non_causal) {284        llama_set_causal_attn(lctx, false);285        // TODO @ngxson : need to make sure only one image is processed at a time, and n_ubatch must be enough to hold the image286    }287 288    while (i_batch < n_img_batches) { // split into batches289        int pos_offset = i_batch*n_batch;290        int n_tokens_batch = std::min(n_batch, n_tokens - pos_offset);291        llama_batch batch_embd_view = batch_embd.get_view(pos_offset, n_tokens_batch);292 293        LOG_INF("decoding %s batch %d/%d, n_tokens_batch = %d\n", name, i_batch+1, n_img_batches, n_tokens_batch);294 295        int64_t t1 = ggml_time_ms();296        int32_t ret = llama_decode(lctx, batch_embd_view);297        if (ret != 0) {298            LOG_ERR("failed to decode %s\n", name);299            llama_set_causal_attn(lctx, true); // restore causal attn300            return ret;301        }302 303        LOG_INF("%s decoded (batch %d/%d) in %" PRId64 " ms\n", name, i_batch+1, n_img_batches, ggml_time_ms() - t1);304 305        i_batch++;306    }307 308    n_past += mtmd_input_chunk_get_n_pos(chunk);309    *new_n_past = n_past;310 311    if (use_non_causal) {312        llama_set_causal_attn(lctx, true);313    }314    return 0;315}316 317int32_t mtmd_helper_eval_chunk_single(mtmd_context * ctx,318        struct llama_context * lctx,319        const mtmd_input_chunk * chunk,320        llama_pos n_past,321        llama_seq_id seq_id,322        int32_t n_batch,323        bool logits_last,324        llama_pos * new_n_past) {325    GGML_ASSERT(n_batch > 0);326    int32_t ret;327    llama_batch text_batch = llama_batch_init(n_batch, 0, 1);328    auto chunk_type = mtmd_input_chunk_get_type(chunk);329 330    if (chunk_type == MTMD_INPUT_CHUNK_TYPE_TEXT) {331        size_t n_tokens;332        const auto tokens = mtmd_input_chunk_get_tokens_text(chunk, &n_tokens);333        // LOG_INF("decoding text chunk, n_tokens = %zu\n", n_tokens);334        size_t i = 0;335        while (i < n_tokens) { // split into batches336            text_batch.n_tokens = 0; // clear the batch337            for (; i < n_tokens && text_batch.n_tokens < n_batch; i++) {338                int32_t j = text_batch.n_tokens;339                text_batch.token   [j]    = tokens[i];340                text_batch.pos     [j]    = n_past++;341                text_batch.n_seq_id[j]    = 1;342                text_batch.seq_id  [j][0] = seq_id;343                text_batch.logits  [j]    = false;344 345                text_batch.n_tokens++;346            }347            bool is_last_token = (i == n_tokens);348            if (logits_last && is_last_token) {349                text_batch.logits[text_batch.n_tokens - 1] = true;350            }351            ret = llama_decode(lctx, text_batch);352            if (ret != 0) {353                LOG_ERR("failed to decode text\n");354                llama_batch_free(text_batch);355                return ret;356            }357            *new_n_past += text_batch.n_tokens;358        }359 360    } else if (chunk_type == MTMD_INPUT_CHUNK_TYPE_IMAGE || chunk_type == MTMD_INPUT_CHUNK_TYPE_AUDIO) {361        const char * name = chunk_type == MTMD_INPUT_CHUNK_TYPE_IMAGE ? "image" : "audio";362        int64_t t0 = ggml_time_ms();363 364        LOG_INF("encoding %s slice...\n", name);365 366        ret = mtmd_encode_chunk(ctx, chunk);367        if (ret != 0) {368            LOG_ERR("failed to encode %s slice\n", name);369            llama_batch_free(text_batch);370            return ret;371        }372 373        LOG_INF("%s slice encoded in %" PRId64 " ms\n", name, ggml_time_ms() - t0);374 375        float * embd = mtmd_get_output_embd(ctx);376        ret = mtmd_helper_decode_image_chunk(ctx, lctx, chunk, embd, n_past, seq_id, n_batch, new_n_past);377        if (ret != 0) {378            LOG_ERR("failed to decode %s\n", name);379            llama_batch_free(text_batch);380            return ret;381        }382    } else {383        GGML_ABORT("chunk type not supported");384    }385 386    llama_batch_free(text_batch);387    return 0;388}389 390int32_t mtmd_helper_eval_chunks(mtmd_context * ctx,391                                struct llama_context * lctx,392                                const mtmd_input_chunks * chunks,393                                llama_pos n_past,394                                llama_seq_id seq_id,395                                int32_t n_batch,396                                bool logits_last,397                                llama_pos * new_n_past) {398    size_t n_chunks = mtmd_input_chunks_size(chunks);399    if (n_chunks == 0) {400        LOG_WRN("no chunks to eval\n");401        return 0;402    }403 404    for (size_t i = 0; i < n_chunks; i++) {405        bool chunk_logits_last = (i == n_chunks - 1) && logits_last;406        auto chunk = mtmd_input_chunks_get(chunks, i);407 408        int32_t res = mtmd_helper_eval_chunk_single(ctx, lctx, chunk, n_past, seq_id, n_batch, chunk_logits_last, &n_past);409        if (res != 0) {410            LOG_ERR("failed to eval chunk %zu\n", i);411            return res;412        }413        *new_n_past = n_past;414    }415 416    return 0;417}418 419namespace audio_helpers {420 421static bool is_audio_file(const char * buf, size_t len) {422    if (len < 12) {423        return false;424    }425 426    // RIFF ref: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format427    // WAV ref: https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html428    bool is_wav = memcmp(buf, "RIFF", 4) == 0 && memcmp(buf + 8, "WAVE", 4) == 0;429    bool is_mp3 = len >= 3 && (430        memcmp(buf, "ID3", 3) == 0 ||431        // Check for MPEG sync word (simplified check)432        ((unsigned char)buf[0] == 0xFF && ((unsigned char)buf[1] & 0xE0) == 0xE0)433    );434    bool is_flac = memcmp(buf, "fLaC", 4) == 0;435 436    return is_wav || is_mp3 || is_flac;437}438 439// returns true if the buffer is a valid audio file440static bool decode_audio_from_buf(const unsigned char * buf_in, size_t len, int target_sampler_rate, std::vector<float> & pcmf32_mono) {441    ma_result result;442    const int channels = 1;443    ma_decoder_config decoder_config = ma_decoder_config_init(ma_format_f32, channels, target_sampler_rate);444    ma_decoder decoder;445 446    result = ma_decoder_init_memory(buf_in, len, &decoder_config, &decoder);447    if (result != MA_SUCCESS) {448        return false;449    }450 451    ma_uint64 frame_count;452    ma_uint64 frames_read;453    result = ma_decoder_get_length_in_pcm_frames(&decoder, &frame_count);454    if (result != MA_SUCCESS) {455        ma_decoder_uninit(&decoder);456        return false;457    }458 459    pcmf32_mono.resize(frame_count);460    result = ma_decoder_read_pcm_frames(&decoder, pcmf32_mono.data(), frame_count, &frames_read);461    if (result != MA_SUCCESS) {462        ma_decoder_uninit(&decoder);463        return false;464    }465 466#ifdef MTMD_AUDIO_DEBUG467    // save audio to wav file468    ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, ma_format_f32, 1, target_sampler_rate);469    ma_encoder encoder;470    ma_encoder_init_file("output.wav", &config, &encoder);471    ma_encoder_write_pcm_frames(&encoder, pcmf32_mono.data(), pcmf32_mono.size(), &frames_read);472    ma_encoder_uninit(&encoder);473#endif474 475    ma_decoder_uninit(&decoder);476    return true;477}478 479} // namespace audio_helpers480 481mtmd_bitmap * mtmd_helper_bitmap_init_from_buf(mtmd_context * ctx, const unsigned char * buf, size_t len) {482    if (audio_helpers::is_audio_file((const char *)buf, len)) {483        std::vector<float> pcmf32;484        const int sample_rate = mtmd_get_audio_sample_rate(ctx);485        if (sample_rate < 0) {486            LOG_ERR("This model does not support audio input\n");487            return nullptr;488        }489        if (!audio_helpers::decode_audio_from_buf(buf, len, sample_rate, pcmf32)) {490            LOG_ERR("Unable to read WAV audio file from buffer\n");491            return nullptr;492        }493        return mtmd_bitmap_init_from_audio(pcmf32.size(), pcmf32.data());494    }495 496    // otherwise, we assume it's an image497    mtmd_bitmap * result = nullptr;498    {499        int nx, ny, nc;500        auto * data = stbi_load_from_memory(buf, len, &nx, &ny, &nc, 3);501        if (!data) {502            LOG_ERR("%s: failed to decode image bytes\n", __func__);503            return nullptr;504        }505        result = mtmd_bitmap_init(nx, ny, data);506        stbi_image_free(data);507    }508    return result;509}510 511mtmd_bitmap * mtmd_helper_bitmap_init_from_file(mtmd_context * ctx, const char * fname) {512    std::vector<unsigned char> buf;513    FILE * f = fopen(fname, "rb");514    if (!f) {515        LOG_ERR("Unable to open file %s: %s\n", fname, strerror(errno));516        return nullptr;517    }518 519    fseek(f, 0, SEEK_END);520    long file_size = ftell(f);521    fseek(f, 0, SEEK_SET);522    if (file_size < 0) {523        LOG_ERR("Failed to get file size of %s\n", fname);524        fclose(f);525        return nullptr;526    }527    buf.resize(file_size);528 529    size_t n_read = fread(buf.data(), 1, file_size, f);530    fclose(f);531    if (n_read != (size_t)file_size) {532        LOG_ERR("Failed to read entire file %s", fname);533        return nullptr;534    }535 536    return mtmd_helper_bitmap_init_from_buf(ctx, buf.data(), buf.size());537}538