server: save processed mtmd chunks as placeholder (#27278)
This commit is contained in:
+32
-14
@@ -2322,23 +2322,12 @@ void mtmd_input_chunk_free(mtmd_input_chunk * chunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, size_t out_len, size_t * expected_out_len) {
|
// returns 0 on success
|
||||||
|
static int32_t mtmd_input_chunk_save_impl(const mtmd_input_chunk * chunk, std::vector<char> & out_buf) {
|
||||||
try {
|
try {
|
||||||
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION);
|
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION);
|
||||||
chunk->serialize(ser);
|
chunk->serialize(ser);
|
||||||
|
out_buf = std::move(ser.data);
|
||||||
if (expected_out_len) {
|
|
||||||
*expected_out_len = ser.data.size();
|
|
||||||
}
|
|
||||||
if (!out_buf) {
|
|
||||||
// caller is only querying the required size
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (out_len < ser.data.size()) {
|
|
||||||
LOG_ERR("%s: out_buf is too small, need %zu bytes, got %zu\n", __func__, ser.data.size(), out_len);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
std::memcpy(out_buf, ser.data.data(), ser.data.size());
|
|
||||||
return 0;
|
return 0;
|
||||||
} catch (const std::exception & e) {
|
} catch (const std::exception & e) {
|
||||||
LOG_ERR("%s: %s\n", __func__, e.what());
|
LOG_ERR("%s: %s\n", __func__, e.what());
|
||||||
@@ -2346,6 +2335,35 @@ int32_t mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, si
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtmd_input_chunk * mtmd_input_chunk_get_placeholder(const mtmd_input_chunk * chunk) {
|
||||||
|
// this is hacky, but still faster than copy the whole batch data
|
||||||
|
std::vector<char> buf;
|
||||||
|
if (mtmd_input_chunk_save_impl(chunk, buf) != 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return mtmd_input_chunk_load(buf.data(), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, size_t out_len, size_t * expected_out_len) {
|
||||||
|
std::vector<char> buf;
|
||||||
|
if (mtmd_input_chunk_save_impl(chunk, buf) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (expected_out_len) {
|
||||||
|
*expected_out_len = buf.size();
|
||||||
|
}
|
||||||
|
if (!out_buf) {
|
||||||
|
// caller is only querying the required size
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (out_len < buf.size()) {
|
||||||
|
LOG_ERR("%s: out_buf is too small, need %zu bytes, got %zu\n", __func__, buf.size(), out_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::memcpy(out_buf, buf.data(), buf.size());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
mtmd_input_chunk * mtmd_input_chunk_load(const char * buf, size_t len) {
|
mtmd_input_chunk * mtmd_input_chunk_load(const char * buf, size_t len) {
|
||||||
try {
|
try {
|
||||||
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION, buf, len);
|
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION, buf, len);
|
||||||
|
|||||||
@@ -233,6 +233,9 @@ MTMD_API llama_pos mtmd_input_chunk_get_n_pos (const mtmd
|
|||||||
MTMD_API mtmd_input_chunk * mtmd_input_chunk_copy(const mtmd_input_chunk * chunk);
|
MTMD_API mtmd_input_chunk * mtmd_input_chunk_copy(const mtmd_input_chunk * chunk);
|
||||||
MTMD_API void mtmd_input_chunk_free(mtmd_input_chunk * chunk);
|
MTMD_API void mtmd_input_chunk_free(mtmd_input_chunk * chunk);
|
||||||
|
|
||||||
|
// similar to mtmd_input_chunk_copy, but returns a placeholder chunk
|
||||||
|
MTMD_API mtmd_input_chunk * mtmd_input_chunk_get_placeholder(const mtmd_input_chunk * chunk);
|
||||||
|
|
||||||
// save/load an input chunk to/from a buffer (useful for KV save/load)
|
// save/load an input chunk to/from a buffer (useful for KV save/load)
|
||||||
// important: only chunk's metadata will be saved, the actual image/audio data will not be saved
|
// important: only chunk's metadata will be saved, the actual image/audio data will not be saved
|
||||||
// the loaded chunk will always be a placeholder, cannot be used for mtmd_encode() or mtmd_batch_encode()
|
// the loaded chunk will always be a placeholder, cannot be used for mtmd_encode() or mtmd_batch_encode()
|
||||||
|
|||||||
@@ -507,6 +507,23 @@ void server_tokens::push_back(const mtmd_input_chunk * chunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void server_tokens::push_back_placeholder(const mtmd_input_chunk * chunk) {
|
||||||
|
auto type = mtmd_input_chunk_get_type(chunk);
|
||||||
|
if (type == MTMD_INPUT_CHUNK_TYPE_IMAGE || type == MTMD_INPUT_CHUNK_TYPE_AUDIO) {
|
||||||
|
GGML_ASSERT(has_mtmd);
|
||||||
|
mtmd::input_chunk_ptr new_chunk(mtmd_input_chunk_get_placeholder(chunk));
|
||||||
|
GGML_ASSERT(new_chunk != nullptr && "failed to create placeholder chunk");
|
||||||
|
const size_t n_tokens = mtmd_input_chunk_get_n_tokens(chunk);
|
||||||
|
size_t start_idx = tokens.size();
|
||||||
|
for (size_t i = 0; i < n_tokens; ++i) {
|
||||||
|
tokens.emplace_back(LLAMA_TOKEN_NULL);
|
||||||
|
}
|
||||||
|
map_idx_to_media[start_idx] = std::move(new_chunk);
|
||||||
|
} else {
|
||||||
|
push_back(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void server_tokens::push_back(server_tokens & tokens) {
|
void server_tokens::push_back(server_tokens & tokens) {
|
||||||
size_t start_idx = size();
|
size_t start_idx = size();
|
||||||
for (size_t i = 0; i < tokens.size(); i++) {
|
for (size_t i = 0; i < tokens.size(); i++) {
|
||||||
|
|||||||
@@ -195,6 +195,10 @@ public:
|
|||||||
// will create a copy of the chunk if it contains non-text data
|
// will create a copy of the chunk if it contains non-text data
|
||||||
void push_back(const mtmd_input_chunk * chunk);
|
void push_back(const mtmd_input_chunk * chunk);
|
||||||
|
|
||||||
|
// same as push_back, but media chunks are stored as placeholders (no image/audio data)
|
||||||
|
// only use this if the chunk will never be encoded again (e.g. it is already in the KV cache)
|
||||||
|
void push_back_placeholder(const mtmd_input_chunk * chunk);
|
||||||
|
|
||||||
// appends server tokens, updates the media map. copies media chunks.
|
// appends server tokens, updates the media map. copies media chunks.
|
||||||
void push_back(server_tokens & tokens);
|
void push_back(server_tokens & tokens);
|
||||||
|
|
||||||
|
|||||||
@@ -3416,7 +3416,8 @@ private:
|
|||||||
// add the mtmd chunk to cache
|
// add the mtmd chunk to cache
|
||||||
{
|
{
|
||||||
const auto & chunk = input_tokens.find_chunk(cur_token_idx);
|
const auto & chunk = input_tokens.find_chunk(cur_token_idx);
|
||||||
slot.prompt.tokens.push_back(chunk.get()); // copy
|
// the chunk is already in the KV cache at this point, so we don't need to keep its data around
|
||||||
|
slot.prompt.tokens.push_back_placeholder(chunk.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
has_mtmd = true;
|
has_mtmd = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user