From 7a49a6f6dc4ce3169ff465af7154d5ab74720706 Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 19:28:47 +0800 Subject: [PATCH 01/57] init --- .gitignore | 1 + Makefile | 9 +- convert-hf-to-gguf.py | 38 - examples/CMakeLists.txt | 1 + examples/minicpmv/CMakeLists.txt | 42 + examples/minicpmv/README.md | 19 + examples/minicpmv/android/adb_run.sh | 53 + examples/minicpmv/clip.cpp | 2178 +++++++++++++++++ examples/minicpmv/clip.h | 86 + examples/minicpmv/minicpmv-cli.cpp | 158 ++ .../minicpmv-convert-image-encoder-to-gguf.py | 382 +++ examples/minicpmv/minicpmv-surgery.py | 48 + examples/minicpmv/minicpmv.cpp | 663 +++++ examples/minicpmv/minicpmv.h | 50 + examples/minicpmv/minicpmv_io.cpp | 153 ++ examples/minicpmv/minicpmv_io.h | 49 + examples/minicpmv/requirements.txt | 3 + gguf-py/gguf/constants.py | 1 + llama.cpp | 283 +-- 19 files changed, 3926 insertions(+), 291 deletions(-) create mode 100644 examples/minicpmv/CMakeLists.txt create mode 100644 examples/minicpmv/README.md create mode 100755 examples/minicpmv/android/adb_run.sh create mode 100644 examples/minicpmv/clip.cpp create mode 100644 examples/minicpmv/clip.h create mode 100644 examples/minicpmv/minicpmv-cli.cpp create mode 100644 examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py create mode 100644 examples/minicpmv/minicpmv-surgery.py create mode 100644 examples/minicpmv/minicpmv.cpp create mode 100644 examples/minicpmv/minicpmv.h create mode 100644 examples/minicpmv/minicpmv_io.cpp create mode 100644 examples/minicpmv/minicpmv_io.h create mode 100644 examples/minicpmv/requirements.txt diff --git a/.gitignore b/.gitignore index 50ae0973ae3b3..0ba9d810d345e 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ models-mnt /libllama.so /llama-bench /llava-cli +/minicpmv-cli /lookahead /lookup /lookup-create diff --git a/Makefile b/Makefile index fe63cbd6063aa..b34a868d3f009 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Define the default target now so that it is always the first target BUILD_TARGETS = \ main quantize quantize-stats perplexity imatrix embedding vdot q8dot train-text-from-scratch convert-llama2c-to-ggml \ - simple batched batched-bench save-load-state server gguf gguf-split eval-callback llama-bench libllava.a llava-cli baby-llama beam-search \ + simple batched batched-bench save-load-state server gguf gguf-split eval-callback llama-bench libllava.a llava-cli minicpmv-cli baby-llama beam-search \ retrieval speculative infill tokenize benchmark-matmult parallel finetune export-lora lookahead lookup passkey gritlm tests/test-c.o # Binaries only useful for tests @@ -859,6 +859,13 @@ llava-cli: examples/llava/llava-cli.cpp examples/llava/clip.h examples/llava/cli $(CXX) $(CXXFLAGS) -c examples/llava/llava.cpp -o $(call GET_OBJ_FILE, examples/llava/llava.cpp) $(CXX) $(CXXFLAGS) $(filter-out %.h $< examples/llava/clip.cpp examples/llava/llava.cpp,$^) $(call GET_OBJ_FILE, $<) $(call GET_OBJ_FILE, examples/llava/clip.cpp) $(call GET_OBJ_FILE, examples/llava/llava.cpp) -o $@ $(LDFLAGS) +minicpmv-cli: examples/minicpmv/minicpmv-cli.cpp examples/minicpmv/clip.h examples/minicpmv/clip.cpp examples/minicpmv/minicpmv.h examples/minicpmv/minicpmv.cpp examples/minicpmv/minicpmv_io.h examples/minicpmv/minicpmv_io.cpp ggml.o llama.o $(COMMON_DEPS) $(OBJS) + $(CXX) $(CXXFLAGS) -c $< -o $(call GET_OBJ_FILE, $<) + $(CXX) $(CXXFLAGS) -c examples/minicpmv/clip.cpp -o $(call GET_OBJ_FILE, examples/minicpmv/clip.cpp) -Wno-cast-qual + $(CXX) $(CXXFLAGS) -c examples/minicpmv/minicpmv.cpp -o $(call GET_OBJ_FILE, examples/minicpmv/minicpmv.cpp) + $(CXX) $(CXXFLAGS) -c examples/minicpmv/minicpmv_io.cpp -o $(call GET_OBJ_FILE, examples/minicpmv/minicpmv_io.cpp) + $(CXX) $(CXXFLAGS) $(filter-out %.h $< examples/minicpmv/clip.cpp examples/minicpmv/minicpmv.cpp examples/minicpmv/minicpmv_io.cpp,$^) $(call GET_OBJ_FILE, $<) $(call GET_OBJ_FILE, examples/minicpmv/clip.cpp) $(call GET_OBJ_FILE, examples/minicpmv/minicpmv.cpp) $(call GET_OBJ_FILE, examples/minicpmv/minicpmv_io.cpp) -o $@ $(LDFLAGS) + baby-llama: examples/baby-llama/baby-llama.cpp ggml.o llama.o $(COMMON_DEPS) train.o $(OBJS) $(CXX) $(CXXFLAGS) -c $< -o $(call GET_OBJ_FILE, $<) $(CXX) $(CXXFLAGS) $(filter-out %.h $<,$^) $(call GET_OBJ_FILE, $<) -o $@ $(LDFLAGS) diff --git a/convert-hf-to-gguf.py b/convert-hf-to-gguf.py index 5a00a5e89accb..daad1c4fc7255 100755 --- a/convert-hf-to-gguf.py +++ b/convert-hf-to-gguf.py @@ -673,44 +673,6 @@ def set_gguf_parameters(self): self.gguf_writer.add_parallel_residual(self.hparams.get("use_parallel_residual", True)) self.gguf_writer.add_layer_norm_eps(self.hparams["layer_norm_eps"]) - def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]: - del bid # unused - - n_head = self.hparams.get("n_head", self.hparams.get("num_attention_heads")) - n_embed = self.hparams.get("hidden_size", self.hparams.get("n_embed")) - - tensors: list[tuple[str, Tensor]] = [] - - if re.match(r"gpt_neox\.layers\.\d+\.attention\.query_key_value\.weight", name): - # Map bloom-style qkv_linear to gpt-style qkv_linear - # bloom: https://github.com/huggingface/transformers/blob/main/src/transformers/models/bloom/modeling_bloom.py#L238-L252 # noqa - # gpt-2: https://github.com/huggingface/transformers/blob/main/src/transformers/models/gpt2/modeling_gpt2.py#L312 # noqa - qkv_weights = data_torch.reshape((n_head, 3, n_embed // n_head, n_embed)) - data_torch = torch.cat( - ( - qkv_weights[:, 0, :, :].reshape((-1, n_embed)), - qkv_weights[:, 1, :, :].reshape((-1, n_embed)), - qkv_weights[:, 2, :, :].reshape((-1, n_embed)), - ), - dim=0, - ) - logger.info("re-format attention.linear_qkv.weight") - elif re.match(r"gpt_neox\.layers\.\d+\.attention\.query_key_value\.bias", name): - qkv_bias = data_torch.reshape((n_head, 3, n_embed // n_head)) - data_torch = torch.cat( - ( - qkv_bias[:, 0, :].reshape((n_embed,)), - qkv_bias[:, 1, :].reshape((n_embed,)), - qkv_bias[:, 2, :].reshape((n_embed,)), - ), - dim=0, - ) - logger.info("re-format attention.linear_qkv.bias") - - tensors.append((self.map_tensor_name(name), data_torch)) - - return tensors - @Model.register("BloomForCausalLM") class BloomModel(Model): diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b40ee4ccb2ec1..d8c95f36d0489 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -26,6 +26,7 @@ else() add_subdirectory(infill) add_subdirectory(llama-bench) add_subdirectory(llava) + add_subdirectory(minicpmv) if (LLAMA_SYCL) add_subdirectory(sycl) endif() diff --git a/examples/minicpmv/CMakeLists.txt b/examples/minicpmv/CMakeLists.txt new file mode 100644 index 0000000000000..80dd8741115db --- /dev/null +++ b/examples/minicpmv/CMakeLists.txt @@ -0,0 +1,42 @@ +add_library(minicpmv OBJECT + minicpmv.cpp + minicpmv.h + clip.cpp + clip.h + ) + +target_link_libraries(minicpmv PRIVATE ggml llama ${CMAKE_THREAD_LIBS_INIT}) + +target_include_directories(minicpmv PUBLIC .) +target_include_directories(minicpmv PUBLIC ../..) +target_include_directories(minicpmv PUBLIC ../../common) + +target_compile_features(minicpmv PRIVATE cxx_std_11) + +add_library(minicpmv_static STATIC $) +if (BUILD_SHARED_LIBS) + set_target_properties(minicpmv PROPERTIES POSITION_INDEPENDENT_CODE ON) + target_compile_definitions(minicpmv PRIVATE LLAMA_SHARED LLAMA_BUILD) + add_library(minicpmv_shared SHARED $) + target_link_libraries(minicpmv_shared PRIVATE ggml llama ${CMAKE_THREAD_LIBS_INIT}) + install(TARGETS minicpmv_shared LIBRARY) +endif() + +if (NOT MSVC) + target_compile_options(minicpmv PRIVATE -Wno-cast-qual) # stb_image.h +endif() + +if(TARGET BUILD_INFO) + add_dependencies(minicpmv BUILD_INFO) +endif() + +set(TARGET minicpmv-cli) +add_executable(minicpmv-cli minicpmv-cli.cpp) +install(TARGETS minicpmv-cli RUNTIME) +target_link_libraries(minicpmv-cli PRIVATE common minicpmv ${CMAKE_THREAD_LIBS_INIT}) +target_compile_features(minicpmv PRIVATE cxx_std_11) + +add_library(minicpmv_io OBJECT + minicpmv_io.cpp +) +target_link_libraries(minicpmv_io PRIVATE llava ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md new file mode 100644 index 0000000000000..fad1e033691a0 --- /dev/null +++ b/examples/minicpmv/README.md @@ -0,0 +1,19 @@ +# 所有命令在 llama.cpp 根目录执行,模型位于根目录上级目录处 +# All command should be executed under the root path of llama.cpp repo. We assume the MiniCPM-V-2.5 model are put in its parent folder. + +```bash +make +make minicpmv-cli + +python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-V-2_5 +python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-V-2_5 --llava-projector ../MiniCPM-V-2_5/llava.projector --output-dir ../MiniCPM-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 +python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe +./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-f16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" + +# or run quantize int4 version +./quantize ../MiniCPM-V-2_5/model/ggml-model-f16.gguf ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M +./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.6 --top-p 0.8 --top-k 100 --repeat-penalty 1.0 --image xx.jpg -p "What is in the image?" + +# or run in interactive mode +./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.6 --top-p 0.8 --top-k 100 --repeat-penalty 1.0 --image xx.jpg -i +``` \ No newline at end of file diff --git a/examples/minicpmv/android/adb_run.sh b/examples/minicpmv/android/adb_run.sh new file mode 100755 index 0000000000000..2fbcd19b22b11 --- /dev/null +++ b/examples/minicpmv/android/adb_run.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +model_dir="/Users/cxt/model/llm/mobileVLM/MobileVLM-1.7B_processed" +projector_name="mmproj-model-f16.gguf" +llama_name="ggml-model-q4_k.gguf" +img_dir="/Users/cxt/model/llm" +img_name="demo.jpg" +prompt="A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions. USER: \nWho is the author of this book? \nAnswer the question using a single word or phrase. ASSISTANT:" +# img_name="cat.jpeg" +# prompt="A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions. USER: \nWhat is in the image? ASSISTANT:" + +program_dir="build_64/bin" +binName="minicpmv-cli" +n_threads=4 + + +deviceDir="/data/local/tmp" +saveDir="output" +if [ ! -d ${saveDir} ]; then + mkdir ${saveDir} +fi + + +function android_run() { + # # copy resource into device + # adb push ${model_dir}/${projector_name} ${deviceDir}/${projector_name} + # adb push ${model_dir}/${llama_name} ${deviceDir}/${llama_name} + adb push ${img_dir}/${img_name} ${deviceDir}/${img_name} + # copy program into device + adb push ${program_dir}/${binName} ${deviceDir}/${binName} + adb shell "chmod 0777 ${deviceDir}/${binName}" + + # run + adb shell "echo cd ${deviceDir} ${deviceDir}/${binName} \ + -m ${deviceDir}/${llama_name} \ + --mmproj ${deviceDir}/${projector_name} \ + -t ${n_threads} \ + --image ${deviceDir}/${img_name} \ + -p \"${prompt}\" \ + > ${deviceDir}/${modelName}_${projector_name}_${n_threads}_${img_name}.txt" + adb shell "cd ${deviceDir}; pwd; ${deviceDir}/${binName} \ + -m ${deviceDir}/${llama_name} \ + --mmproj ${deviceDir}/${projector_name} \ + -t ${n_threads} \ + --image ${deviceDir}/${img_name} \ + -p \"${prompt}\" \ + >> ${deviceDir}/${modelName}_${projector_name}_${n_threads}_${img_name}.txt 2>&1" + adb pull ${deviceDir}/${modelName}_${projector_name}_${n_threads}_${img_name}.txt ${saveDir} +} + +android_run + +echo "android_run is Done!" diff --git a/examples/minicpmv/clip.cpp b/examples/minicpmv/clip.cpp new file mode 100644 index 0000000000000..b09c5883f200f --- /dev/null +++ b/examples/minicpmv/clip.cpp @@ -0,0 +1,2178 @@ +// NOTE: This is modified from clip.cpp only for LLaVA, +// so there might be still unnecessary artifacts hanging around +// I'll gradually clean and extend it +// Note: Even when using identical normalized image inputs (see normalize_image_u8_to_f32()) we have a significant difference in resulting embeddings compared to pytorch +#include "clip.h" +#include "log.h" +#include "ggml.h" +#include "ggml-alloc.h" +#include "ggml-backend.h" + +#ifdef GGML_USE_CUDA +#include "ggml-cuda.h" +#endif + +#ifdef GGML_USE_METAL +#include "ggml-metal.h" +#endif + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define CLIP_DEBUG_FUNCTIONS + +// RGB uint8 image +struct clip_image_u8 { + int nx; + int ny; + + std::vector buf; +}; + +// RGB float32 image (NHWC) +// Memory layout: RGBRGBRGB... +struct clip_image_f32 { + int nx; + int ny; + + std::vector buf; +}; + +static std::string format(const char * fmt, ...) { + va_list ap; + va_list ap2; + va_start(ap, fmt); + va_copy(ap2, ap); + int size = vsnprintf(NULL, 0, fmt, ap); + GGML_ASSERT(size >= 0 && size < INT_MAX); // NOLINT + std::vector buf(size + 1); + int size2 = vsnprintf(buf.data(), size + 1, fmt, ap2); + GGML_ASSERT(size2 == size); + va_end(ap2); + va_end(ap); + return std::string(buf.data(), buf.size()); +} + +// +// key constants +// + +#define KEY_FTYPE "general.file_type" +#define KEY_NAME "general.name" +#define KEY_DESCRIPTION "general.description" +#define KEY_HAS_TEXT_ENC "clip.has_text_encoder" +#define KEY_HAS_VIS_ENC "clip.has_vision_encoder" +#define KEY_HAS_LLAVA_PROJ "clip.has_llava_projector" +#define KEY_USE_GELU "clip.use_gelu" +#define KEY_N_EMBD "clip.%s.embedding_length" +#define KEY_N_FF "clip.%s.feed_forward_length" +#define KEY_N_BLOCK "clip.%s.block_count" +#define KEY_N_HEAD "clip.%s.attention.head_count" +#define KEY_LAYER_NORM_EPS "clip.%s.attention.layer_norm_epsilon" +#define KEY_PROJ_DIM "clip.%s.projection_dim" +#define KEY_TOKENS "tokenizer.ggml.tokens" +#define KEY_N_POSITIONS "clip.text.context_length" +#define KEY_IMAGE_SIZE "clip.vision.image_size" +#define KEY_PATCH_SIZE "clip.vision.patch_size" +#define KEY_IMAGE_MEAN "clip.vision.image_mean" +#define KEY_IMAGE_STD "clip.vision.image_std" +#define KEY_PROJ_TYPE "clip.projector_type" + +#define KEY_MM_PATCH_MERGE_TYPE "clip.vision.mm_patch_merge_type" +#define KEY_IMAGE_GRID_PINPOINTS "clip.vision.image_grid_pinpoints" +#define KEY_IMAGE_CROP_RESOLUTION "clip.vision.image_crop_resolution" + + +// +// tensor name constants +// + +#define TN_TOKEN_EMBD "%s.token_embd.weight" +// #define TN_POS_EMBD "%s.position_embd" +// // #define TN_CLASS_EMBD "v.class_embd" +// #define TN_PATCH_EMBD "v.patch_embd.proj.%s" +#define TN_POS_EMBD "%s.position_embd.weight" +// #define TN_CLASS_EMBD "v.class_embd" +#define TN_PATCH_EMBD "v.patch_embd.%s" +#define TN_ATTN_K "%s.blk.%d.attn_k.%s" +#define TN_ATTN_Q "%s.blk.%d.attn_q.%s" +#define TN_ATTN_V "%s.blk.%d.attn_v.%s" +#define TN_ATTN_OUTPUT "%s.blk.%d.attn_out.%s" +#define TN_FFN_DOWN "%s.blk.%d.ffn_down.%s" +#define TN_FFN_UP "%s.blk.%d.ffn_up.%s" +#define TN_LN_1 "%s.blk.%d.ln1.%s" +#define TN_LN_2 "%s.blk.%d.ln2.%s" +// #define TN_LN_PRE "%s.pre_ln.%s" +#define TN_LN_POST "%s.post_ln.%s" +#define TN_TEXT_PROJ "text_projection.weight" +#define TN_VIS_PROJ "visual_projection.weight" +#define TN_LLAVA_PROJ "mm.%d.%s" +#define TN_MVLM_PROJ_MLP "mm.model.mlp.%d.%s" +#define TN_MVLM_PROJ_BLOCK "mm.model.mb_block.%d.block.%d.%s" +#define TN_MVLM_PROJ_PEG "mm.model.peg.%d.%s" +#define TN_IMAGE_NEWLINE "model.image_newline" +// MINICPMV +// #define TN_MINICPMV_POS_EMBD "resampler.pos_embed" +#define TN_MINICPMV_POS_EMBD_K "resampler.pos_embed_k" +#define TN_MINICPMV_QUERY "resampler.query" +#define TN_MINICPMV_PROJ "resampler.proj.weight" +#define TN_MINICPMV_KV_PROJ "resampler.kv.weight" +#define TN_MINICPMV_ATTN "resampler.attn.%s.%s" +#define TN_MINICPMV_LN "resampler.ln_%s.%s" + + +enum projector_type { + PROJECTOR_TYPE_MLP, + PROJECTOR_TYPE_MLP_NORM, + PROJECTOR_TYPE_LDP, + PROJECTOR_TYPE_LDPV2, + PROJECTOR_TYPE_RESAMPLER, + PROJECTOR_TYPE_UNKNOWN, +}; + +static std::map PROJECTOR_TYPE_NAMES = { + { PROJECTOR_TYPE_MLP, "mlp" }, + { PROJECTOR_TYPE_LDP, "ldp" }, + { PROJECTOR_TYPE_LDPV2, "ldpv2"}, + { PROJECTOR_TYPE_RESAMPLER, "resampler"}, +}; + + +// +// utilities to get data from a gguf file +// + +static int get_key_idx(const gguf_context * ctx, const char * key) { + int i = gguf_find_key(ctx, key); + if (i == -1) { + LOG_TEE("key %s not found in file\n", key); + throw std::runtime_error(format("Missing required key: %s", key)); + } + + return i; +} + +static uint32_t get_u32(const gguf_context * ctx, const std::string & key) { + const int i = get_key_idx(ctx, key.c_str()); + + return gguf_get_val_u32(ctx, i); +} + +static float get_f32(const gguf_context * ctx, const std::string & key) { + const int i = get_key_idx(ctx, key.c_str()); + + return gguf_get_val_f32(ctx, i); +} + +static struct ggml_tensor * get_tensor(struct ggml_context * ctx, const std::string & name) { + struct ggml_tensor * cur = ggml_get_tensor(ctx, name.c_str()); + if (!cur) { + throw std::runtime_error(format("%s: unable to find tensor %s\n", __func__, name.c_str())); + } + + return cur; +} + +static std::string get_ftype(int ftype) { + return ggml_type_name(static_cast(ftype)); +} + +static std::string gguf_data_to_str(enum gguf_type type, const void * data, int i) { + switch (type) { + case GGUF_TYPE_UINT8: return std::to_string(((const uint8_t *)data)[i]); + case GGUF_TYPE_INT8: return std::to_string(((const int8_t *)data)[i]); + case GGUF_TYPE_UINT16: return std::to_string(((const uint16_t *)data)[i]); + case GGUF_TYPE_INT16: return std::to_string(((const int16_t *)data)[i]); + case GGUF_TYPE_UINT32: return std::to_string(((const uint32_t *)data)[i]); + case GGUF_TYPE_INT32: return std::to_string(((const int32_t *)data)[i]); + case GGUF_TYPE_UINT64: return std::to_string(((const uint64_t *)data)[i]); + case GGUF_TYPE_INT64: return std::to_string(((const int64_t *)data)[i]); + case GGUF_TYPE_FLOAT32: return std::to_string(((const float *)data)[i]); + case GGUF_TYPE_FLOAT64: return std::to_string(((const double *)data)[i]); + case GGUF_TYPE_BOOL: return ((const bool *)data)[i] ? "true" : "false"; + default: return format("unknown type %d", type); + } +} + +static void replace_all(std::string & s, const std::string & search, const std::string & replace) { + std::string result; + for (size_t pos = 0; ; pos += search.length()) { + auto new_pos = s.find(search, pos); + if (new_pos == std::string::npos) { + result += s.substr(pos, s.size() - pos); + break; + } + result += s.substr(pos, new_pos - pos) + replace; + pos = new_pos; + } + s = std::move(result); +} + +static std::string gguf_kv_to_str(const struct gguf_context * ctx_gguf, int i) { + const enum gguf_type type = gguf_get_kv_type(ctx_gguf, i); + + switch (type) { + case GGUF_TYPE_STRING: + return gguf_get_val_str(ctx_gguf, i); + case GGUF_TYPE_ARRAY: + { + const enum gguf_type arr_type = gguf_get_arr_type(ctx_gguf, i); + int arr_n = gguf_get_arr_n(ctx_gguf, i); + const void * data = gguf_get_arr_data(ctx_gguf, i); + std::stringstream ss; + ss << "["; + for (int j = 0; j < arr_n; j++) { + if (arr_type == GGUF_TYPE_STRING) { + std::string val = gguf_get_arr_str(ctx_gguf, i, j); + // escape quotes + replace_all(val, "\\", "\\\\"); + replace_all(val, "\"", "\\\""); + ss << '"' << val << '"'; + } else if (arr_type == GGUF_TYPE_ARRAY) { + ss << "???"; + } else { + ss << gguf_data_to_str(arr_type, data, j); + } + if (j < arr_n - 1) { + ss << ", "; + } + } + ss << "]"; + return ss.str(); + } + default: + return gguf_data_to_str(type, gguf_get_val_data(ctx_gguf, i), 0); + } +} + +static void print_tensor_info(const ggml_tensor * tensor, const char * prefix = "") { + size_t tensor_size = ggml_nbytes(tensor); + LOG_TEE("%s: n_dims = %d, name = %s, tensor_size=%zu, shape:[%" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "], type = %s\n", + prefix, ggml_n_dims(tensor), tensor->name, tensor_size, + tensor->ne[0], tensor->ne[1], tensor->ne[2], tensor->ne[3], ggml_type_name(tensor->type)); +} + +static projector_type clip_projector_type_from_string(const std::string & name) { + for (const auto & kv : PROJECTOR_TYPE_NAMES) { // NOLINT + if (kv.second == name) { + return kv.first; + } + } + return PROJECTOR_TYPE_UNKNOWN; +} + +#ifdef CLIP_DEBUG_FUNCTIONS +static void clip_image_write_image_to_ppm(const clip_image_u8& img, const std::string& filename) { + std::ofstream file(filename, std::ios::binary); + if (!file.is_open()) { + LOG_TEE("Failed to open file for writing: %s\n", filename.c_str()); + return; + } + + // PPM header: P6 format, width, height, and max color value + file << "P6\n" << img.nx << " " << img.ny << "\n255\n"; + + // Write pixel data + for (size_t i = 0; i < img.buf.size(); i += 3) { + // PPM expects binary data in RGB format, which matches our image buffer + file.write(reinterpret_cast(&img.buf[i]), 3); + } + + file.close(); +} + +static void clip_image_save_to_bmp(const clip_image_u8& img, const std::string& filename) { + std::ofstream file(filename, std::ios::binary); + if (!file.is_open()) { + LOG_TEE("Failed to open file for writing: %s\n", filename.c_str()); + return; + } + + int fileSize = 54 + 3 * img.nx * img.ny; // File header + info header + pixel data + int bytesPerPixel = 3; + int widthInBytes = img.nx * bytesPerPixel; + int paddingAmount = (4 - (widthInBytes % 4)) % 4; + int stride = widthInBytes + paddingAmount; + + // Bitmap file header + unsigned char fileHeader[14] = { + 'B','M', // Signature + 0,0,0,0, // Image file size in bytes + 0,0,0,0, // Reserved + 54,0,0,0 // Start of pixel array + }; + + // Total file size + fileSize = 54 + (stride * img.ny); + fileHeader[2] = (unsigned char)(fileSize); + fileHeader[3] = (unsigned char)(fileSize >> 8); + fileHeader[4] = (unsigned char)(fileSize >> 16); + fileHeader[5] = (unsigned char)(fileSize >> 24); + + // Bitmap information header (BITMAPINFOHEADER) + unsigned char infoHeader[40] = { + 40,0,0,0, // Size of this header (40 bytes) + 0,0,0,0, // Image width + 0,0,0,0, // Image height + 1,0, // Number of color planes + 24,0, // Bits per pixel + 0,0,0,0, // No compression + 0,0,0,0, // Image size (can be 0 for no compression) + 0,0,0,0, // X pixels per meter (not specified) + 0,0,0,0, // Y pixels per meter (not specified) + 0,0,0,0, // Total colors (color table not used) + 0,0,0,0 // Important colors (all are important) + }; + + // Width and height in the information header + infoHeader[4] = (unsigned char)(img.nx); + infoHeader[5] = (unsigned char)(img.nx >> 8); + infoHeader[6] = (unsigned char)(img.nx >> 16); + infoHeader[7] = (unsigned char)(img.nx >> 24); + infoHeader[8] = (unsigned char)(img.ny); + infoHeader[9] = (unsigned char)(img.ny >> 8); + infoHeader[10] = (unsigned char)(img.ny >> 16); + infoHeader[11] = (unsigned char)(img.ny >> 24); + + // Write file headers + file.write(reinterpret_cast(fileHeader), sizeof(fileHeader)); + file.write(reinterpret_cast(infoHeader), sizeof(infoHeader)); + + // Pixel data + std::vector padding(3, 0); // Max padding size to be added to each row + for (int y = img.ny - 1; y >= 0; --y) { // BMP files are stored bottom-to-top + for (int x = 0; x < img.nx; ++x) { + // Each pixel + size_t pixelIndex = (y * img.nx + x) * 3; + unsigned char pixel[3] = { + img.buf[pixelIndex + 2], // BMP stores pixels in BGR format + img.buf[pixelIndex + 1], + img.buf[pixelIndex] + }; + file.write(reinterpret_cast(pixel), 3); + } + // Write padding for the row + file.write(reinterpret_cast(padding.data()), paddingAmount); + } + + file.close(); +} + +// debug function to convert f32 to u8 +static void clip_image_convert_f32_to_u8(const clip_image_f32& src, clip_image_u8& dst) { + dst.nx = src.nx; + dst.ny = src.ny; + dst.buf.resize(3 * src.nx * src.ny); + for (size_t i = 0; i < src.buf.size(); ++i) { + dst.buf[i] = static_cast(std::min(std::max(int(src.buf[i] * 255.0f), 0), 255)); + } +} +#endif + + +// +// clip layers +// + +struct clip_hparams { + int32_t image_size; + int32_t patch_size; + int32_t hidden_size; + int32_t n_intermediate; + int32_t projection_dim; + int32_t n_head; + int32_t n_layer; + + float eps; + + char mm_patch_merge_type[32] = "flat"; // spatial_unpad or flat (default) + + int32_t image_grid_pinpoints[32]; + int32_t image_crop_resolution; +}; + +struct clip_layer { + // attention + struct ggml_tensor * k_w; + struct ggml_tensor * k_b; + struct ggml_tensor * q_w; + struct ggml_tensor * q_b; + struct ggml_tensor * v_w; + struct ggml_tensor * v_b; + + struct ggml_tensor * o_w; + struct ggml_tensor * o_b; + + // layernorm 1 + struct ggml_tensor * ln_1_w; + struct ggml_tensor * ln_1_b; + + // ff + struct ggml_tensor * ff_i_w; + struct ggml_tensor * ff_i_b; + + struct ggml_tensor * ff_o_w; + struct ggml_tensor * ff_o_b; + + // layernorm 2 + struct ggml_tensor * ln_2_w; + struct ggml_tensor * ln_2_b; +}; + +struct clip_vision_model { + struct clip_hparams hparams; + + // embeddings + // struct ggml_tensor * class_embedding; + struct ggml_tensor * patch_embeddings_w; + struct ggml_tensor * patch_embeddings_b; + struct ggml_tensor * position_embeddings; + + // struct ggml_tensor * pre_ln_w; + // struct ggml_tensor * pre_ln_b; + + std::vector layers; + + struct ggml_tensor * post_ln_w; + struct ggml_tensor * post_ln_b; + + struct ggml_tensor * projection; + + // LLaVA projection + struct ggml_tensor * mm_0_w = NULL; + struct ggml_tensor * mm_0_b = NULL; + struct ggml_tensor * mm_2_w = NULL; + struct ggml_tensor * mm_2_b = NULL; + + struct ggml_tensor * image_newline = NULL; + + // Yi type models with mlp+normalization projection + struct ggml_tensor * mm_1_w = NULL; // Yi type models have 0, 1, 3, 4 + struct ggml_tensor * mm_1_b = NULL; + struct ggml_tensor * mm_3_w = NULL; + struct ggml_tensor * mm_3_b = NULL; + struct ggml_tensor * mm_4_w = NULL; + struct ggml_tensor * mm_4_b = NULL; + + // MobileVLM projection + struct ggml_tensor * mm_model_mlp_1_w; + struct ggml_tensor * mm_model_mlp_1_b; + struct ggml_tensor * mm_model_mlp_3_w; + struct ggml_tensor * mm_model_mlp_3_b; + struct ggml_tensor * mm_model_block_1_block_0_0_w; + struct ggml_tensor * mm_model_block_1_block_0_1_w; + struct ggml_tensor * mm_model_block_1_block_0_1_b; + struct ggml_tensor * mm_model_block_1_block_1_fc1_w; + struct ggml_tensor * mm_model_block_1_block_1_fc1_b; + struct ggml_tensor * mm_model_block_1_block_1_fc2_w; + struct ggml_tensor * mm_model_block_1_block_1_fc2_b; + struct ggml_tensor * mm_model_block_1_block_2_0_w; + struct ggml_tensor * mm_model_block_1_block_2_1_w; + struct ggml_tensor * mm_model_block_1_block_2_1_b; + struct ggml_tensor * mm_model_block_2_block_0_0_w; + struct ggml_tensor * mm_model_block_2_block_0_1_w; + struct ggml_tensor * mm_model_block_2_block_0_1_b; + struct ggml_tensor * mm_model_block_2_block_1_fc1_w; + struct ggml_tensor * mm_model_block_2_block_1_fc1_b; + struct ggml_tensor * mm_model_block_2_block_1_fc2_w; + struct ggml_tensor * mm_model_block_2_block_1_fc2_b; + struct ggml_tensor * mm_model_block_2_block_2_0_w; + struct ggml_tensor * mm_model_block_2_block_2_1_w; + struct ggml_tensor * mm_model_block_2_block_2_1_b; + + // MobileVLM_V2 projection + struct ggml_tensor * mm_model_mlp_0_w; + struct ggml_tensor * mm_model_mlp_0_b; + struct ggml_tensor * mm_model_mlp_2_w; + struct ggml_tensor * mm_model_mlp_2_b; + struct ggml_tensor * mm_model_peg_0_w; + struct ggml_tensor * mm_model_peg_0_b; + + // MINICPMV projection + // struct ggml_tensor * mm_model_pos_embed; + struct ggml_tensor * mm_model_pos_embed_k; + struct ggml_tensor * mm_model_query; + struct ggml_tensor * mm_model_proj; + struct ggml_tensor * mm_model_kv_proj; + struct ggml_tensor * mm_model_attn_q_w; + struct ggml_tensor * mm_model_attn_q_b; + struct ggml_tensor * mm_model_attn_k_w; + struct ggml_tensor * mm_model_attn_k_b; + struct ggml_tensor * mm_model_attn_v_w; + struct ggml_tensor * mm_model_attn_v_b; + struct ggml_tensor * mm_model_attn_o_w; + struct ggml_tensor * mm_model_attn_o_b; + struct ggml_tensor * mm_model_ln_q_w; + struct ggml_tensor * mm_model_ln_q_b; + struct ggml_tensor * mm_model_ln_kv_w; + struct ggml_tensor * mm_model_ln_kv_b; + struct ggml_tensor * mm_model_ln_post_w; + struct ggml_tensor * mm_model_ln_post_b; +}; + +struct clip_ctx { + bool has_text_encoder = false; + bool has_vision_encoder = false; + bool has_llava_projector = false; + + struct clip_vision_model vision_model; + projector_type proj_type = PROJECTOR_TYPE_MLP; + + float image_mean[3]; + float image_std[3]; + bool use_gelu = false; + int32_t ftype = 1; + + struct gguf_context * ctx_gguf; + struct ggml_context * ctx_data; + + std::vector buf_compute_meta; + + // memory buffers to evaluate the model + ggml_backend_buffer_t params_buffer = NULL; + + ggml_backend_t backend = NULL; + ggml_gallocr_t compute_alloc = NULL; +}; + +void print_tensor_info(const struct ggml_tensor *tensor, const std::string &name) { + std::cout << "Tensor " << name << ": (" + << tensor->ne[0] << ", " << tensor->ne[1] << ", " << tensor->ne[2] << ")" << std::endl; + for (int i = 0; i < tensor->ne[0]; ++i) { + for (int j = 0; j < tensor->ne[1]; ++j) { + for (int k = 0; k < tensor->ne[2]; ++k) { + std::cout << ((float *)tensor->data)[i * tensor->ne[1] * tensor->ne[2] + j * tensor->ne[2] + k] << " "; + } + std::cout << std::endl; + } + std::cout << std::endl; + } +} + +struct ggml_tensor *ggml_sin(struct ggml_context *ctx, struct ggml_tensor *input) { + int size = input->ne[0] * input->ne[1] * input->ne[2]; + struct ggml_tensor *out = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, input->ne[0], input->ne[1], input->ne[2]); + + for (int i = 0; i < size; ++i) { + ((float *)out->data)[i] = std::sin(((float *)input->data)[i]); + } + + return out; +} + +struct ggml_tensor *ggml_cos(struct ggml_context *ctx, struct ggml_tensor *input) { + int size = input->ne[0] * input->ne[1] * input->ne[2]; + struct ggml_tensor *out = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, input->ne[0], input->ne[1], input->ne[2]); + + for (int i = 0; i < size; ++i) { + ((float *)out->data)[i] = std::cos(((float *)input->data)[i]); + } + + return out; +} + +static ggml_cgraph * clip_image_build_graph(clip_ctx * ctx, const clip_image_f32_batch * imgs, std::pair load_image_size = {70, 70}) { + if (!ctx->has_vision_encoder) { + LOG_TEE("This gguf file seems to have no vision encoder\n"); + return nullptr; + } + + const auto & model = ctx->vision_model; + const auto & hparams = model.hparams; + + const int image_size = hparams.image_size; + const int patch_size = hparams.patch_size; + const int num_patches = ((image_size / patch_size) * (image_size / patch_size)); + const int num_patches_per_side = image_size / patch_size; GGML_UNUSED(num_patches_per_side); + const int num_positions = num_patches; + const int hidden_size = hparams.hidden_size; + const int n_head = hparams.n_head; + const int d_head = hidden_size / n_head; + const int n_layer = hparams.n_layer; + const float eps = hparams.eps; + + const int batch_size = imgs->size; + + if (ctx->has_llava_projector) { + GGML_ASSERT(batch_size == 1); + } + + struct ggml_init_params params = { + /*.mem_size =*/ ctx->buf_compute_meta.size(), + /*.mem_buffer =*/ ctx->buf_compute_meta.data(), + /*.no_alloc =*/ true, + }; + + LOG_TEE("%s: ctx->buf_compute_meta.size(): %d \n", __func__, ctx->buf_compute_meta.size()); + struct ggml_context * ctx0 = ggml_init(params); + struct ggml_cgraph * gf = ggml_new_graph(ctx0); + + struct ggml_tensor * inp_raw = ggml_new_tensor_4d(ctx0, GGML_TYPE_F32, image_size, image_size, 3, batch_size); + ggml_set_name(inp_raw, "inp_raw"); + ggml_set_input(inp_raw); + + struct ggml_tensor * inp = ggml_conv_2d(ctx0, model.patch_embeddings_w, inp_raw, patch_size, patch_size, 0, 0, 1, 1); + + inp = ggml_reshape_3d(ctx0, inp, num_patches, hidden_size, batch_size); + inp = ggml_cont(ctx0, ggml_permute(ctx0, inp, 1, 0, 2, 3)); + inp = ggml_add(ctx0, inp, model.patch_embeddings_b); + + // concat class_embeddings and patch_embeddings + // struct ggml_tensor * embeddings = ggml_new_tensor_3d(ctx0, GGML_TYPE_F32, hidden_size, num_positions, batch_size); + // ggml_set_name(embeddings, "embeddings"); + // ggml_set_input(embeddings); + + // embeddings = ggml_acc(ctx0, embeddings, model.class_embedding, + // embeddings->nb[1], embeddings->nb[2], embeddings->nb[3], 0); + + // embeddings = ggml_acc(ctx0, embeddings, inp, + // embeddings->nb[1], embeddings->nb[2], embeddings->nb[3], model.class_embedding->nb[1]); + + struct ggml_tensor * positions = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, num_positions); + ggml_set_name(positions, "positions"); + ggml_set_input(positions); + + struct ggml_tensor * embeddings = + ggml_add(ctx0, inp, ggml_get_rows(ctx0, model.position_embeddings, positions)); + + // // pre-layernorm + // { + // embeddings = ggml_norm(ctx0, embeddings, eps); + // ggml_set_name(embeddings, "pre_ln"); + + // embeddings = ggml_add(ctx0, ggml_mul(ctx0, embeddings, model.pre_ln_w), model.pre_ln_b); + // } + + // loop over layers + for (int il = 0; il < n_layer; il++) { + struct ggml_tensor * cur = embeddings; // embeddings = residual, cur = hidden_states + + //const size_t nb_q_w = model.layers[il].q_w->nb[0]; + + // layernorm1 + { + cur = ggml_norm(ctx0, cur, eps); + + cur = ggml_add(ctx0, ggml_mul(ctx0, cur, model.layers[il].ln_1_w), + model.layers[il].ln_1_b); + } + + // self-attention + { + + struct ggml_tensor * Q = + ggml_add(ctx0, ggml_mul_mat(ctx0, model.layers[il].q_w, cur), model.layers[il].q_b); + + Q = ggml_scale_inplace(ctx0, Q, 1.0f / sqrt((float)d_head)); + Q = ggml_reshape_4d(ctx0, Q, d_head, n_head, num_positions, batch_size); + Q = ggml_cont(ctx0, ggml_permute(ctx0, Q, 0, 2, 1, 3)); + Q = ggml_reshape_3d(ctx0, Q, d_head, num_positions, n_head * batch_size); + + struct ggml_tensor * K = + ggml_add(ctx0, ggml_mul_mat(ctx0, model.layers[il].k_w, cur), model.layers[il].k_b); + + K = ggml_reshape_4d(ctx0, K, d_head, n_head, num_positions, batch_size); + K = ggml_cont(ctx0, ggml_permute(ctx0, K, 0, 2, 1, 3)); + K = ggml_reshape_3d(ctx0, K, d_head, num_positions, n_head * batch_size); + + struct ggml_tensor * V = + ggml_add(ctx0, ggml_mul_mat(ctx0, model.layers[il].v_w, cur), model.layers[il].v_b); + + V = ggml_reshape_4d(ctx0, V, d_head, n_head, num_positions, batch_size); + V = ggml_cont(ctx0, ggml_permute(ctx0, V, 1, 2, 0, 3)); + V = ggml_reshape_3d(ctx0, V, num_positions, d_head, n_head * batch_size); + + struct ggml_tensor * KQ = ggml_mul_mat(ctx0, K, Q); + KQ = ggml_soft_max_inplace(ctx0, KQ); + struct ggml_tensor * KQV = ggml_mul_mat(ctx0, V, KQ); + KQV = ggml_reshape_4d(ctx0, KQV, d_head, num_positions, n_head, batch_size); + KQV = ggml_permute(ctx0, KQV, 0, 2, 1, 3); + + cur = ggml_cont_3d(ctx0, KQV, hidden_size, num_positions, batch_size); + } + + // attention output + cur = ggml_add(ctx0, ggml_mul_mat(ctx0, model.layers[il].o_w, cur), model.layers[il].o_b); + + // re-add the layer input, e.g., residual + cur = ggml_add(ctx0, cur, embeddings); + + embeddings = cur; // embeddings = residual, cur = hidden_states + + // layernorm2 + { + cur = ggml_norm(ctx0, cur, eps); + + cur = ggml_add(ctx0, ggml_mul(ctx0, cur, model.layers[il].ln_2_w), model.layers[il].ln_2_b); + } + + cur = ggml_mul_mat(ctx0, model.layers[il].ff_i_w, cur); + cur = ggml_add(ctx0, cur, model.layers[il].ff_i_b); + + if (ctx->use_gelu) { + cur = ggml_gelu_inplace(ctx0, cur); + } else { + cur = ggml_gelu_quick_inplace(ctx0, cur); + } + + cur = ggml_mul_mat(ctx0, model.layers[il].ff_o_w, cur); + cur = ggml_add(ctx0, cur, model.layers[il].ff_o_b); + + // residual 2 + cur = ggml_add(ctx0, embeddings, cur); + + embeddings = cur; + } + + { // post layernorm + embeddings = ggml_norm(ctx0, embeddings, eps); + embeddings = ggml_add(ctx0, ggml_mul(ctx0, embeddings, model.post_ln_w), model.post_ln_b); + } + + // llava projector + { + // embeddings = ggml_reshape_2d(ctx0, embeddings, embeddings->ne[0], embeddings->ne[1]); + + // struct ggml_tensor * patches = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, 64); + // ggml_set_name(patches, "patches"); + // ggml_set_input(patches); + + // shape [1, 576, 1024] + // ne is whcn, ne = [1024, 576, 1, 1] + // embeddings = ggml_get_rows(ctx0, embeddings, patches); + + // print_tensor_info(embeddings, "embeddings"); + + // llava projector + if (ctx->proj_type == PROJECTOR_TYPE_MLP) { + embeddings = ggml_mul_mat(ctx0, model.mm_0_w, embeddings); + embeddings = ggml_add(ctx0, embeddings, model.mm_0_b); + + embeddings = ggml_gelu(ctx0, embeddings); + embeddings = ggml_mul_mat(ctx0, model.mm_2_w, embeddings); + embeddings = ggml_add(ctx0, embeddings, model.mm_2_b); + + } else if (ctx->proj_type == PROJECTOR_TYPE_MLP_NORM) { + embeddings = ggml_mul_mat(ctx0, model.mm_0_w, embeddings); + embeddings = ggml_add(ctx0, embeddings, model.mm_0_b); + // ggml_tensor_printf(embeddings, "mm_0_w",0,true,false); + // First LayerNorm + embeddings = ggml_norm(ctx0, embeddings, eps); + embeddings = ggml_add(ctx0, ggml_mul(ctx0, embeddings, model.mm_1_w), + model.mm_1_b); + + // GELU activation + embeddings = ggml_gelu(ctx0, embeddings); + + // Second linear layer + embeddings = ggml_mul_mat(ctx0, model.mm_3_w, embeddings); + embeddings = ggml_add(ctx0, embeddings, model.mm_3_b); + + // Second LayerNorm + embeddings = ggml_norm(ctx0, embeddings, eps); + embeddings = ggml_add(ctx0, ggml_mul(ctx0, embeddings, model.mm_4_w), + model.mm_4_b); + } + else if (ctx->proj_type == PROJECTOR_TYPE_LDP) { + // MobileVLM projector + int n_patch = 24; + struct ggml_tensor * mlp_1 = ggml_mul_mat(ctx0, model.mm_model_mlp_1_w, embeddings); + mlp_1 = ggml_add(ctx0, mlp_1, model.mm_model_mlp_1_b); + mlp_1 = ggml_gelu(ctx0, mlp_1); + struct ggml_tensor * mlp_3 = ggml_mul_mat(ctx0, model.mm_model_mlp_3_w, mlp_1); + mlp_3 = ggml_add(ctx0, mlp_3, model.mm_model_mlp_3_b); + // mlp_3 shape = [1, 576, 2048], ne = [2048, 576, 1, 1] + + // block 1 + struct ggml_tensor * block_1 = nullptr; + { + // transpose from [1, 576, 2048] --> [1, 2048, 576] --> [1, 2048, 24, 24] + mlp_3 = ggml_cont(ctx0, ggml_permute(ctx0, mlp_3, 1, 0, 2, 3)); + mlp_3 = ggml_reshape_4d(ctx0, mlp_3, n_patch, n_patch, mlp_3->ne[1], mlp_3->ne[2]); + // stride = 1, padding = 1, bias is nullptr + block_1 = ggml_conv_depthwise_2d(ctx0, model.mm_model_block_1_block_0_0_w, mlp_3, 1, 1, 1, 1, 1, 1); + + // layer norm + // // block_1 shape = [1, 2048, 24, 24], ne = [24, 24, 2048, 1] + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 1, 2, 0, 3)); + // block_1 shape = [1, 24, 24, 2048], ne = [2048, 24, 24, 1] + block_1 = ggml_norm(ctx0, block_1, eps); + block_1 = ggml_add(ctx0, ggml_mul(ctx0, block_1, model.mm_model_block_1_block_0_1_w), model.mm_model_block_1_block_0_1_b); + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 2, 0, 1, 3)); + + // block_1 shape = [1, 2048, 24, 24], ne = [24, 24, 2048, 1] + // hardswish + struct ggml_tensor * block_1_hw = ggml_hardswish(ctx0, block_1); + + block_1 = ggml_pool_2d(ctx0, block_1_hw, GGML_OP_POOL_AVG, block_1_hw->ne[0], block_1_hw->ne[1], block_1_hw->ne[0], block_1_hw->ne[1], 0, 0); + // block_1 shape = [1, 2048, 1, 1], ne = [1, 1, 2048, 1] + // pointwise conv + block_1 = ggml_reshape_2d(ctx0, block_1, block_1->ne[0]*block_1->ne[1]*block_1->ne[2], block_1->ne[3]); + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_1_block_1_fc1_w, block_1); + block_1 = ggml_add(ctx0, block_1, model.mm_model_block_1_block_1_fc1_b); + block_1 = ggml_relu(ctx0, block_1); + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_1_block_1_fc2_w, block_1); + block_1 = ggml_add(ctx0, block_1, model.mm_model_block_1_block_1_fc2_b); + block_1 = ggml_hardsigmoid(ctx0, block_1); + // block_1_hw shape = [1, 2048, 24, 24], ne = [24, 24, 2048, 1], block_1 shape = [1, 2048], ne = [2048, 1, 1, 1] + block_1 = ggml_reshape_4d(ctx0, block_1, 1, 1, block_1->ne[0], block_1->ne[1]); + block_1 = ggml_mul(ctx0, block_1_hw, block_1); + + int w = block_1->ne[0], h = block_1->ne[1]; + block_1 = ggml_reshape_3d(ctx0, block_1, w*h, block_1->ne[2], block_1->ne[3]); + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 1, 0, 2, 3)); + + // block_1 shape = [1, 24*24, 2048], ne = [24*24, 2048, 1] + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_1_block_2_0_w, block_1); + block_1 = ggml_reshape_4d(ctx0, block_1, block_1->ne[0], w, h, block_1->ne[3]); + + // block_1 shape = [1, 24, 24, 2048], ne = [2048, 24, 24, 1] + block_1 = ggml_norm(ctx0, block_1, eps); + block_1 = ggml_add(ctx0, ggml_mul(ctx0, block_1, model.mm_model_block_1_block_2_1_w), model.mm_model_block_1_block_2_1_b); + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 2, 0, 1, 3)); + // block1 shape = [1, 2048, 24, 24], ne = [24, 24, 2048, 1] + // residual + block_1 = ggml_add(ctx0, mlp_3, block_1); + } + + // block_2 + { + // stride = 2 + block_1 = ggml_conv_depthwise_2d(ctx0, model.mm_model_block_2_block_0_0_w, block_1, 2, 2, 1, 1, 1, 1); + + // block_1 shape = [1, 2048, 12, 12], ne = [12, 12, 2048, 1] + // layer norm + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 1, 2, 0, 3)); + // block_1 shape = [1, 12, 12, 2048], ne = [2048, 12, 12, 1] + block_1 = ggml_norm(ctx0, block_1, eps); + block_1 = ggml_add(ctx0, ggml_mul(ctx0, block_1, model.mm_model_block_2_block_0_1_w), model.mm_model_block_2_block_0_1_b); + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 2, 0, 1, 3)); + // block_1 shape = [1, 2048, 12, 12], ne = [12, 12, 2048, 1] + // hardswish + struct ggml_tensor * block_1_hw = ggml_hardswish(ctx0, block_1); + + // not sure the parameters is right for globalAvgPooling + block_1 = ggml_pool_2d(ctx0, block_1_hw, GGML_OP_POOL_AVG, block_1_hw->ne[0], block_1_hw->ne[1], block_1_hw->ne[0], block_1_hw->ne[1], 0, 0); + // block_1 shape = [1, 2048, 1, 1], ne = [1, 1, 2048, 1] + // pointwise conv + block_1 = ggml_reshape_2d(ctx0, block_1, block_1->ne[0]*block_1->ne[1]*block_1->ne[2], block_1->ne[3]); + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_2_block_1_fc1_w, block_1); + block_1 = ggml_add(ctx0, block_1, model.mm_model_block_2_block_1_fc1_b); + block_1 = ggml_relu(ctx0, block_1); + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_2_block_1_fc2_w, block_1); + block_1 = ggml_add(ctx0, block_1, model.mm_model_block_2_block_1_fc2_b); + block_1 = ggml_hardsigmoid(ctx0, block_1); + + // block_1_hw shape = [1, 2048, 12, 12], ne = [12, 12, 2048, 1], block_1 shape = [1, 2048, 1, 1], ne = [1, 1, 2048, 1] + block_1 = ggml_reshape_4d(ctx0, block_1, 1, 1, block_1->ne[0], block_1->ne[1]); + block_1 = ggml_mul(ctx0, block_1_hw, block_1); + + int w = block_1->ne[0], h = block_1->ne[1]; + block_1 = ggml_reshape_3d(ctx0, block_1, w*h, block_1->ne[2], block_1->ne[3]); + block_1 = ggml_cont(ctx0, ggml_permute(ctx0, block_1, 1, 0, 2, 3)); + // block_1 shape = [1, 24*24, 2048], ne = [24*24, 2048, 1] + block_1 = ggml_mul_mat(ctx0, model.mm_model_block_2_block_2_0_w, block_1); + block_1 = ggml_reshape_4d(ctx0, block_1, block_1->ne[0], w, h, block_1->ne[3]); + + + // block_1 shape = [1, 12, 12, 2048], ne = [2048, 12, 12, 1] + block_1 = ggml_norm(ctx0, block_1, eps); + block_1 = ggml_add(ctx0, ggml_mul(ctx0, block_1, model.mm_model_block_2_block_2_1_w), model.mm_model_block_2_block_2_1_b); + block_1 = ggml_reshape_3d(ctx0, block_1, block_1->ne[0], block_1->ne[1] * block_1->ne[2], block_1->ne[3]); + // block_1 shape = [1, 144, 2048], ne = [2048, 144, 1] + } + embeddings = block_1; + } + else if (ctx->proj_type == PROJECTOR_TYPE_LDPV2) + { + int n_patch = 24; + struct ggml_tensor * mlp_0 = ggml_mul_mat(ctx0, model.mm_model_mlp_0_w, embeddings); + mlp_0 = ggml_add(ctx0, mlp_0, model.mm_model_mlp_0_b); + mlp_0 = ggml_gelu(ctx0, mlp_0); + struct ggml_tensor * mlp_2 = ggml_mul_mat(ctx0, model.mm_model_mlp_2_w, mlp_0); + mlp_2 = ggml_add(ctx0, mlp_2, model.mm_model_mlp_2_b); + // mlp_2 ne = [2048, 576, 1, 1] + // // AVG Pool Layer 2*2, strides = 2 + mlp_2 = ggml_cont(ctx0, ggml_permute(ctx0, mlp_2, 1, 0, 2, 3)); + // mlp_2 ne = [576, 2048, 1, 1] + mlp_2 = ggml_reshape_4d(ctx0, mlp_2, n_patch, n_patch, mlp_2->ne[1], mlp_2->ne[2]); + // mlp_2 ne [24, 24, 2048, 1] + mlp_2 = ggml_pool_2d(ctx0, mlp_2, GGML_OP_POOL_AVG, 2, 2, 2, 2, 0, 0); + // weight ne = [3, 3, 2048, 1] + struct ggml_tensor * peg_0 = ggml_conv_depthwise_2d(ctx0, model.mm_model_peg_0_w, mlp_2, 1, 1, 1, 1, 1, 1); + peg_0 = ggml_cont(ctx0, ggml_permute(ctx0, peg_0, 1, 2, 0, 3)); + peg_0 = ggml_add(ctx0, peg_0, model.mm_model_peg_0_b); + mlp_2 = ggml_cont(ctx0, ggml_permute(ctx0, mlp_2, 1, 2, 0, 3)); + peg_0 = ggml_add(ctx0, peg_0, mlp_2); + peg_0 = ggml_reshape_3d(ctx0, peg_0, peg_0->ne[0], peg_0->ne[1] * peg_0->ne[2], peg_0->ne[3]); + embeddings = peg_0; + } + else if (ctx->proj_type == PROJECTOR_TYPE_RESAMPLER) { + struct ggml_tensor * q = model.mm_model_query; + { // layernorm + q = ggml_norm(ctx0, q, eps); + q = ggml_add(ctx0, ggml_mul(ctx0, q, model.mm_model_ln_q_w), model.mm_model_ln_q_b); + } + struct ggml_tensor *k, *v = ggml_mul_mat(ctx0, model.mm_model_kv_proj, embeddings); + { // layernorm + v = ggml_norm(ctx0, v, eps); + v = ggml_add(ctx0, ggml_mul(ctx0, v, model.mm_model_ln_kv_w), model.mm_model_ln_kv_b); + } + { // position + // q = ggml_add(ctx0, q, model.mm_model_pos_embed); + k = ggml_add(ctx0, v, model.mm_model_pos_embed_k); + } + + { // attention + const int hidden_size = 4096; + const int d_head = 128; + const int n_head = hidden_size/d_head; + const int num_query = 96; + + struct ggml_tensor * Q = ggml_add(ctx0, ggml_mul_mat(ctx0, model.mm_model_attn_q_w, q), model.mm_model_attn_q_b); + Q = ggml_scale_inplace(ctx0, Q, 1.0f / sqrt((float)d_head)); + struct ggml_tensor * K = ggml_add(ctx0, ggml_mul_mat(ctx0, model.mm_model_attn_k_w, k), model.mm_model_attn_k_b); + struct ggml_tensor * V = ggml_add(ctx0, ggml_mul_mat(ctx0, model.mm_model_attn_v_w, v), model.mm_model_attn_v_b); + // permute + Q = ggml_reshape_4d(ctx0, Q, d_head, n_head, num_query, batch_size); + Q = ggml_cont(ctx0, ggml_permute(ctx0, Q, 0, 2, 1, 3)); + Q = ggml_reshape_3d(ctx0, Q, d_head, num_query, n_head * batch_size); + K = ggml_reshape_4d(ctx0, K, d_head, n_head, num_positions, batch_size); + K = ggml_cont(ctx0, ggml_permute(ctx0, K, 0, 2, 1, 3)); + K = ggml_reshape_3d(ctx0, K, d_head, num_positions, n_head * batch_size); + V = ggml_reshape_4d(ctx0, V, d_head, n_head, num_positions, batch_size); + V = ggml_cont(ctx0, ggml_permute(ctx0, V, 1, 2, 0, 3)); + V = ggml_reshape_3d(ctx0, V, num_positions, d_head, n_head * batch_size); + struct ggml_tensor * KQ = ggml_mul_mat(ctx0, K, Q); + KQ = ggml_soft_max_inplace(ctx0, KQ); + struct ggml_tensor * KQV = ggml_mul_mat(ctx0, V, KQ); + KQV = ggml_reshape_4d(ctx0, KQV, d_head, num_query, n_head, batch_size); + KQV = ggml_permute(ctx0, KQV, 0, 2, 1, 3); + KQV = ggml_cont_3d(ctx0, KQV, hidden_size, num_query, batch_size); + + embeddings = ggml_add(ctx0, ggml_mul_mat(ctx0, model.mm_model_attn_o_w, KQV), model.mm_model_attn_o_b); + } + { // layernorm + embeddings = ggml_norm(ctx0, embeddings, eps); + embeddings = ggml_add(ctx0, ggml_mul(ctx0, embeddings, model.mm_model_ln_post_w), model.mm_model_ln_post_b); + } + embeddings = ggml_mul_mat(ctx0, model.mm_model_proj, embeddings); + } + else { + GGML_ASSERT(false); + } + } + + // build the graph + ggml_build_forward_expand(gf, embeddings); + + ggml_free(ctx0); + + return gf; +} + +// read and create ggml_context containing the tensors and their data +struct clip_ctx * clip_model_load(const char * fname, const int verbosity = 1, std::pair load_image_size = {70, 70}) { + struct ggml_context * meta = NULL; + + struct gguf_init_params params = { + /*.no_alloc = */ false, + /*.ctx = */ &meta, + }; + + struct gguf_context * ctx = gguf_init_from_file(fname, params); + if (!ctx) { + throw std::runtime_error(format("%s: failed to load CLIP model from %s. Does this file exist?\n", __func__, fname)); + } + + if (verbosity >= 1) { + const int n_tensors = gguf_get_n_tensors(ctx); + const int n_kv = gguf_get_n_kv(ctx); + const int ftype = get_u32(ctx, KEY_FTYPE); + const std::string ftype_str = get_ftype(ftype); + const int idx_desc = get_key_idx(ctx, KEY_DESCRIPTION); + const std::string description = gguf_get_val_str(ctx, idx_desc); + const int idx_name = gguf_find_key(ctx, KEY_NAME); + if (idx_name != -1) { // make name optional temporarily as some of the uploaded models missing it due to a bug + const std::string name = gguf_get_val_str(ctx, idx_name); + LOG_TEE("%s: model name: %s\n", __func__, name.c_str()); + } + LOG_TEE("%s: description: %s\n", __func__, description.c_str()); + LOG_TEE("%s: GGUF version: %d\n", __func__, gguf_get_version(ctx)); + LOG_TEE("%s: alignment: %zu\n", __func__, gguf_get_alignment(ctx)); + LOG_TEE("%s: n_tensors: %d\n", __func__, n_tensors); + LOG_TEE("%s: n_kv: %d\n", __func__, n_kv); + LOG_TEE("%s: ftype: %s\n", __func__, ftype_str.c_str()); + LOG_TEE("\n"); + } + const int n_tensors = gguf_get_n_tensors(ctx); + + // kv + const int n_kv = gguf_get_n_kv(ctx); + LOG_TEE("%s: loaded meta data with %d key-value pairs and %d tensors from %s\n", + __func__, n_kv, n_tensors, fname); + { + std::map n_type; + + for (int i = 0; i < n_tensors; i++) { + enum ggml_type type = gguf_get_tensor_type(ctx, i); + + n_type[type]++; + } + + LOG_TEE("%s: Dumping metadata keys/values. Note: KV overrides do not apply in this output.\n", __func__); + for (int i = 0; i < n_kv; i++) { + const char * name = gguf_get_key(ctx, i); + const enum gguf_type type = gguf_get_kv_type(ctx, i); + const std::string type_name = + type == GGUF_TYPE_ARRAY + ? format("%s[%s,%d]", gguf_type_name(type), gguf_type_name(gguf_get_arr_type(ctx, i)), gguf_get_arr_n(ctx, i)) + : gguf_type_name(type); + + std::string value = gguf_kv_to_str(ctx, i); + const size_t MAX_VALUE_LEN = 40; + if (value.size() > MAX_VALUE_LEN) { + value = format("%s...", value.substr(0, MAX_VALUE_LEN - 3).c_str()); + } + replace_all(value, "\n", "\\n"); + + LOG_TEE("%s: - kv %3d: %42s %-16s = %s\n", __func__, i, name, type_name.c_str(), value.c_str()); + } + + // print type counts + for (auto & kv : n_type) { + if (kv.second == 0) { + continue; + } + + LOG_TEE("%s: - type %4s: %4d tensors\n", __func__, ggml_type_name(kv.first), kv.second); + } + } + + // data + size_t model_size = 0; + { + for (int i = 0; i < n_tensors; ++i) { + const char * name = gguf_get_tensor_name(ctx, i); + const size_t offset = gguf_get_tensor_offset(ctx, i); + enum ggml_type type = gguf_get_tensor_type(ctx, i); + struct ggml_tensor * cur = ggml_get_tensor(meta, name); + size_t tensor_size = ggml_nbytes(cur); + model_size += tensor_size; + if (verbosity >= 3) { + LOG_TEE("%s: tensor[%d]: n_dims = %d, name = %s, tensor_size=%zu, offset=%zu, shape:[%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "], type = %s\n", + __func__, i, ggml_n_dims(cur), cur->name, tensor_size, offset, cur->ne[0], cur->ne[1], cur->ne[2], cur->ne[3], ggml_type_name(type)); + } + } + } + + clip_ctx * new_clip = new clip_ctx; + + // update projector type + { + int idx = gguf_find_key(ctx, KEY_PROJ_TYPE); + if (idx != -1) { + const std::string proj_type = gguf_get_val_str(ctx, idx); + new_clip->proj_type = clip_projector_type_from_string(proj_type); + } else { + new_clip->proj_type = PROJECTOR_TYPE_MLP; + } + + if (new_clip->proj_type == PROJECTOR_TYPE_MLP) { + if (gguf_find_tensor(ctx, format(TN_LLAVA_PROJ, 3, "weight").c_str()) != -1) { + new_clip->proj_type = PROJECTOR_TYPE_MLP_NORM; + } + } + } + +#ifdef GGML_USE_CUDA + new_clip->backend = ggml_backend_cuda_init(0); + LOG_TEE("%s: CLIP using CUDA backend\n", __func__); +#endif + +#ifdef GGML_USE_METAL + new_clip->backend = ggml_backend_metal_init(); + LOG_TEE("%s: CLIP using Metal backend\n", __func__); +#endif + + + if (!new_clip->backend) { + new_clip->backend = ggml_backend_cpu_init(); + LOG_TEE("%s: CLIP using CPU backend\n", __func__); + } + + // model size and capabilities + { + int idx = get_key_idx(ctx, KEY_HAS_TEXT_ENC); + new_clip->has_text_encoder = gguf_get_val_bool(ctx, idx); + + idx = get_key_idx(ctx, KEY_HAS_VIS_ENC); + new_clip->has_vision_encoder = gguf_get_val_bool(ctx, idx); + + idx = gguf_find_key(ctx, KEY_HAS_LLAVA_PROJ); + if (idx != -1) { + new_clip->has_llava_projector = gguf_get_val_bool(ctx, idx); + } + + GGML_ASSERT(new_clip->has_llava_projector); // see monatis/clip.cpp for image and/or text encoding for semantic search + GGML_ASSERT(new_clip->has_vision_encoder); + GGML_ASSERT(!new_clip->has_text_encoder); + + idx = get_key_idx(ctx, KEY_USE_GELU); + new_clip->use_gelu = gguf_get_val_bool(ctx, idx); + + if (verbosity >= 1) { + LOG_TEE("%s: text_encoder: %d\n", __func__, new_clip->has_text_encoder); + LOG_TEE("%s: vision_encoder: %d\n", __func__, new_clip->has_vision_encoder); + LOG_TEE("%s: llava_projector: %d\n", __func__, new_clip->has_llava_projector); + LOG_TEE("%s: model size: %.2f MB\n", __func__, model_size / 1024.0 / 1024.0); + LOG_TEE("%s: metadata size: %.2f MB\n", __func__, ggml_get_mem_size(meta) / 1024.0 / 1024.0); + } + } + + LOG_TEE("%s: params backend buffer size = % 6.2f MB (%i tensors)\n", __func__, model_size / (1024.0 * 1024.0), n_tensors); + + // load tensors + { + std::vector read_buf; + struct ggml_init_params params = { + /*.mem_size =*/ (n_tensors + 1) * ggml_tensor_overhead(), + /*.mem_buffer =*/ NULL, + /*.no_alloc =*/ true, + }; + + new_clip->ctx_data = ggml_init(params); + if (!new_clip->ctx_data) { + LOG_TEE("%s: ggml_init() failed\n", __func__); + clip_free(new_clip); + gguf_free(ctx); + return nullptr; + } + + auto fin = std::ifstream(fname, std::ios::binary); + if (!fin) { + LOG_TEE("cannot open model file for loading tensors\n"); + clip_free(new_clip); + gguf_free(ctx); + return nullptr; + } + + // add tensors to context + for (int i = 0; i < n_tensors; ++i) { + const char * name = gguf_get_tensor_name(ctx, i); + struct ggml_tensor * t = ggml_get_tensor(meta, name); + struct ggml_tensor * cur = ggml_dup_tensor(new_clip->ctx_data, t); + ggml_set_name(cur, name); + } + + // alloc memory and offload data + new_clip->params_buffer = ggml_backend_alloc_ctx_tensors(new_clip->ctx_data, new_clip->backend); + for (int i = 0; i < n_tensors; ++i) { + const char * name = gguf_get_tensor_name(ctx, i); + struct ggml_tensor * cur = ggml_get_tensor(new_clip->ctx_data, name); + const size_t offset = gguf_get_data_offset(ctx) + gguf_get_tensor_offset(ctx, i); + fin.seekg(offset, std::ios::beg); + if (!fin) { + LOG_TEE("%s: failed to seek for tensor %s\n", __func__, name); + clip_free(new_clip); + gguf_free(ctx); + return nullptr; + } + int num_bytes = ggml_nbytes(cur); + if (ggml_backend_buffer_is_host(new_clip->params_buffer)) { + // for the CPU and Metal backend, we can read directly into the tensor + fin.read(reinterpret_cast(cur->data), num_bytes); + } else { + // read into a temporary buffer first, then copy to device memory + read_buf.resize(num_bytes); + fin.read(reinterpret_cast(read_buf.data()), num_bytes); + ggml_backend_tensor_set(cur, read_buf.data(), 0, num_bytes); + } + } + fin.close(); + } + + // vision model + if (new_clip->has_vision_encoder) { + // load vision model + auto & vision_model = new_clip->vision_model; + auto & hparams = vision_model.hparams; + hparams.hidden_size = get_u32(ctx, format(KEY_N_EMBD, "vision")); + hparams.n_head = get_u32(ctx, format(KEY_N_HEAD, "vision")); + hparams.n_intermediate = get_u32(ctx, format(KEY_N_FF, "vision")); + hparams.n_layer = get_u32(ctx, format(KEY_N_BLOCK, "vision")); + hparams.image_size = get_u32(ctx, KEY_IMAGE_SIZE); + hparams.patch_size = get_u32(ctx, KEY_PATCH_SIZE); + hparams.projection_dim = get_u32(ctx, format(KEY_PROJ_DIM, "vision")); + hparams.eps = get_f32(ctx, format(KEY_LAYER_NORM_EPS, "vision")); + + try { + int idx = get_key_idx(ctx, KEY_IMAGE_GRID_PINPOINTS); + int n = gguf_get_arr_n(ctx, idx); + const int32_t * pinpoints = (const int32_t *)gguf_get_arr_data(ctx, idx); + for (int i = 0; i < 32 && i < n && pinpoints[i] != 0; ++i) { + hparams.image_grid_pinpoints[i] = pinpoints[i]; + } + if (n < 32) + hparams.image_grid_pinpoints[n] = 0; + } catch (std::runtime_error & e) { + hparams.image_grid_pinpoints[0]=0; + } + + try { + int idx = get_key_idx(ctx, KEY_MM_PATCH_MERGE_TYPE); + strcpy(hparams.mm_patch_merge_type, gguf_get_val_str(ctx, idx)); + } catch (std::runtime_error & e) { + strcpy(hparams.mm_patch_merge_type, "flat"); + } + + try { + hparams.image_crop_resolution = get_u32(ctx, KEY_IMAGE_CROP_RESOLUTION); // llava-1.6 + } catch(const std::exception& e) { + hparams.image_crop_resolution = hparams.image_size; + } + + int idx_mean = get_key_idx(ctx, KEY_IMAGE_MEAN); + int idx_std = get_key_idx(ctx, KEY_IMAGE_STD); + + const float * mean_data = (const float *)gguf_get_arr_data(ctx, idx_mean); + const float * std_data = (const float *)gguf_get_arr_data(ctx, idx_std); + + for (int i = 0; i < 3; ++i) { + new_clip->image_mean[i] = mean_data[i]; + new_clip->image_std[i] = std_data[i]; + } + + if (verbosity >= 2) { + LOG_TEE("\n%s: vision model hparams\n", __func__); + LOG_TEE("image_size %d\n", hparams.image_size); + LOG_TEE("patch_size %d\n", hparams.patch_size); + LOG_TEE("v_hidden_size %d\n", hparams.hidden_size); + LOG_TEE("v_n_intermediate %d\n", hparams.n_intermediate); + LOG_TEE("v_projection_dim %d\n", hparams.projection_dim); + LOG_TEE("v_n_head %d\n", hparams.n_head); + LOG_TEE("v_n_layer %d\n", hparams.n_layer); + LOG_TEE("v_eps %f\n", hparams.eps); + LOG_TEE("v_image_mean %f %f %f\n", new_clip->image_mean[0], new_clip->image_mean[1], new_clip->image_mean[2]); + LOG_TEE("v_image_std %f %f %f\n", new_clip->image_std[0], new_clip->image_std[1], new_clip->image_std[2]); + LOG_TEE("v_image_grid_pinpoints: "); + for (int i = 0; i < 32 && (hparams.image_grid_pinpoints[i] != 0); ++i) { + LOG_TEE("%d ", hparams.image_grid_pinpoints[i]); + } + LOG_TEE("\n"); + LOG_TEE("v_mm_patch_merge_type: %s\n", hparams.mm_patch_merge_type); + + } + + try { + vision_model.patch_embeddings_w = get_tensor(new_clip->ctx_data, format(TN_PATCH_EMBD, "weight")); + vision_model.patch_embeddings_b = get_tensor(new_clip->ctx_data, format(TN_PATCH_EMBD, "bias")); + // vision_model.class_embedding = get_tensor(new_clip->ctx_data, TN_CLASS_EMBD); + vision_model.position_embeddings = get_tensor(new_clip->ctx_data, format(TN_POS_EMBD, "v")); + // vision_model.pre_ln_w = get_tensor(new_clip->ctx_data, format(TN_LN_PRE, "v", "weight")); + // vision_model.pre_ln_b = get_tensor(new_clip->ctx_data, format(TN_LN_PRE, "v", "bias")); + vision_model.post_ln_w = get_tensor(new_clip->ctx_data, format(TN_LN_POST, "v", "weight")); + vision_model.post_ln_b = get_tensor(new_clip->ctx_data, format(TN_LN_POST, "v", "bias")); + } catch(const std::exception& e) { + LOG_TEE("%s: failed to load vision model tensors\n", __func__); + } + + // LLaVA projection + if (new_clip->proj_type == PROJECTOR_TYPE_MLP || new_clip->proj_type == PROJECTOR_TYPE_MLP_NORM) { + vision_model.mm_0_w = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 0, "weight")); + vision_model.mm_0_b = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 0, "bias")); + try { + // Yi-type llava + vision_model.mm_1_w = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 1, "weight")); + vision_model.mm_1_b = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 1, "bias")); + } catch (std::runtime_error & e) { } + try { + // missing in Yi-type llava + vision_model.mm_2_w = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 2, "weight")); + vision_model.mm_2_b = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 2, "bias")); + } catch (std::runtime_error & e) { } + try { + // Yi-type llava + vision_model.mm_3_w = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 3, "weight")); + vision_model.mm_3_b = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 3, "bias")); + } catch (std::runtime_error & e) { } + try { + // Yi-type llava + vision_model.mm_4_w = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 4, "weight")); + vision_model.mm_4_b = get_tensor(new_clip->ctx_data, format(TN_LLAVA_PROJ, 4, "bias")); + } catch (std::runtime_error & e) { } + try { + vision_model.image_newline = get_tensor(new_clip->ctx_data, TN_IMAGE_NEWLINE); + // LOG_TEE("%s: image_newline tensor (llava-1.6) found\n", __func__); + } catch (std::runtime_error & e) { } + } else if (new_clip->proj_type == PROJECTOR_TYPE_LDP) { + // MobileVLM projection + vision_model.mm_model_mlp_1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 1, "weight")); + vision_model.mm_model_mlp_1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 1, "bias")); + vision_model.mm_model_mlp_3_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 3, "weight")); + vision_model.mm_model_mlp_3_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 3, "bias")); + vision_model.mm_model_block_1_block_0_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 0, "0.weight")); + vision_model.mm_model_block_1_block_0_1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 0, "1.weight")); + vision_model.mm_model_block_1_block_0_1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 0, "1.bias")); + vision_model.mm_model_block_1_block_1_fc1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 1, "fc1.weight")); + vision_model.mm_model_block_1_block_1_fc1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 1, "fc1.bias")); + vision_model.mm_model_block_1_block_1_fc2_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 1, "fc2.weight")); + vision_model.mm_model_block_1_block_1_fc2_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 1, "fc2.bias")); + vision_model.mm_model_block_1_block_2_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 2, "0.weight")); + vision_model.mm_model_block_1_block_2_1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 2, "1.weight")); + vision_model.mm_model_block_1_block_2_1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 1, 2, "1.bias")); + vision_model.mm_model_block_2_block_0_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 0, "0.weight")); + vision_model.mm_model_block_2_block_0_1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 0, "1.weight")); + vision_model.mm_model_block_2_block_0_1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 0, "1.bias")); + vision_model.mm_model_block_2_block_1_fc1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 1, "fc1.weight")); + vision_model.mm_model_block_2_block_1_fc1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 1, "fc1.bias")); + vision_model.mm_model_block_2_block_1_fc2_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 1, "fc2.weight")); + vision_model.mm_model_block_2_block_1_fc2_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 1, "fc2.bias")); + vision_model.mm_model_block_2_block_2_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 2, "0.weight")); + vision_model.mm_model_block_2_block_2_1_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 2, "1.weight")); + vision_model.mm_model_block_2_block_2_1_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_BLOCK, 2, 2, "1.bias")); + } + else if (new_clip->proj_type == PROJECTOR_TYPE_LDPV2) + { + // MobilVLM_V2 projection + vision_model.mm_model_mlp_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 0, "weight")); + vision_model.mm_model_mlp_0_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 0, "bias")); + vision_model.mm_model_mlp_2_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 2, "weight")); + vision_model.mm_model_mlp_2_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_MLP, 2, "bias")); + vision_model.mm_model_peg_0_w = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_PEG, 0, "weight")); + vision_model.mm_model_peg_0_b = get_tensor(new_clip->ctx_data, format(TN_MVLM_PROJ_PEG, 0, "bias")); + } + else if (new_clip->proj_type == PROJECTOR_TYPE_RESAMPLER) { + // vision_model.mm_model_pos_embed = get_tensor(new_clip->ctx_data, TN_MINICPMV_POS_EMBD); + vision_model.mm_model_pos_embed_k = get_tensor(new_clip->ctx_data, TN_MINICPMV_POS_EMBD_K); + vision_model.mm_model_query = get_tensor(new_clip->ctx_data, TN_MINICPMV_QUERY); + vision_model.mm_model_proj = get_tensor(new_clip->ctx_data, TN_MINICPMV_PROJ); + vision_model.mm_model_kv_proj = get_tensor(new_clip->ctx_data, TN_MINICPMV_KV_PROJ); + vision_model.mm_model_attn_q_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "q", "weight")); + vision_model.mm_model_attn_k_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "k", "weight")); + vision_model.mm_model_attn_v_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "v", "weight")); + vision_model.mm_model_attn_q_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "q", "bias")); + vision_model.mm_model_attn_k_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "k", "bias")); + vision_model.mm_model_attn_v_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "v", "bias")); + vision_model.mm_model_attn_o_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "out", "weight")); + vision_model.mm_model_attn_o_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_ATTN, "out", "bias")); + vision_model.mm_model_ln_q_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "q", "weight")); + vision_model.mm_model_ln_q_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "q", "bias")); + vision_model.mm_model_ln_kv_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "kv", "weight")); + vision_model.mm_model_ln_kv_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "kv", "bias")); + vision_model.mm_model_ln_post_w = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "post", "weight")); + vision_model.mm_model_ln_post_b = get_tensor(new_clip->ctx_data, format(TN_MINICPMV_LN, "post", "bias")); + } + else { + std::string proj_type = PROJECTOR_TYPE_NAMES[new_clip->proj_type]; + throw std::runtime_error(format("%s: don't support projector with: %s currently\n", __func__, proj_type.c_str())); + } + + vision_model.layers.resize(hparams.n_layer); + + for (int il = 0; il < hparams.n_layer; ++il) { + auto & layer = vision_model.layers[il]; + layer.k_w = get_tensor(new_clip->ctx_data, format(TN_ATTN_K, "v", il, "weight")); + layer.q_w = get_tensor(new_clip->ctx_data, format(TN_ATTN_Q, "v", il, "weight")); + layer.v_w = get_tensor(new_clip->ctx_data, format(TN_ATTN_V, "v", il, "weight")); + layer.o_w = get_tensor(new_clip->ctx_data, format(TN_ATTN_OUTPUT, "v", il, "weight")); + layer.ln_1_w = get_tensor(new_clip->ctx_data, format(TN_LN_1, "v", il, "weight")); + layer.ln_2_w = get_tensor(new_clip->ctx_data, format(TN_LN_2, "v", il, "weight")); + layer.ff_i_w = get_tensor(new_clip->ctx_data, format(TN_FFN_DOWN, "v", il, "weight")); + layer.ff_o_w = get_tensor(new_clip->ctx_data, format(TN_FFN_UP, "v", il, "weight")); + layer.k_b = get_tensor(new_clip->ctx_data, format(TN_ATTN_K, "v", il, "bias")); + layer.q_b = get_tensor(new_clip->ctx_data, format(TN_ATTN_Q, "v", il, "bias")); + layer.v_b = get_tensor(new_clip->ctx_data, format(TN_ATTN_V, "v", il, "bias")); + layer.o_b = get_tensor(new_clip->ctx_data, format(TN_ATTN_OUTPUT, "v", il, "bias")); + layer.ln_1_b = get_tensor(new_clip->ctx_data, format(TN_LN_1, "v", il, "bias")); + layer.ln_2_b = get_tensor(new_clip->ctx_data, format(TN_LN_2, "v", il, "bias")); + layer.ff_i_b = get_tensor(new_clip->ctx_data, format(TN_FFN_DOWN, "v", il, "bias")); + layer.ff_o_b = get_tensor(new_clip->ctx_data, format(TN_FFN_UP, "v", il, "bias")); + } + } + + ggml_free(meta); + + new_clip->ctx_gguf = ctx; + + // measure mem requirement and allocate + { + // todo + new_clip->buf_compute_meta.resize(GGML_DEFAULT_GRAPH_SIZE * ggml_tensor_overhead() + ggml_graph_overhead()); + new_clip->compute_alloc = ggml_gallocr_new(ggml_backend_get_default_buffer_type(new_clip->backend)); + clip_image_f32_batch batch; + batch.size = 1; + ggml_cgraph * gf = clip_image_build_graph(new_clip, &batch, load_image_size); + ggml_gallocr_reserve(new_clip->compute_alloc, gf); + size_t compute_memory_buffer_size = ggml_gallocr_get_buffer_size(new_clip->compute_alloc, 0); + LOG_TEE("%s: compute allocated memory: %.2f MB\n", __func__, compute_memory_buffer_size /1024.0/1024.0); + } + + return new_clip; +} + +struct clip_image_u8 * clip_image_u8_init() { + return new clip_image_u8(); +} + +struct clip_image_f32 * clip_image_f32_init() { + return new clip_image_f32(); +} + +void clip_image_u8_free(struct clip_image_u8 * img) { delete img; } +void clip_image_f32_free(struct clip_image_f32 * img) { delete img; } +void clip_image_u8_batch_free(struct clip_image_u8_batch * batch) { + if (batch->size > 0) { + delete[] batch->data; + batch->size = 0; + } +} +void clip_image_f32_batch_free(struct clip_image_f32_batch * batch) { + if (batch->size > 0) { + delete[] batch->data; + batch->size = 0; + } +} + +static void build_clip_img_from_data(const stbi_uc * data, int nx, int ny, clip_image_u8 * img) { + img->nx = nx; + img->ny = ny; + img->buf.resize(3 * nx * ny); + memcpy(img->buf.data(), data, img->buf.size()); +} + +bool clip_image_load_from_file(const char * fname, clip_image_u8 * img) { + int nx, ny, nc; + auto * data = stbi_load(fname, &nx, &ny, &nc, 3); + if (!data) { + LOG_TEE("%s: failed to load image '%s'\n", __func__, fname); + return false; + } + build_clip_img_from_data(data, nx, ny, img); + stbi_image_free(data); + return true; +} + +bool clip_image_load_from_bytes(const unsigned char * bytes, size_t bytes_length, struct clip_image_u8 * img) { + int nx, ny, nc; + auto * data = stbi_load_from_memory(bytes, bytes_length, &nx, &ny, &nc, 3); + if (!data) { + LOG_TEE("%s: failed to decode image bytes\n", __func__); + return false; + } + build_clip_img_from_data(data, nx, ny, img); + stbi_image_free(data); + return true; +} + +// Linear interpolation between two points +inline float lerp(float s, float e, float t) { + return s + (e - s) * t; +} +// Bilinear resize function +static void bilinear_resize(const clip_image_u8& src, clip_image_u8& dst, int target_width, int target_height) { + dst.nx = target_width; + dst.ny = target_height; + dst.buf.resize(3 * target_width * target_height); + + float x_ratio = static_cast(src.nx - 1) / target_width; + float y_ratio = static_cast(src.ny - 1) / target_height; + + for (int y = 0; y < target_height; y++) { + for (int x = 0; x < target_width; x++) { + float px = x_ratio * x; + float py = y_ratio * y; + int x_floor = static_cast(px); + int y_floor = static_cast(py); + float x_lerp = px - x_floor; + float y_lerp = py - y_floor; + + for (int c = 0; c < 3; c++) { + float top = lerp( + static_cast(src.buf[3 * (y_floor * src.nx + x_floor) + c]), + static_cast(src.buf[3 * (y_floor * src.nx + (x_floor + 1)) + c]), + x_lerp + ); + float bottom = lerp( + static_cast(src.buf[3 * ((y_floor + 1) * src.nx + x_floor) + c]), + static_cast(src.buf[3 * ((y_floor + 1) * src.nx + (x_floor + 1)) + c]), + x_lerp + ); + dst.buf[3 * (y * target_width + x) + c] = static_cast(lerp(top, bottom, y_lerp)); + } + } + } +} + +// Normalize image to float32 - careful with pytorch .to(model.device, dtype=torch.float16) - this sometimes reduces precision (32>16>32), sometimes not +static void normalize_image_u8_to_f32(const clip_image_u8* src, clip_image_f32* dst, const float mean[3], const float std[3]) { + dst->nx = src->nx; + dst->ny = src->ny; + dst->buf.resize(src->buf.size()); + + for (size_t i = 0; i < src->buf.size(); ++i) { + int c = i % 3; // rgb + dst->buf[i] = (static_cast(src->buf[i]) / 255.0f - mean[c]) / std[c]; + } +} + +inline float clip(float x, float lower, float upper) { + return std::max(lower, std::min(x, upper)); +} + +static bool bicubic_resize(const clip_image_u8 &img, clip_image_u8 &dst, int target_width, int target_height) { + const int nx = img.nx; + const int ny = img.ny; + + dst.nx = target_width; + dst.ny = target_height; + dst.buf.resize(3 * target_width * target_height); + + float Cc; + float C[5]; + float d0, d2, d3, a0, a1, a2, a3; + int i, j, k, jj; + int x, y; + float dx, dy; + float tx, ty; + + tx = (float)nx / (float)target_width; + ty = (float)ny / (float)target_height; + + // Bicubic interpolation; adapted from ViT.cpp, inspired from : + // -> https://github.com/yglukhov/bicubic-interpolation-image-processing/blob/master/libimage.c#L36 + // -> https://en.wikipedia.org/wiki/Bicubic_interpolation + + for (i = 0; i < target_height; i++) { + for (j = 0; j < target_width; j++) { + x = (int)(tx * j); + y = (int)(ty * i); + + dx = tx * j - x; + dy = ty * i - y; + + for (k = 0; k < 3; k++) { + for (jj = 0; jj <= 3; jj++) { + d0 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x - 1, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + d2 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x + 1, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + d3 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x + 2, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + a0 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + + a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; + a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + + C[jj] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx; + + d0 = C[0] - C[1]; + d2 = C[2] - C[1]; + d3 = C[3] - C[1]; + a0 = C[1]; + a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; + a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + Cc = a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy; + + const uint8_t Cc2 = std::min(std::max(std::round(Cc), 0.0f), 255.0f); + dst.buf[(i * target_width + j) * 3 + k] = float(Cc2); + } + } + } + } + + return true; +} + +// llava-1.6 type of resize_and_pad (black) +static void resize_and_pad_image(const clip_image_u8& image, clip_image_u8 &image_output, const std::pair& target_resolution) { + int target_width = target_resolution.first; + int target_height = target_resolution.second; + + float scale_w = static_cast(target_width) / image.nx; + float scale_h = static_cast(target_height) / image.ny; + + int new_width, new_height; + + if (scale_w < scale_h) { + new_width = target_width; + new_height = std::min(static_cast(std::ceil(image.ny * scale_w)), target_height); + } else { + new_height = target_height; + new_width = std::min(static_cast(std::ceil(image.nx * scale_h)), target_width); + } + + clip_image_u8 resized_image; + // bilinear_resize(image, resized_image, new_width, new_height); + bicubic_resize(image, resized_image, new_width, new_height); + + clip_image_u8 padded_image; + padded_image.nx = target_width; + padded_image.ny = target_height; + padded_image.buf.resize(3 * target_width * target_height, 0); // Initialize with black + + // Calculate padding offsets + int pad_x = (target_width - new_width) / 2; + int pad_y = (target_height - new_height) / 2; + + // Copy the resized image into the center of the padded buffer + for (int y = 0; y < new_height; ++y) { + for (int x = 0; x < new_width; ++x) { + for (int c = 0; c < 3; ++c) { + padded_image.buf[3 * ((y + pad_y) * target_width + (x + pad_x)) + c] = resized_image.buf[3 * (y * new_width + x) + c]; + } + } + } + image_output = std::move(padded_image); +} + +/** + * Selects the best resolution from a list of possible resolutions based on the original size. + * + * @param original_size The original size of the image in the format (width, height). + * @param possible_resolutions A list of possible resolutions in the format [(width1, height1), (width2, height2), ...]. + * @return The best fit resolution in the format (width, height). + */ +static std::pair select_best_resolution(const std::pair & original_size, const std::vector> & possible_resolutions) { + int original_width = original_size.first; + int original_height = original_size.second; + std::pair best_fit; + int max_effective_resolution = 0; + int min_wasted_resolution = std::numeric_limits::max(); + + for (const auto& resolution : possible_resolutions) { + int width = resolution.first; + int height = resolution.second; + float scale = std::min(static_cast(width) / original_width, static_cast(height) / original_height); + int downscaled_width = static_cast(original_width * scale); + int downscaled_height = static_cast(original_height * scale); + int effective_resolution = std::min(downscaled_width * downscaled_height, original_width * original_height); + int wasted_resolution = (width * height) - effective_resolution; + // LOG_TEE("resolution: %d %d, scale: %f, downscaled: %d %d, effective: %d, wasted: %d\n", width, height, scale, downscaled_width, downscaled_height, effective_resolution, wasted_resolution); + if (effective_resolution > max_effective_resolution || (effective_resolution == max_effective_resolution && wasted_resolution < min_wasted_resolution)) { + max_effective_resolution = effective_resolution; + min_wasted_resolution = wasted_resolution; + best_fit = resolution; + } + } + + return best_fit; +} + +static std::vector divide_to_patches_u8(const clip_image_u8 & image, int patch_size) { + std::vector patches; + int width = image.nx; + int height = image.ny; + for (int i = 0; i < height; i += patch_size) { + for (int j = 0; j < width; j += patch_size) { + clip_image_u8 *patch = clip_image_u8_init(); + patch->nx = std::min(patch_size, width - j); + patch->ny = std::min(patch_size, height - i); + patch->buf.resize(3 * patch->nx * patch->ny); + for (int y = 0; y < patch->ny; ++y) { + for (int x = 0; x < patch->nx; ++x) { + for (int c = 0; c < 3; ++c) { + patch->buf[3 * (y * patch->nx + x) + c] = image.buf[3 * ((i + y) * width + (j + x)) + c]; + } + } + } + patches.push_back(patch); + } + } + return patches; +} + +// returns the normalized float tensor for llava-1.5, for spatial_unpad with anyres processing for llava-1.6 it returns the normalized image patch tensors as a vector +// res_imgs memory is being allocated here, previous allocations will be freed if found +bool clip_image_preprocess(struct clip_ctx * ctx, const clip_image_u8 * img, clip_image_f32_batch * res_imgs) { + bool pad_to_square = true; + if (!ctx->has_vision_encoder) { + LOG_TEE("This gguf file seems to have no vision encoder\n"); + return false; + } + auto & params = ctx->vision_model.hparams; + // The model config actually contains all we need to decide on how to preprocess, here we automatically switch to the new llava-1.6 preprocessing + if (strcmp(params.mm_patch_merge_type, "spatial_unpad") == 0) { + pad_to_square = false; + } + // free the previous res_imgs if any set + if (res_imgs->size > 0) { + clip_image_f32_batch_free(res_imgs); + } + res_imgs->data = nullptr; + res_imgs->size = 0; + + // the logic below is to pad the shorter side to the longer side with a background color: rgb(122, 116, 104) + // see https://github.com/haotian-liu/LLaVA/blob/e854a2bf85118c504f6f16bf5c3c7c92f8fa8c6b/llava/conversation.py#L113-L156 + + clip_image_u8 * temp = clip_image_u8_init(); // we will keep the input image data here temporarily + + if (pad_to_square && img->nx != img->ny) { + int longer_side = std::max(img->nx, img->ny); + temp->nx = longer_side; + temp->ny = longer_side; + temp->buf.resize(3 * longer_side * longer_side); + const uint8_t bc[3] = {122, 116, 104}; // background color in RGB from LLaVA (this is the mean rgb color * 255) + + // fill with background color + for (size_t i = 0; i < temp->buf.size(); i++) { + temp->buf[i] = bc[i % 3]; + } + + // copy from the input image + for (int y = 0; y < img->ny; y++) { + for (int x = 0; x < img->nx; x++) { + const int i = 3 * (y * img->nx + x); + const int j = 3 * (y * temp->nx + x); + temp->buf[j] = img->buf[i]; + temp->buf[j+1] = img->buf[i+1]; + temp->buf[j+2] = img->buf[i+2]; + } + } + } else { + if (params.image_grid_pinpoints[0] != 0) { + // "spatial_unpad" with "anyres" processing for llava-1.6 + std::vector> possible_resolutions; + for (int i = 0; i < 32 && params.image_grid_pinpoints[i] != 0; i+=2) { + possible_resolutions.push_back({params.image_grid_pinpoints[i], params.image_grid_pinpoints[i+1]}); + } + std::pair best_resolution = select_best_resolution({img->nx, img->ny}, possible_resolutions); + // clip_image_save_to_bmp(*img, "input.bmp"); + resize_and_pad_image(*img, *temp, best_resolution); // we do not pad with mean-bg color anymore in llava-1.6 + // clip_image_save_to_bmp(*temp, "resized.bmp"); + // visually verify normalized image: + // normalize_image_u8_to_f32(*temp, *res, ctx->image_mean, ctx->image_std); + // { + // clip_image_u8 * temp2 = clip_image_u8_init(); + // clip_image_convert_f32_to_u8(*res, *temp2); + // clip_image_save_to_bmp(*temp2, "resized_normalized_f32.bmp"); + // clip_image_u8_free(temp2); + // } + + std::vector patches = divide_to_patches_u8(*temp, params.image_size); // prepare spatial sorted main patches of image_size each (336 in llava-1.6) + + clip_image_u8 *image_original_resize = clip_image_u8_init(); + // bilinear_resize(*img, *image_original_resize, params.image_size, params.image_size); // in python this is "shortest_edge", but all CLIP are square + bicubic_resize(*img, *image_original_resize, params.image_size, params.image_size); // in python this is "shortest_edge", but all CLIP are square + patches.insert(patches.begin(), image_original_resize); + // clip_image_f32_batch_init(patches.size()); + res_imgs->size = patches.size(); + res_imgs->data = new clip_image_f32[res_imgs->size]; + int num=0; + for (auto& patch : patches) { + normalize_image_u8_to_f32(patch, &res_imgs->data[num], ctx->image_mean, ctx->image_std); + num++; + } + + for (size_t i = 0; i < patches.size(); i++) { + // LOG_TEE("patch %d: %d %d\n", i, patches[i]->nx, patches[i]->ny); + clip_image_u8_free(patches[i]); + } + + clip_image_u8_free(temp); + + return true; + } else { + temp->nx = img->nx; + temp->ny = img->ny; + temp->buf.resize(img->buf.size()); + memcpy(temp->buf.data(), img->buf.data(), temp->buf.size()); + } + } + + const int nx = temp->nx; + const int ny = temp->ny; + // clip_image_save_to_bmp(*temp, "resized_vanilla.bmp"); + + const int nx2 = ctx->vision_model.hparams.image_size; + const int ny2 = ctx->vision_model.hparams.image_size; + clip_image_f32 * res = clip_image_f32_init(); + res->nx = nx2; + res->ny = ny2; + res->buf.resize(3 * nx2 * ny2); + + const float scale = std::max(nx, ny) / (float)ctx->vision_model.hparams.image_size; + + const int nx3 = int(nx / scale + 0.5f); + const int ny3 = int(ny / scale + 0.5f); + + const auto & m3 = ctx->image_mean; // {0.48145466f, 0.4578275f, 0.40821073f}; + const auto & s3 = ctx->image_std; // {0.26862954f, 0.26130258f, 0.27577711f}; + + for (int y = 0; y < ny3; y++) { + for (int x = 0; x < nx3; x++) { + for (int c = 0; c < 3; c++) { + // linear interpolation + const float sx = (x + 0.5f) * scale - 0.5f; + const float sy = (y + 0.5f) * scale - 0.5f; + + const int x0 = std::max(0, (int)std::floor(sx)); + const int y0 = std::max(0, (int)std::floor(sy)); + + const int x1 = std::min(x0 + 1, nx - 1); + const int y1 = std::min(y0 + 1, ny - 1); + + const float dx = sx - x0; + const float dy = sy - y0; + + const int j00 = 3 * (y0 * nx + x0) + c; + const int j01 = 3 * (y0 * nx + x1) + c; + const int j10 = 3 * (y1 * nx + x0) + c; + const int j11 = 3 * (y1 * nx + x1) + c; + + const float v00 = temp->buf[j00]; + const float v01 = temp->buf[j01]; + const float v10 = temp->buf[j10]; + const float v11 = temp->buf[j11]; + + const float v0 = v00 * (1.0f - dx) + v01 * dx; + const float v1 = v10 * (1.0f - dx) + v11 * dx; + + const float v = v0 * (1.0f - dy) + v1 * dy; + + const uint8_t v2 = std::min(std::max(std::round(v), 0.0f), 255.0f); + + const int i = 3 * (y * nx3 + x) + c; + + res->buf[i] = ((float(v2) / 255.0f) - m3[c]) / s3[c]; + } + } + } + clip_image_u8_free(temp); + + // { + // clip_image_u8 * temp2 = clip_image_u8_init(); + // clip_image_convert_f32_to_u8(*res, *temp2); + // clip_image_save_to_bmp(*temp2, "resized_normalized_f32_vanilla.bmp"); + // clip_image_u8_free(temp2); + // } + // res_imgs.push_back(res); + + res_imgs->size = 1; + res_imgs->data = new clip_image_f32[res_imgs->size]; + res_imgs->data[0] = *res; + clip_image_f32_free(res); + + return true; +} + +ggml_tensor * clip_get_newline_tensor(const struct clip_ctx * ctx) { + return ctx->vision_model.image_newline; +} + +void clip_free(clip_ctx * ctx) { + ggml_free(ctx->ctx_data); + gguf_free(ctx->ctx_gguf); + + ggml_backend_buffer_free(ctx->params_buffer); + ggml_backend_free(ctx->backend); + ggml_gallocr_free(ctx->compute_alloc); + delete ctx; +} + +size_t clip_embd_nbytes(const struct clip_ctx * ctx) { + return clip_n_patches(ctx) * clip_n_mmproj_embd(ctx) * sizeof(float); +} + +int32_t clip_image_size(const struct clip_ctx * ctx) { + return ctx->vision_model.hparams.image_size; +} + +int32_t clip_patch_size(const struct clip_ctx * ctx) { + return ctx->vision_model.hparams.patch_size; +} + +int32_t clip_hidden_size(const struct clip_ctx * ctx) { + return ctx->vision_model.hparams.hidden_size; +} + +const char * clip_patch_merge_type(const struct clip_ctx * ctx) { + return ctx->vision_model.hparams.mm_patch_merge_type; +} + +const int32_t * clip_image_grid(const struct clip_ctx * ctx) { + return ctx->vision_model.hparams.image_grid_pinpoints; +} + +int clip_n_patches(const struct clip_ctx * ctx) { + const auto & params = ctx->vision_model.hparams; + + int n_patches = (params.image_size / params.patch_size) * (params.image_size / params.patch_size); + + if (ctx->proj_type == PROJECTOR_TYPE_LDP || ctx->proj_type == PROJECTOR_TYPE_LDPV2) { + n_patches /= 4; + } else if (ctx->proj_type == PROJECTOR_TYPE_RESAMPLER) { + n_patches = 96; + } + + return n_patches; +} + +bool clip_image_encode(struct clip_ctx * ctx, const int n_threads, clip_image_f32 * img, float * vec, std::pair load_image_size = {70, 70}) { + if (!ctx->has_vision_encoder) { + LOG_TEE("This gguf file seems to have no vision encoder\n"); + return false; + } + + clip_image_f32_batch imgs{}; + imgs.size = 1; + imgs.data = img; + return clip_image_batch_encode(ctx, n_threads, &imgs, vec, load_image_size); +} + +bool clip_image_batch_encode(clip_ctx * ctx, const int n_threads, const clip_image_f32_batch * imgs, float * vec, std::pair load_image_size = {70, 70}) { + if (!ctx->has_vision_encoder) { + LOG_TEE("This gguf file seems to have no vision encoder\n"); + return false; + } + + int batch_size = imgs->size; + if (ctx->has_llava_projector) { + GGML_ASSERT(batch_size == 1); // TODO: support multiple images + } + + // build the inference graph + ggml_cgraph * gf = clip_image_build_graph(ctx, imgs, load_image_size); + ggml_gallocr_alloc_graph(ctx->compute_alloc, gf); + + // set inputs + const auto & model = ctx->vision_model; + const auto & hparams = model.hparams; + + const int image_size = hparams.image_size; + const int patch_size = hparams.patch_size; + const int num_patches = ((image_size / patch_size) * (image_size / patch_size)); + const int num_positions = num_patches; + + { + struct ggml_tensor * inp_raw = ggml_graph_get_tensor(gf, "inp_raw"); + float * data = (float *)malloc(ggml_nbytes(inp_raw)); + + for (size_t i = 0; i < imgs->size; i++) { + const int nx = imgs->data[i].nx; + const int ny = imgs->data[i].ny; + GGML_ASSERT(nx == image_size && ny == image_size); + + const int n = nx * ny; + + for (int b = 0; b < batch_size; b++) { + for (int k = 0; k < 3; k++) { + for (int y = 0; y < ny; y++) { + for (int x = 0; x < nx; x++) { + data[(b * 3 * n) + k * n + y * nx + x] = imgs->data[b].buf[3 * (y * nx + x) + k]; + } + } + } + } + } + ggml_backend_tensor_set(inp_raw, data, 0, ggml_nbytes(inp_raw)); + free(data); + } + + { + struct ggml_tensor * positions = ggml_graph_get_tensor(gf, "positions"); + + int* positions_data = (int*)malloc(ggml_nbytes(positions)); + for (int i = 0; i < num_positions; i++) { + positions_data[i] = i; + } + ggml_backend_tensor_set(positions, positions_data, 0, ggml_nbytes(positions)); + free(positions_data); + } + + // { + // struct ggml_tensor * patches = ggml_graph_get_tensor(gf, "patches"); + // int* patches_data = (int*)malloc(ggml_nbytes(patches)); + // for (int i = 0; i < num_patches; i++) { + // patches_data[i] = i + 1; + // } + // ggml_backend_tensor_set(patches, patches_data, 0, ggml_nbytes(patches)); + // free(patches_data); + // } + + if (ggml_backend_is_cpu(ctx->backend)) { + ggml_backend_cpu_set_n_threads(ctx->backend, n_threads); + } + +#ifdef GGML_USE_METAL + if (ggml_backend_is_metal(ctx->backend)) { + ggml_backend_metal_set_n_cb(ctx->backend, n_threads); + } +#endif + + ggml_backend_graph_compute(ctx->backend, gf); + + // the last node is the embedding tensor + struct ggml_tensor * embeddings = gf->nodes[gf->n_nodes - 1]; + + // copy the embeddings to the location passed by the user + ggml_backend_tensor_get(embeddings, vec, 0, ggml_nbytes(embeddings)); + + return true; +} + +bool clip_model_quantize(const char * fname_inp, const char * fname_out, const int itype) { + ggml_type type = GGML_TYPE_Q4_1; + + assert(itype < GGML_TYPE_COUNT); + type = static_cast(itype); + + auto * ctx_clip = clip_model_load(fname_inp, 2); + + const auto & ctx_src = ctx_clip->ctx_gguf; + const auto & ctx_data = ctx_clip->ctx_data; + + auto * ctx_out = gguf_init_empty(); + gguf_set_kv(ctx_out, ctx_src); + gguf_set_val_u32(ctx_out, "general.quantization_version", GGML_QNT_VERSION); + gguf_set_val_u32(ctx_out, "general.file_type", itype); + + auto fout = std::ofstream(fname_out, std::ios::binary); + + const int n_tensors = gguf_get_n_tensors(ctx_src); + + for (int i = 0; i < n_tensors; ++i) { + const char * name = gguf_get_tensor_name(ctx_src, i); + struct ggml_tensor * cur = ggml_get_tensor(ctx_data, name); + gguf_add_tensor(ctx_out, cur); + } + + const size_t meta_size = gguf_get_meta_size(ctx_out); + for (size_t i = 0; i < meta_size; ++i) { + fout.put(0); + } + + // regexes of tensor names to be quantized + const std::vector k_names = { + ".*weight", + }; + + std::vector work(512); + std::vector conv_buf(512); + size_t total_size_org = 0; + size_t total_size_new = 0; + + for (int i = 0; i < n_tensors; ++i) { + const std::string name = gguf_get_tensor_name(ctx_src, i); + struct ggml_tensor * cur = ggml_get_tensor(ctx_data, name.c_str()); + + enum ggml_type new_type; + void * new_data; + size_t new_size; + + bool quantize = false; + for (const auto & s : k_names) { + if (std::regex_match(name, std::regex(s))) { + quantize = true; + break; + } + } + + // quantize only 2D tensors + quantize &= (ggml_n_dims(cur) == 2); + + if (quantize) { + new_type = type; + if (new_type >= GGML_TYPE_Q2_K && name.find("embd") != std::string::npos) { + new_type = GGML_TYPE_Q8_0; // ggml_get_rows needs non K type + // LOG_TEE("%s: quantizing %s to %s\n", __func__, name.c_str(), ggml_type_name(new_type)); + } + const size_t n_elms = ggml_nelements(cur); + float * f32_data; + + switch (cur->type) { + case GGML_TYPE_F32: + f32_data = (float *)cur->data; + break; + case GGML_TYPE_F16: + if (conv_buf.size() < n_elms) { + conv_buf.resize(n_elms); + } + for (size_t j = 0; j < n_elms; ++j) { + conv_buf[j] = ggml_fp16_to_fp32(((ggml_fp16_t *)cur->data)[j]); + } + f32_data = (float *)conv_buf.data(); + break; + default: + LOG_TEE("Please use an input file in f32 or f16\n"); + gguf_free(ctx_out); + return false; + } + + if (work.size() < n_elms * 4) { + work.resize(n_elms * 4); + } + new_data = work.data(); + + new_size = ggml_quantize_chunk(new_type, f32_data, new_data, 0, n_elms/cur->ne[0], cur->ne[0], nullptr); + } else { + new_type = cur->type; + new_data = cur->data; + new_size = ggml_nbytes(cur); + } + const size_t orig_size = ggml_nbytes(cur); + total_size_org += orig_size; + total_size_new += new_size; + gguf_set_tensor_type(ctx_out, name.c_str(), new_type); + gguf_set_tensor_data(ctx_out, name.c_str(), new_data, new_size); + fout.write((const char *)new_data, new_size); + size_t pad = GGML_PAD(new_size, gguf_get_alignment(ctx_out)) - new_size; + for (size_t j = 0; j < pad; ++j) { + fout.put(0); + } + + LOG_TEE("%s: n_dims = %d | quantize=%d | size = %f MB -> %f MB\n", name.c_str(), ggml_n_dims(cur), quantize, + orig_size / 1024.0 / 1024.0, new_size / 1024.0 / 1024.0); + } + + // go back to beginning of file and write the updated metadata + fout.seekp(0, std::ios::beg); + std::vector meta(meta_size); + gguf_get_meta_data(ctx_out, meta.data()); + fout.write((const char *)meta.data(), meta_size); + + fout.close(); + + clip_free(ctx_clip); + gguf_free(ctx_out); + + { + LOG_TEE("%s: original size = %8.2f MB\n", __func__, total_size_org / 1024.0 / 1024.0); + LOG_TEE("%s: quantized size = %8.2f MB\n", __func__, total_size_new / 1024.0 / 1024.0); + } + + return true; +} + +int clip_n_mmproj_embd(const struct clip_ctx * ctx) { + if (ctx->proj_type == PROJECTOR_TYPE_LDP) { + return ctx->vision_model.mm_model_block_1_block_2_1_b->ne[0]; + } + if (ctx->proj_type == PROJECTOR_TYPE_LDPV2) { + return ctx->vision_model.mm_model_peg_0_b->ne[0]; + } + if (ctx->proj_type == PROJECTOR_TYPE_MLP) { + return ctx->vision_model.mm_2_b->ne[0]; + } + if (ctx->proj_type == PROJECTOR_TYPE_MLP_NORM) { + return ctx->vision_model.mm_3_b->ne[0]; + } + if (ctx->proj_type == PROJECTOR_TYPE_RESAMPLER) { + return 4096; + } + + std::string proj_type = PROJECTOR_TYPE_NAMES[ctx->proj_type]; + throw std::runtime_error(format("%s: don't support projector with: %s currently\n", __func__, proj_type.c_str())); +} diff --git a/examples/minicpmv/clip.h b/examples/minicpmv/clip.h new file mode 100644 index 0000000000000..335a02e1ddd6d --- /dev/null +++ b/examples/minicpmv/clip.h @@ -0,0 +1,86 @@ +#ifndef CLIP_H +#define CLIP_H + +#include +#include +#include + +#ifdef LLAMA_SHARED +# if defined(_WIN32) && !defined(__MINGW32__) +# ifdef LLAMA_BUILD +# define CLIP_API __declspec(dllexport) +# else +# define CLIP_API __declspec(dllimport) +# endif +# else +# define CLIP_API __attribute__ ((visibility ("default"))) +# endif +#else +# define CLIP_API +#endif + +struct clip_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +struct clip_ctx; + +struct clip_image_u8_batch { + struct clip_image_u8 * data; + size_t size; +}; + +struct clip_image_f32_batch { + struct clip_image_f32 * data; + size_t size; +}; + +CLIP_API struct clip_ctx * clip_model_load (const char * fname, int verbosity, std::pair load_image_size); +CLIP_API struct clip_ctx * clip_model_load_cpu(const char * fname, int verbosity); + +CLIP_API void clip_free(struct clip_ctx * ctx); + +CLIP_API size_t clip_embd_nbytes(const struct clip_ctx * ctx); + +CLIP_API int32_t clip_image_size (const struct clip_ctx * ctx); +CLIP_API int32_t clip_patch_size (const struct clip_ctx * ctx); +CLIP_API int32_t clip_hidden_size(const struct clip_ctx * ctx); + +// TODO: should be enum, not string +CLIP_API const char * clip_patch_merge_type(const struct clip_ctx * ctx); + +CLIP_API const int32_t * clip_image_grid(const struct clip_ctx * ctx); + +CLIP_API int clip_n_patches (const struct clip_ctx * ctx); +CLIP_API int clip_n_mmproj_embd(const struct clip_ctx * ctx); + +CLIP_API struct clip_image_u8 * clip_image_u8_init (); +CLIP_API struct clip_image_f32 * clip_image_f32_init(); + +CLIP_API void clip_image_u8_free (struct clip_image_u8 * img); +CLIP_API void clip_image_f32_free(struct clip_image_f32 * img); +CLIP_API void clip_image_u8_batch_free (struct clip_image_u8_batch * batch); +CLIP_API void clip_image_f32_batch_free(struct clip_image_f32_batch * batch); + +CLIP_API bool clip_image_load_from_file(const char * fname, struct clip_image_u8 * img); + +/** interpret bytes as an image file with length bytes_length, and use the result to populate img */ +CLIP_API bool clip_image_load_from_bytes(const unsigned char * bytes, size_t bytes_length, struct clip_image_u8 * img); + +/** preprocess img and store the result in res_imgs, pad_to_square may be overriden to false depending on model configuration */ +CLIP_API bool clip_image_preprocess(struct clip_ctx * ctx, const struct clip_image_u8 * img, struct clip_image_f32_batch * res_imgs ); + +CLIP_API struct ggml_tensor * clip_get_newline_tensor(const struct clip_ctx * ctx); + +CLIP_API bool clip_image_encode (struct clip_ctx * ctx, int n_threads, struct clip_image_f32 * img, float * vec, std::pair load_image_size); +CLIP_API bool clip_image_batch_encode(struct clip_ctx * ctx, int n_threads, const struct clip_image_f32_batch * imgs, float * vec, std::pair load_image_size); + +CLIP_API bool clip_model_quantize(const char * fname_inp, const char * fname_out, int itype); + +#ifdef __cplusplus +} +#endif + +#endif // CLIP_H diff --git a/examples/minicpmv/minicpmv-cli.cpp b/examples/minicpmv/minicpmv-cli.cpp new file mode 100644 index 0000000000000..e9cd526b798e0 --- /dev/null +++ b/examples/minicpmv/minicpmv-cli.cpp @@ -0,0 +1,158 @@ +#include "ggml.h" +#include "log.h" +#include "common.h" +#include "clip.h" +#include "minicpmv.h" +#include "minicpmv_io.h" +#include "llama.h" + +#include +#include +#include + +static void show_additional_info(int /*argc*/, char ** argv) { + LOG_TEE("\n example usage: %s -m --mmproj --image --image [--temp 0.1] [-p \"describe the image in detail.\"]\n", argv[0]); + LOG_TEE(" note: a lower temperature value like 0.1 is recommended for better quality.\n"); +} + +static void llama_log_callback_logTee(ggml_log_level level, const char * text, void * user_data) { + (void) level; + (void) user_data; + LOG_TEE("%s", text); +} + +struct minicpmv_context * minicpmv_init(gpt_params * params, const std::string & fname, int &n_past){ + auto image_embed_slices = minicpmv_image_embed(params, fname); + if (!image_embed_slices[0][0]) { + std::cerr << "error: failed to load image " << fname << ". Terminating\n\n"; + return NULL; + } + + // process the prompt + if (params->prompt.empty() && params->interactive == false) { + LOG_TEE("prompt should be given or interactive mode should be on"); + return NULL; + } + + auto model = llava_init(params); + if (model == NULL) { + fprintf(stderr, "%s: error: failed to init minicpmv model\n", __func__); + return NULL; + } + const int64_t t_llava_init_start_us = ggml_time_us(); + auto ctx_llava = llava_init_context(params, model); + + const int64_t t_llava_init_end_us = ggml_time_us(); + float t_llava_init_ms = (t_llava_init_end_us - t_llava_init_start_us) / 1000.0; + LOG_TEE("\n%s: llava init in %8.2f ms.\n", __func__, t_llava_init_ms); + + const int64_t t_process_image_start_us = ggml_time_us(); + process_image(ctx_llava, image_embed_slices, params, n_past); + const int64_t t_process_image_end_us = ggml_time_us(); + float t_process_image_ms = (t_process_image_end_us - t_process_image_start_us) / 1000.0; + LOG_TEE("\n%s: llama process image in %8.2f ms.\n", __func__, t_process_image_ms); + + llava_image_embed_free_slice(image_embed_slices); + return ctx_llava; +} + +struct llama_sampling_context * llama_init(struct minicpmv_context * ctx_llava, gpt_params * params, std::string prompt, int &n_past, bool is_first = false){ + std::string user_prompt = prompt; + if (!is_first) user_prompt = "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n" + prompt; + const int max_tgt_len = params->n_predict < 0 ? 256 : params->n_predict; + + eval_string(ctx_llava->ctx_llama, user_prompt.c_str(), params->n_batch, &n_past, false); + eval_string(ctx_llava->ctx_llama, "<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", params->n_batch, &n_past, false); + // generate the response + + LOG_TEE("\n"); + + struct llama_sampling_context * ctx_sampling = llama_sampling_init(params->sparams); + return ctx_sampling; +} + +const char * llama_loop(struct minicpmv_context * ctx_llava,struct llama_sampling_context * ctx_sampling, int &n_past){ + + const char * tmp = sample(ctx_sampling, ctx_llava->ctx_llama, &n_past); + return tmp; +} + +int main(int argc, char ** argv) { + ggml_time_init(); + + gpt_params params; + + if (!gpt_params_parse(argc, argv, params)) { + show_additional_info(argc, argv); + return 1; + } + +#ifndef LOG_DISABLE_LOGS + log_set_target(log_filename_generator("llava", "log")); + LOG_TEE("Log start\n"); + log_dump_cmdline(argc, argv); + llama_log_set(llama_log_callback_logTee, nullptr); +#endif // LOG_DISABLE_LOGS + + if (params.mmproj.empty() || (params.image.empty())) { + gpt_params_print_usage(argc, argv, params); + show_additional_info(argc, argv); + return 1; + } + + for (auto & image : params.image) { + int n_past = 0; + auto ctx_llava = minicpmv_init(¶ms, image, n_past); + + if (!params.prompt.empty()) { + LOG_TEE("%s\n", params.prompt.c_str()); + LOG_TEE(""); + auto ctx_sampling = llama_init(ctx_llava, ¶ms, params.prompt.c_str(), n_past, true); + const int max_tgt_len = params.n_predict < 0 ? 256 : params.n_predict; + std::string response = ""; + bool have_tmp = false; + for (int i = 0; i < max_tgt_len; i++) { + auto tmp = llama_loop(ctx_llava, ctx_sampling, n_past); + response += tmp; + if (strcmp(tmp, "") == 0){ + if(!have_tmp)continue; + else break; + } + if (strstr(tmp, "###")) break; // Yi-VL behavior + have_tmp = true; + printf("%s", tmp); + if (strstr(response.c_str(), "")) break; // minicpm-v + + fflush(stdout); + } + llama_sampling_free(ctx_sampling); + }else { + while (true) { + LOG_TEE(""); + std::string prompt; + std::getline(std::cin, prompt); + LOG_TEE(""); + auto ctx_sampling = llama_init(ctx_llava, ¶ms, prompt, n_past, true); + const int max_tgt_len = params.n_predict < 0 ? 256 : params.n_predict; + std::string response = ""; + for (int i = 0; i < max_tgt_len; i++) { + auto tmp = llama_loop(ctx_llava, ctx_sampling, n_past); + response += tmp; + if (strcmp(tmp, "") == 0) break; + if (strstr(tmp, "###")) break; // Yi-VL behavior + printf("%s", tmp);// mistral llava-1.6 + if (strstr(response.c_str(), "")) break; // minicpm-v + fflush(stdout); + } + llama_sampling_free(ctx_sampling); + } + } + printf("\n"); + llama_print_timings(ctx_llava->ctx_llama); + + ctx_llava->model = NULL; + llava_free(ctx_llava); + } + + return 0; +} \ No newline at end of file diff --git a/examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py b/examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py new file mode 100644 index 0000000000000..c184e56ac202a --- /dev/null +++ b/examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py @@ -0,0 +1,382 @@ +import argparse +import os +import json +import re + +import torch +import numpy as np +from gguf import * +import timm +from transformers.models.idefics2.modeling_idefics2 import Idefics2VisionTransformer, Idefics2VisionConfig + +TEXT = "clip.text" +VISION = "clip.vision" + + +def k(raw_key: str, arch: str) -> str: + return raw_key.format(arch=arch) + + +def should_skip_tensor(name: str, has_text: bool, has_vision: bool, has_minicpmv: bool) -> bool: + if name in ( + "logit_scale", + "text_model.embeddings.position_ids", + "vision_model.embeddings.position_ids", + ): + return True + + if has_minicpmv and name in ["visual_projection.weight"]: + return True + + if name.startswith("v") and not has_vision: + return True + + if name.startswith("t") and not has_text: + return True + + return False + + +def get_tensor_name(name: str) -> str: + if "projection" in name: + return name + if "mm_projector" in name: + name = name.replace("model.mm_projector", "mm") + name = re.sub(r'mm\.mlp\.mlp', 'mm.model.mlp', name, count=1) + name = re.sub(r'mm\.peg\.peg', 'mm.model.peg', name, count=1) + return name + + return name.replace("text_model", "t").replace("vision_model", "v").replace("encoder.layers", "blk").replace("embeddings.", "").replace("_proj", "").replace("self_attn.", "attn_").replace("layer_norm", "ln").replace("layernorm", "ln").replace("mlp.fc1", "ffn_down").replace("mlp.fc2", "ffn_up").replace("embedding", "embd").replace("final", "post").replace("layrnorm", "ln") + + +def bytes_to_unicode(): + """ + Returns list of utf-8 byte and a corresponding list of unicode strings. + The reversible bpe codes work on unicode strings. + This means you need a large # of unicode characters in your vocab if you want to avoid UNKs. + When you're at something like a 10B token dataset you end up needing around 5K for decent coverage. + This is a significant percentage of your normal, say, 32K bpe vocab. + To avoid that, we want lookup tables between utf-8 bytes and unicode strings. + And avoids mapping to whitespace/control characters the bpe code barfs on. + """ + bs = ( + list(range(ord("!"), ord("~") + 1)) + + list(range(ord("¡"), ord("¬") + 1)) + + list(range(ord("®"), ord("ÿ") + 1)) + ) + cs = bs[:] + n = 0 + for b in range(2**8): + if b not in bs: + bs.append(b) + cs.append(2**8 + n) + n += 1 + cs = [chr(n) for n in cs] + return dict(zip(bs, cs)) + + +ap = argparse.ArgumentParser() +ap.add_argument("-m", "--model-dir", help="Path to model directory cloned from HF Hub", required=True) +ap.add_argument("--use-f32", action="store_true", default=False, help="Use f32 instead of f16") +ap.add_argument("--text-only", action="store_true", required=False, + help="Save a text-only model. It can't be used to encode images") +ap.add_argument("--vision-only", action="store_true", required=False, + help="Save a vision-only model. It can't be used to encode texts") +ap.add_argument("--clip-model-is-vision", action="store_true", required=False, + help="The clip model is a pure vision model (ShareGPT4V vision extract for example)") +ap.add_argument("--clip-model-is-openclip", action="store_true", required=False, + help="The clip model is from openclip (for ViT-SO400M type))") +ap.add_argument("--minicpmv-projector", help="Path to minicpmv.projector file. If specified, save an image encoder for MiniCPM-V models.") +ap.add_argument("--projector-type", help="Type of projector. Possible values: mlp, ldp, ldpv2", choices=["mlp", "ldp", "ldpv2"], default="mlp") +ap.add_argument("-o", "--output-dir", help="Directory to save GGUF files. Default is the original model directory", default=None) +# Example --image_mean 0.48145466 0.4578275 0.40821073 --image_std 0.26862954 0.26130258 0.27577711 +# Example --image_mean 0.5 0.5 0.5 --image_std 0.5 0.5 0.5 +default_image_mean = [0.48145466, 0.4578275, 0.40821073] +default_image_std = [0.26862954, 0.26130258, 0.27577711] +ap.add_argument('--image-mean', type=float, nargs='+', help='Mean of the images for normalization (overrides processor) ', default=None) +ap.add_argument('--image-std', type=float, nargs='+', help='Standard deviation of the images for normalization (overrides processor)', default=None) + +# with proper +args = ap.parse_args() + + +if args.text_only and args.vision_only: + print("--text-only and --image-only arguments cannot be specified at the same time.") + exit(1) + +if args.use_f32: + print("WARNING: Weights for the convolution op is always saved in f16, as the convolution op in GGML does not support 32-bit kernel weights yet.") + +# output in the same directory as the model if output_dir is None +dir_model = args.model_dir + +if args.clip_model_is_vision or not os.path.exists(dir_model + "/vocab.json") or args.clip_model_is_openclip: + vocab = None + tokens = None +else: + with open(dir_model + "/vocab.json", "r", encoding="utf-8") as f: + vocab = json.load(f) + tokens = [key for key in vocab] + +# possible data types +# ftype == 0 -> float32 +# ftype == 1 -> float16 +# +# map from ftype to string +ftype_str = ["f32", "f16"] + +ftype = 1 +if args.use_f32: + ftype = 0 + +# if args.clip_model_is_vision or args.clip_model_is_openclip: +# model = CLIPVisionModel.from_pretrained(dir_model) +# processor = None +# else: +# model = CLIPModel.from_pretrained(dir_model) +# processor = CLIPProcessor.from_pretrained(dir_model) + +default_vision_config = { + "hidden_size": 1152, + "image_size": 980, + "intermediate_size": 4304, + "model_type": "idefics2", + "num_attention_heads": 16, + "num_hidden_layers": 27, + "patch_size": 14, + } +vision_config = Idefics2VisionConfig(**default_vision_config) +model = Idefics2VisionTransformer(vision_config) + +processor = None +# if model.attn_pool is not None: +# model.attn_pool = torch.nn.Identity() + +# model.blocks = model.blocks[:-1] +model.load_state_dict(torch.load(os.path.join(dir_model, "minicpmv.clip"))) + +fname_middle = None +has_text_encoder = True +has_vision_encoder = True +has_minicpmv_projector = False +if args.text_only: + fname_middle = "text-" + has_vision_encoder = False +elif args.minicpmv_projector is not None: + fname_middle = "mmproj-" + has_text_encoder = False + has_minicpmv_projector = True +elif args.vision_only: + fname_middle = "vision-" + has_text_encoder = False +else: + fname_middle = "" + +output_dir = args.output_dir if args.output_dir is not None else dir_model +os.makedirs(output_dir, exist_ok=True) +output_prefix = os.path.basename(output_dir).replace("ggml_", "") +fname_out = os.path.join(output_dir, f"{fname_middle}model-{ftype_str[ftype]}.gguf") +fout = GGUFWriter(path=fname_out, arch="clip") + +fout.add_bool("clip.has_text_encoder", has_text_encoder) +fout.add_bool("clip.has_vision_encoder", has_vision_encoder) +fout.add_bool("clip.has_minicpmv_projector", has_minicpmv_projector) +fout.add_file_type(ftype) +if args.text_only: + fout.add_description("text-only CLIP model") +elif args.vision_only and not has_minicpmv_projector: + fout.add_description("vision-only CLIP model") +elif has_minicpmv_projector: + fout.add_description("image encoder for MiniCPM-V") + # add projector type + fout.add_string("clip.projector_type", "resampler") +else: + fout.add_description("two-tower CLIP model") + +if has_vision_encoder: + # vision_model hparams + fout.add_uint32("clip.vision.image_size", 448) + fout.add_uint32("clip.vision.patch_size", 14) + fout.add_uint32(k(KEY_EMBEDDING_LENGTH, VISION), 1152) + fout.add_uint32(k(KEY_FEED_FORWARD_LENGTH, VISION), 4304) + fout.add_uint32("clip.vision.projection_dim", 0) + fout.add_uint32(k(KEY_ATTENTION_HEAD_COUNT, VISION), 16) + fout.add_float32(k(KEY_ATTENTION_LAYERNORM_EPS, VISION), 1e-6) + block_count = 26 + fout.add_uint32(k(KEY_BLOCK_COUNT, VISION), block_count) + + if processor is not None: + image_mean = processor.image_processor.image_mean if args.image_mean is None or args.image_mean == default_image_mean else args.image_mean + image_std = processor.image_processor.image_std if args.image_std is None or args.image_std == default_image_std else args.image_std + else: + image_mean = args.image_mean if args.image_mean is not None else default_image_mean + image_std = args.image_std if args.image_std is not None else default_image_std + fout.add_array("clip.vision.image_mean", image_mean) + fout.add_array("clip.vision.image_std", image_std) + +use_gelu = True +fout.add_bool("clip.use_gelu", use_gelu) + +def get_1d_sincos_pos_embed_from_grid(embed_dim, pos): + """ + embed_dim: output dimension for each position + pos: a list of positions to be encoded: size (M,) + out: (M, D) + """ + assert embed_dim % 2 == 0 + omega = np.arange(embed_dim // 2, dtype=np.float32) + omega /= embed_dim / 2. + omega = 1. / 10000 ** omega # (D/2,) + + pos = pos.reshape(-1) # (M,) + out = np.einsum('m,d->md', pos, omega) # (M, D/2), outer product + + emb_sin = np.sin(out) # (M, D/2) + emb_cos = np.cos(out) # (M, D/2) + + emb = np.concatenate([emb_sin, emb_cos], axis=1) # (M, D) + return emb + +def get_2d_sincos_pos_embed_from_grid(embed_dim, grid): + assert embed_dim % 2 == 0 + + # use half of dimensions to encode grid_h + emb_h = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0]) # (H*W, D/2) + emb_w = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1]) # (H*W, D/2) + + emb = np.concatenate([emb_h, emb_w], axis=1) # (H*W, D) + return emb + + +# https://github.com/facebookresearch/mae/blob/efb2a8062c206524e35e47d04501ed4f544c0ae8/util/pos_embed.py#L20 +def get_2d_sincos_pos_embed(embed_dim, grid_size, cls_token=False): + """ + grid_size: int of the grid height and width + return: + pos_embed: [grid_size*grid_size, embed_dim] or [1+grid_size*grid_size, embed_dim] (w/ or w/o cls_token) + """ + if isinstance(grid_size, int): + grid_h_size, grid_w_size = grid_size, grid_size + else: + grid_h_size, grid_w_size = grid_size[0], grid_size[1] + + grid_h = np.arange(grid_h_size, dtype=np.float32) + grid_w = np.arange(grid_w_size, dtype=np.float32) + grid = np.meshgrid(grid_w, grid_h) # here w goes first + grid = np.stack(grid, axis=0) + + grid = grid.reshape([2, 1, grid_h_size, grid_w_size]) + pos_embed = get_2d_sincos_pos_embed_from_grid(embed_dim, grid) + if cls_token: + pos_embed = np.concatenate([np.zeros([1, embed_dim]), pos_embed], axis=0) + return pos_embed + +def _replace_name_resampler(s, v): + if re.match("resampler.pos_embed", s): + return { + s: v, + re.sub("pos_embed", "pos_embed_k", s): torch.from_numpy(get_2d_sincos_pos_embed(4096, (448//14, 448//14))), + } + if re.match("resampler.proj", s): + return { + re.sub("proj", "pos_embed_k", s): torch.from_numpy(get_2d_sincos_pos_embed(4096, (448//14, 448//14))), + re.sub("proj", "proj.weight", s): v.transpose(-1, -2).contiguous(), + } + if re.match("resampler.attn.in_proj_.*", s): + return { + re.sub("attn.in_proj_", "attn.q.", s): v.chunk(3, dim=0)[0], + re.sub("attn.in_proj_", "attn.k.", s): v.chunk(3, dim=0)[1], + re.sub("attn.in_proj_", "attn.v.", s): v.chunk(3, dim=0)[2], + } + return {s: v} + +if has_minicpmv_projector: + projector = torch.load(args.minicpmv_projector) + new_state_dict = {} + for k, v in projector.items(): + kvs = _replace_name_resampler(k, v) + for nk, nv in kvs.items(): + new_state_dict[nk] = nv + projector = new_state_dict + for name, data in projector.items(): + name = get_tensor_name(name) + data = data.squeeze().numpy() + + n_dims = len(data.shape) + if ftype == 1: + if name[-7:] == ".weight" and n_dims == 2: + print(" Converting to float16") + data = data.astype(np.float16) + ftype_cur = 1 + else: + print(" Converting to float32") + data = data.astype(np.float32) + ftype_cur = 0 + else: + if data.dtype != np.float32: + print(" Converting to float32") + data = data.astype(np.float32) + ftype_cur = 0 + + fout.add_tensor(name, data) + print(f"{name} - {ftype_str[ftype_cur]} - shape = {data.shape}") + + print("Projector tensors added\n") + +def _replace_name(s, v): + s = "vision_model." + s + if re.match("vision_model.embeddings.position_embedding", s): + v = v.unsqueeze(0) + return {s: v} + + return {s: v} + +state_dict = model.state_dict() +new_state_dict = {} +for k, v in state_dict.items(): + kvs = _replace_name(k, v) + for nk, nv in kvs.items(): + new_state_dict[nk] = nv +state_dict = new_state_dict +for name, data in state_dict.items(): + if should_skip_tensor(name, has_text_encoder, has_vision_encoder, has_minicpmv_projector): + # we don't need this + print(f"skipping parameter: {name}") + continue + + name = get_tensor_name(name) + data = data.squeeze().numpy() + + n_dims = len(data.shape) + + # ftype == 0 -> float32, ftype == 1 -> float16 + ftype_cur = 0 + if n_dims == 4: + print(f"tensor {name} is always saved in f16") + data = data.astype(np.float16) + ftype_cur = 1 + elif ftype == 1: + if name[-7:] == ".weight" and n_dims == 2: + print(" Converting to float16") + data = data.astype(np.float16) + ftype_cur = 1 + else: + print(" Converting to float32") + data = data.astype(np.float32) + ftype_cur = 0 + else: + if data.dtype != np.float32: + print(" Converting to float32") + data = data.astype(np.float32) + ftype_cur = 0 + + print(f"{name} - {ftype_str[ftype_cur]} - shape = {data.shape}") + fout.add_tensor(name, data) + + +fout.write_header_to_file() +fout.write_kv_data_to_file() +fout.write_tensors_to_file() +fout.close() + +print("Done. Output file: " + fname_out) diff --git a/examples/minicpmv/minicpmv-surgery.py b/examples/minicpmv/minicpmv-surgery.py new file mode 100644 index 0000000000000..51b4d48598440 --- /dev/null +++ b/examples/minicpmv/minicpmv-surgery.py @@ -0,0 +1,48 @@ +import argparse +import glob +import os +import torch +from transformers import AutoModel, AutoTokenizer + +ap = argparse.ArgumentParser() +ap.add_argument("-m", "--model", help="Path to MiniCPM-V-2.5 model") +args = ap.parse_args() + +# find the model part that includes the the multimodal projector weights +model = AutoModel.from_pretrained(args.model, trust_remote_code=True, local_files_only=True) +checkpoint = model.state_dict() + +# get a list of mm tensor names +mm_tensors = [k for k, v in checkpoint.items() if k.startswith("resampler")] + +# store these tensors in a new dictionary and torch.save them +projector = {name: checkpoint[name].float() for name in mm_tensors} +torch.save(projector, f"{args.model}/minicpmv.projector") + +clip_tensors = [k for k, v in checkpoint.items() if k.startswith("vpm")] +if len(clip_tensors) > 0: + clip = {name.replace("vpm.", ""): checkpoint[name].float() for name in clip_tensors} + torch.save(clip, f"{args.model}/minicpmv.clip") + + # added tokens should be removed to be able to convert Mistral models + if os.path.exists(f"{args.model}/added_tokens.json"): + with open(f"{args.model}/added_tokens.json", "w") as f: + f.write("{}\n") + +config = model.llm.config +config._name_or_path = "openbmb/MiniCPM-Llama3-V-2.5" +config.auto_map = { + "AutoConfig": "configuration_minicpm.MiniCPMConfig", + "AutoModel": "modeling_minicpm.MiniCPMModel", + "AutoModelForCausalLM": "modeling_minicpm.MiniCPMForCausalLM", + "AutoModelForSeq2SeqLM": "modeling_minicpm.MiniCPMForCausalLM", + "AutoModelForSequenceClassification": "modeling_minicpm.MiniCPMForSequenceClassification" +} +model.llm.save_pretrained(f"{args.model}/model") +tok = AutoTokenizer.from_pretrained(args.model, trust_remote_code=True) +tok.save_pretrained(f"{args.model}/model") +# os.system(f"cp {args.model}/modeling_minicpm.py {args.model}/MiniCPM_l3/modeling_minicpm.py") + +print("Done!") +print(f"Now you can convert {args.model} to a regular LLaMA GGUF file.") +print(f"Also, use {args.model}/minicpmv.projector to prepare a minicpmv-encoder.gguf file.") diff --git a/examples/minicpmv/minicpmv.cpp b/examples/minicpmv/minicpmv.cpp new file mode 100644 index 0000000000000..d0c17bd537249 --- /dev/null +++ b/examples/minicpmv/minicpmv.cpp @@ -0,0 +1,663 @@ +#include "clip.h" +#include "common.h" +#include "llama.h" +#include "minicpmv.h" +#include "base64.hpp" + +#include +#include +#include +#include + +// RGB uint8 image +struct clip_image_u8 { + int nx; + int ny; + + std::vector buf; +}; + +// RGB float32 image (NHWC) +// Memory layout: RGBRGBRGB... +struct clip_image_f32 { + int nx; + int ny; + + std::vector buf; +}; + +struct clip_image_grid_shape { + int first; + int second; +}; + +/** + * Selects the best resolution from a list of possible resolutions based on the original size. + * + * @param original_size The original size of the image in the format (width, height). + * @param possible_resolutions A list of possible resolutions in the format [(width1, height1), (width2, height2), ...]. + * @return The best fit resolution in the format (width, height). + */ +static std::pair select_best_resolution(const std::pair& original_size, const std::vector>& possible_resolutions) { + int original_width = original_size.first; + int original_height = original_size.second; + + std::pair best_fit; + int max_effective_resolution = 0; + int min_wasted_resolution = std::numeric_limits::max(); + + for (const auto& resolution : possible_resolutions) { + int width = resolution.first; + int height = resolution.second; + float scale = std::min(static_cast(width) / original_width, static_cast(height) / original_height); + int downscaled_width = static_cast(original_width * scale); + int downscaled_height = static_cast(original_height * scale); + int effective_resolution = std::min(downscaled_width * downscaled_height, original_width * original_height); + int wasted_resolution = (width * height) - effective_resolution; + // LOG_TEE("resolution: %d %d, scale: %f, downscaled: %d %d, effective: %d, wasted: %d\n", width, height, scale, downscaled_width, downscaled_height, effective_resolution, wasted_resolution); + if (effective_resolution > max_effective_resolution || (effective_resolution == max_effective_resolution && wasted_resolution < min_wasted_resolution)) { + max_effective_resolution = effective_resolution; + min_wasted_resolution = wasted_resolution; + best_fit = resolution; + } + } + + return best_fit; +} + +/** + * @brief Get the anyres image grid shape object + * + * @param image_size + * @param grid_pinpoints + * @param image_patch_size + * @return + */ +static struct clip_image_grid_shape get_anyres_image_grid_shape(const std::pair & image_size, const std::vector> & grid_pinpoints, int image_patch_size) { + /** + Conversion from gguf flat array to vector: + std::vector> possible_resolutions; + for (int i = 0; i < 32 && params.image_grid_pinpoints[i] != 0; i+=2) { + possible_resolutions.push_back({params.image_grid_pinpoints[i], params.image_grid_pinpoints[i+1]}); + } + */ + auto best_resolution = select_best_resolution(image_size, grid_pinpoints); + return {best_resolution.first / image_patch_size, best_resolution.second / image_patch_size}; +} + +// Take the image segments in a grid configuration and return the embeddings and the number of embeddings into preallocated memory (image_embd_out) +static bool clip_llava_handle_patches(clip_ctx * ctx_clip, std::vector & image_embd_v, struct clip_image_grid_shape grid_shape, float * image_embd_out, int * n_img_pos_out) { + struct { + struct ggml_tensor * newline; + struct ggml_context * ctx; + } model; + + const int32_t image_size = clip_image_size(ctx_clip); + const int32_t patch_size = clip_patch_size(ctx_clip); + + int32_t num_patches_per_side = image_size / patch_size; // 336 / 14 = 24 - used for embedding-patching boxes (24*24 = 576 patches) + + int num_patches_width = grid_shape.first; // grid 1-4 + int num_patches_height = grid_shape.second; // grid 1-4 + + const size_t num_images = num_patches_width * num_patches_height + 1; + + // TODO: size calculation is not calculated - it's only tens of MB + size_t ctx_size = 0; + + { + ctx_size += clip_embd_nbytes(ctx_clip) * num_images * 8; // image_features + ctx_size += 1024*1024 * ggml_type_size(GGML_TYPE_F32); + } + + struct ggml_init_params params { + /*.mem_size =*/ ctx_size, + /*.mem_buffer =*/ NULL, + /*.no_alloc =*/ false, // NOTE: this should be false when using the legacy API + }; + + // Python reference code for full unpad: + /* + base_image_feature = image_feature[0] + image_feature = image_feature[1:] + image_feature = image_feature.permute(4, 0, 2, 1, 3).contiguous() + image_feature = image_feature.flatten(1, 2).flatten(2, 3) + image_feature = unpad_image(image_feature, image_sizes[image_idx]) + image_feature = torch.cat(( + image_feature, + self.model.image_newline[:, None, None].expand(*image_feature.shape[:-1], 1) + ), dim=-1) + image_feature = image_feature.flatten(1, 2).transpose(0, 1) + image_feature = torch.cat((base_image_feature, image_feature), dim=0) + */ + // We now have two options: unpad or no unpad. Unpad removes tokens for faster llm eval. + // In terms of result quality it appears to make no difference, so we'll start with the easier approach given 5D tensors are not supported in ggml yet. + // Without unpad we have to split the sub-image embeddings into patches of 24 features each and permute them. + // Once all images are processed to prepended the base_image_features without any changes. + + // Pytorch reference simplified, modified for ggml compatibility - confirmed identical output in python (for a 2x2 grid image (676x676 scaling)) + /* + image_feature = image_feature.view(2, 2, 24, 24, 4096) + image_feature = image_feature.permute(0, 2, 1, 3, 4).contiguous() + image_feature = image_feature.view(2, 24, 2, 24, 4096) + image_feature = image_feature.flatten(0, 3) + + // Reshape to 4D tensor by merging the last two dimensions + image_feature = image_feature.view(2, 2, 24, 24*4096) + image_feature = image_feature.permute(0, 2, 1, 3).contiguous() + image_feature = image_feature.view(-1, 4096) + */ + + model.ctx = ggml_init(params); + + ggml_tensor * newline_tmp = clip_get_newline_tensor(ctx_clip); + model.newline = ggml_new_tensor_1d(model.ctx, GGML_TYPE_F32, newline_tmp->ne[0]); + if (newline_tmp->backend != GGML_BACKEND_TYPE_CPU) { + if (newline_tmp->buffer == NULL) { + LOG_TEE("newline_tmp tensor buffer is NULL\n"); + } + ggml_backend_tensor_get(newline_tmp, model.newline->data, 0, ggml_nbytes(newline_tmp)); + } else { + model.newline->data = newline_tmp->data; + if (model.newline->data == NULL) { + LOG_TEE("newline_tmp tensor data is NULL\n"); + } + } + + struct ggml_tensor * image_features = ggml_new_tensor_3d(model.ctx, GGML_TYPE_F32, clip_n_mmproj_embd(ctx_clip), clip_n_patches(ctx_clip), num_images - 1); // example: 4096 x 576 x 4 + // ggml_tensor_printf(image_features,"image_features",__LINE__,false,false); + // fill it with the image embeddings, ignoring the base + for (size_t i = 1; i < num_images; i++) { + size_t offset = (i-1) * clip_embd_nbytes(ctx_clip); + memcpy((uint8_t *)(image_features->data) + offset, image_embd_v[i], clip_embd_nbytes(ctx_clip)); + } + + struct ggml_cgraph * gf = ggml_new_graph(model.ctx); + size_t size_ele = ggml_type_size(GGML_TYPE_F32); + + struct ggml_tensor *image_features_patchview = ggml_view_4d(model.ctx, image_features, + num_patches_per_side * clip_n_mmproj_embd(ctx_clip), + num_patches_per_side, + num_patches_width, + num_patches_height, + size_ele * num_patches_per_side * clip_n_mmproj_embd(ctx_clip), + size_ele * num_patches_per_side * clip_n_mmproj_embd(ctx_clip) * num_patches_per_side, + size_ele * num_patches_per_side * clip_n_mmproj_embd(ctx_clip) * num_patches_per_side * num_patches_width, 0); + // ggml_tensor_printf(image_features_patchview,"image_features_patchview",__LINE__,false,false); + struct ggml_tensor *permuted_cont = ggml_cont(model.ctx, ggml_permute(model.ctx, image_features_patchview, 0, 2, 1, 3)); + /** + At the end of each row we have to add the row_end embeddings, which are the same as the newline embeddings + image_feature = torch.cat(( + image_feature, + self.model.image_newline[:, None, None].expand(*image_feature.shape[:-1], 1).to(image_feature.device) + ), dim=-1) + * + */ + + // ggml_tensor_printf(permuted_cont,"permuted_cont",__LINE__,false,false); + struct ggml_tensor *flatten = ggml_view_2d(model.ctx, permuted_cont, clip_n_mmproj_embd(ctx_clip), num_patches_height * num_patches_width * num_patches_per_side * num_patches_per_side, size_ele * clip_n_mmproj_embd(ctx_clip), 0); + // ggml_tensor_printf(flatten,"flatten",__LINE__,false,false); + ggml_build_forward_expand(gf, flatten); + ggml_graph_compute_with_ctx(model.ctx, gf, 1); + struct ggml_tensor* result = gf->nodes[gf->n_nodes - 1]; + + memcpy(image_embd_out, image_embd_v[0], clip_embd_nbytes(ctx_clip)); // main image as global context + // append without newline tokens (default behavior in llava_arch when not using unpad ): + memcpy(image_embd_out + clip_n_patches(ctx_clip) * clip_n_mmproj_embd(ctx_clip), (float*)result->data, clip_embd_nbytes(ctx_clip) * (num_images-1)); // grid patches + *n_img_pos_out = static_cast(result->ne[1]+clip_n_patches(ctx_clip)); + + // Debug: Test single segments + // Current findings: sending base image, sending a segment embedding all works similar to python + // However, permuted embeddings do not work yet (stride issue?) + // memcpy(image_embd_out, image_embd_v[0], clip_embd_nbytes(ctx_clip)); // main image as context + // memcpy(image_embd_out, (float*)prepared_cont->data, clip_embd_nbytes(ctx_clip)); // main image as context + // *n_img_pos_out=576; + + ggml_free(model.ctx); + return true; +} + + +static bool encode_image_with_clip(clip_ctx * ctx_clip, int n_threads, const clip_image_u8 * img, float * image_embd, int * n_img_pos) { + // std::vector img_res_v; // format VectN x H x W x RGB (N x 336 x 336 x 3), so interleaved RGB - different to the python implementation which is N x 3 x 336 x 336 + clip_image_f32_batch img_res_v; + img_res_v.size = 0; + img_res_v.data = nullptr; + std::pair load_image_size; + load_image_size.first = img->nx; + load_image_size.second = img->ny; + const int64_t t_img_enc_start_us_ip = ggml_time_us(); + if (!clip_image_preprocess(ctx_clip, img, &img_res_v)) { + LOG_TEE("%s: unable to preprocess image\n", __func__); + delete[] img_res_v.data; + return false; + } + + const int64_t t_img_enc_end_us_ip = ggml_time_us(); + float t_img_enc_ms_ip = (t_img_enc_end_us_ip - t_img_enc_start_us_ip) / 1000.0; + + LOG_TEE("\n%s: image encoded in %8.2f ms by clip_image_preprocess.\n", __func__, t_img_enc_ms_ip); + + const int64_t t_img_enc_start_us = ggml_time_us(); + + const char * mm_patch_merge_type = clip_patch_merge_type(ctx_clip); + + LOG_TEE("\n%s: mm_patch_merge_type is %s.\n", __func__, mm_patch_merge_type); + if (strcmp(mm_patch_merge_type, "spatial_unpad") != 0) { + // flat / default llava-1.5 type embedding + *n_img_pos = clip_n_patches(ctx_clip); + + bool encoded = clip_image_encode(ctx_clip, n_threads, &img_res_v.data[0], image_embd, load_image_size); // image_embd shape is 576 x 4096 + delete[] img_res_v.data; + if (!encoded) { + LOG_TEE("Unable to encode image\n"); + + return false; + } + } else { + // spatial_unpad llava-1.6 type embedding + // TODO: CLIP needs batching support - in HF the llm projection is separate after encoding, which might be a solution to quickly get batching working + std::vector image_embd_v; + image_embd_v.resize(img_res_v.size); + for (size_t i = 0; i < img_res_v.size; i++) { + image_embd_v[i] = (float *)malloc(clip_embd_nbytes(ctx_clip)); // 576 patches * 4096 embeddings * 4 bytes = 9437184 + const bool encoded = clip_image_encode(ctx_clip, n_threads, &img_res_v.data[i], image_embd_v[i], load_image_size); // image data is in 3x336x336 format and will be converted to 336x336x3 inside + if (!encoded) { + LOG_TEE("Unable to encode image - spatial_unpad - subimage %d of %d\n", (int) i+1, (int) img_res_v.size); + return false; + } + } + const int64_t t_img_enc_batch_us = ggml_time_us(); + LOG_TEE("%s: %d segments encoded in %8.2f ms\n", __func__, (int)img_res_v.size, (t_img_enc_batch_us - t_img_enc_start_us) / 1000.0); + + const int32_t * image_grid = clip_image_grid(ctx_clip); + + std::vector> grid_pinpoints; + for (int i = 0; i < 32 && image_grid[i] != 0; i += 2) { + grid_pinpoints.push_back({image_grid[i], image_grid[i+1]}); + } + + // free all img_res_v - not needed anymore + delete[] img_res_v.data; + img_res_v.size = 0; + img_res_v.data = nullptr; + + const int32_t image_size = clip_image_size(ctx_clip); + + struct clip_image_grid_shape grid_shape = get_anyres_image_grid_shape({img->nx,img->ny}, grid_pinpoints, image_size); + + int n_img_pos_out; + clip_llava_handle_patches(ctx_clip, image_embd_v, grid_shape, image_embd, &n_img_pos_out); + *n_img_pos = n_img_pos_out; + + for (size_t i = 0; i < image_embd_v.size(); i++) { + free(image_embd_v[i]); + } + image_embd_v.clear(); + + // debug image/segment/normalization content: + // clip_image_u8 * tmp = clip_image_u8_init(); + // clip_image_convert_f32_to_u8(*image_feature, *tmp); + // clip_image_save_to_bmp(*tmp, "image_feature.bmp"); + } + + LOG_TEE("%s: image embedding created: %d tokens\n", __func__, *n_img_pos); + + const int64_t t_img_enc_end_us = ggml_time_us(); + float t_img_enc_ms = (t_img_enc_end_us - t_img_enc_start_us) / 1000.0; + + LOG_TEE("\n%s: image encoded in %8.2f ms by CLIP (%8.2f ms per image patch)\n", __func__, t_img_enc_ms, t_img_enc_ms / *n_img_pos); + + return true; +} + +bool llava_validate_embed_size(const llama_context * ctx_llama, const clip_ctx * ctx_clip) { + // make sure that the correct mmproj was used, i.e., compare apples to apples + int n_llama_embd = llama_n_embd(llama_get_model(ctx_llama)); + auto n_image_embd = clip_n_mmproj_embd(ctx_clip); + if (n_image_embd != n_llama_embd) { + LOG_TEE("%s: embedding dim of the multimodal projector (%d) is not equal to that of LLaMA (%d). Make sure that you use the correct mmproj file.\n", __func__, n_image_embd, n_llama_embd); + return false; + } + return true; +} + +bool llava_image_embed_make_with_clip_img(clip_ctx * ctx_clip, int n_threads, const clip_image_u8 * img, float ** image_embd_out, int * n_img_pos_out) { + float * image_embd = (float *)malloc(clip_embd_nbytes(ctx_clip)*6); // TODO: base on gridsize/llava model + if (!image_embd) { + LOG_TEE("Unable to allocate memory for image embeddings\n"); + return false; + } + + int n_img_pos; + if (!encode_image_with_clip(ctx_clip, n_threads, img, image_embd, &n_img_pos)) { + LOG_TEE("%s: cannot encode image, aborting\n", __func__); + free(image_embd); + return false; + } + *image_embd_out = image_embd; + *n_img_pos_out = n_img_pos; + + return true; +} + +bool llava_eval_image_embed(llama_context * ctx_llama, const struct llava_image_embed * image_embed, int n_batch, int * n_past) { + int n_embd = llama_n_embd(llama_get_model(ctx_llama)); + + for (int i = 0; i < image_embed->n_image_pos; i += n_batch) { + int n_eval = image_embed->n_image_pos - i; + if (n_eval > n_batch) { + n_eval = n_batch; + } + llama_batch batch = {int32_t(n_eval), nullptr, (image_embed->embed+i*n_embd), nullptr, nullptr, nullptr, nullptr, *n_past, 1, 0, }; + if (llama_decode(ctx_llama, batch)) { + LOG_TEE("%s : failed to eval\n", __func__); + return false; + } + *n_past += n_eval; + } + return true; +} + +int ensure_divide(int length, int patch_size) { + return std::max(static_cast(std::round(static_cast(length) / patch_size) * patch_size), patch_size); +} + +std::pair find_best_resize(std::pair original_size, int scale_resolution, int patch_size, bool allow_upscale = false) { + int width = original_size.first; + int height = original_size.second; + if ((width * height > scale_resolution * scale_resolution) || allow_upscale) { + float r = static_cast(width) / height; + height = static_cast(scale_resolution / std::sqrt(r)); + width = static_cast(height * r); + } + int best_width = ensure_divide(width, patch_size); + int best_height = ensure_divide(height, patch_size); + return std::make_pair(best_width, best_height); +} + +inline float clip(float x, float lower, float upper) { + return std::max(lower, std::min(x, upper)); +} + +std::pair get_refine_size(std::pair original_size, std::pair grid, int scale_resolution, int patch_size, bool allow_upscale = false) { + int width, height; + std::tie(width, height) = original_size; + int grid_x, grid_y; + std::tie(grid_x, grid_y) = grid; + + int refine_width = ensure_divide(width, grid_x); + int refine_height = ensure_divide(height, grid_y); + + int grid_width = refine_width / grid_x; + int grid_height = refine_height / grid_y; + + auto best_grid_size = find_best_resize(std::make_tuple(grid_width, grid_height), scale_resolution, patch_size, allow_upscale); + + int best_grid_width, best_grid_height; + std::tie(best_grid_width, best_grid_height) = best_grid_size; + + std::pair refine_size = std::make_tuple(best_grid_width * grid_x, best_grid_height * grid_y); + + return refine_size; +} + +static bool bicubic_resize(const clip_image_u8 &img, clip_image_u8 &dst, int target_width, int target_height) { + const int nx = img.nx; + const int ny = img.ny; + + dst.nx = target_width; + dst.ny = target_height; + dst.buf.resize(3 * target_width * target_height); + + float Cc; + float C[5]; + float d0, d2, d3, a0, a1, a2, a3; + int i, j, k, jj; + int x, y; + float dx, dy; + float tx, ty; + + tx = (float)nx / (float)target_width; + ty = (float)ny / (float)target_height; + + // Bicubic interpolation; adapted from ViT.cpp, inspired from : + // -> https://github.com/yglukhov/bicubic-interpolation-image-processing/blob/master/libimage.c#L36 + // -> https://en.wikipedia.org/wiki/Bicubic_interpolation + + for (i = 0; i < target_height; i++) { + for (j = 0; j < target_width; j++) { + x = (int)(tx * j); + y = (int)(ty * i); + + dx = tx * j - x; + dy = ty * i - y; + + for (k = 0; k < 3; k++) { + for (jj = 0; jj <= 3; jj++) { + d0 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x - 1, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + d2 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x + 1, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + d3 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x + 2, 0, nx - 1)) * 3 + k] - img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + a0 = img.buf[(clip(y - 1 + jj, 0, ny - 1) * nx + clip(x, 0, nx - 1)) * 3 + k]; + + a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; + a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + + C[jj] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx; + + d0 = C[0] - C[1]; + d2 = C[2] - C[1]; + d3 = C[3] - C[1]; + a0 = C[1]; + a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; + a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + Cc = a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy; + + const uint8_t Cc2 = std::min(std::max(std::round(Cc), 0.0f), 255.0f); + dst.buf[(i * target_width + j) * 3 + k] = float(Cc2); + } + } + } + } + + return true; +} + +std::vector> slice_image(const clip_image_u8 * img, const int max_slice_nums=9, const int scale_resolution=448, const int patch_size=14, const bool never_split=false) { + const std::pair original_size={img->nx,img->ny}; + const int original_width = img->nx; + const int original_height = img->ny; + const float log_ratio = log(1.0*original_width/original_height); // + const float ratio = 1.0 * original_width * original_height/ (scale_resolution * scale_resolution); + const int multiple = fmin(ceil(ratio), max_slice_nums); + + std::vector> images; + LOG_TEE("%s: multiple %d\n", __func__, multiple); + images.push_back(std::vector()); + + if(multiple <= 1){ + // auto best_resolution = select_best_resolution(image_size, grid_pinpoints); + // clip_image_u8 *image_original_resize = clip_image_u8_init(); + // bicubic_resize(*img, *image_original_resize, best_resolution.first, best_resolution.second); + + auto best_size = find_best_resize(original_size, scale_resolution, patch_size, true); + clip_image_u8 *source_image = clip_image_u8_init(); + bicubic_resize(*img, *source_image, best_size.first, best_size.second); + // source_image = image.resize(best_size, Image.Resampling.BICUBIC) + images[images.size()-1].push_back(source_image); + } + else if(multiple > 1){ + + std::vector candidate_split_grids_nums; + for (int i : {multiple - 1, multiple, multiple + 1}) { + if (i == 1 || i > max_slice_nums) { + continue; + } + candidate_split_grids_nums.push_back(i); + } + + auto best_size = find_best_resize(original_size, scale_resolution, patch_size); + clip_image_u8 *source_image = clip_image_u8_init(); + bicubic_resize(*img, *source_image, best_size.first, best_size.second); + // source_image = image.copy().resize(best_resize, Image.Resampling.BICUBIC) + images[images.size()-1].push_back(source_image); + + std::vector> candidate_grids; + + for (int split_grids_nums : candidate_split_grids_nums) { + int m = 1; + while (m <= split_grids_nums) { + if (split_grids_nums % m == 0) { + candidate_grids.emplace_back(m, split_grids_nums / m); + } + ++m; + } + } + + std::pair best_grid{1, 1}; + float min_error = std::numeric_limits::infinity(); + + for (const auto& grid : candidate_grids) { + float error = std::abs(log_ratio - std::log(1.0 * grid.first / grid.second)); + if (error < min_error) { + best_grid = grid; + min_error = error; + } + } + LOG_TEE("%s: image_size: %d %d; best_grid: %d %d\n", __func__, img->nx, img->ny, best_grid.first, best_grid.second); + + auto refine_size = get_refine_size(original_size, best_grid, scale_resolution, patch_size, true); + clip_image_u8 *refine_image = clip_image_u8_init(); + bicubic_resize(*img, *refine_image, refine_size.first, refine_size.second); + + LOG_TEE("%s: refine_image_size: %d %d; best_grid: %d %d\n", __func__, refine_image->nx, refine_image->ny, best_grid.first, best_grid.second); + + // split_to_patches + int width = refine_image->nx; + int height = refine_image->ny; + int grid_x = int(width / best_grid.first); + int grid_y = int(height / best_grid.second); + for (int patches_i = 0, ic = 0; patches_i < height && ic < best_grid.second; patches_i += grid_y, ic += 1){ + images.push_back(std::vector()); + for(int patches_j = 0, jc = 0; patches_j < width && jc < best_grid.first; patches_j += grid_x, jc += 1){ + clip_image_u8 * patch = clip_image_u8_init(); + patch->nx = grid_x; + patch->ny = grid_y; + patch->buf.resize(3 * patch->nx * patch->ny); + for (int y = patches_i; y < patches_i + grid_y; ++y) { + for (int x = patches_j; x < patches_j + grid_x; ++x) { + const int i = 3 * (y * refine_image->nx + x); + const int j = 3 * ((y-patches_i) * patch->nx + (x-patches_j)); + patch->buf[j] = refine_image->buf[i]; + patch->buf[j+1] = refine_image->buf[i+1]; + patch->buf[j+2] = refine_image->buf[i+2]; + } + } + images[images.size()-1].push_back(patch); + } + } + + + } + + return images; +} + + +std::vector> llava_image_embed_make_with_bytes_slice(struct clip_ctx * ctx_clip, int n_threads, const unsigned char * image_bytes, int image_bytes_length) { + clip_image_u8 * img = clip_image_u8_init(); + if (!clip_image_load_from_bytes(image_bytes, image_bytes_length, img)) { + clip_image_u8_free(img); + LOG_TEE("%s: can't load image from bytes, is it a valid image?", __func__); + return std::vector>(); + } + std::vector> imgs = slice_image(img); + for (size_t i = 0; i < imgs.size(); ++i){ + for (size_t j = 0; j < imgs[i].size(); ++j) { + LOG_TEE("%s: %d %d\n", __func__,imgs[i][j]->nx,imgs[i][j]->ny); + } + } + std::vector> results; + + for (size_t i = 0; i < imgs.size(); ++i){ + results.push_back(std::vector()); + for (size_t j = 0; j < imgs[i].size(); ++j) { + float* image_embed = NULL; + int n_image_pos = 0; + bool image_embed_result = llava_image_embed_make_with_clip_img(ctx_clip, n_threads, imgs[i][j], &image_embed, &n_image_pos); + if (!image_embed_result) { + clip_image_u8_free(img); + LOG_TEE("%s: coulnd't embed the image\n", __func__); + return std::vector>(); + } + + auto result = (llava_image_embed*)malloc(sizeof(llava_image_embed)); + result->embed = image_embed; + result->n_image_pos = n_image_pos; + results[i].push_back(result); + } + } + clip_image_u8_free(img); + return results; +} + + +static bool load_file_to_bytes(const char* path, unsigned char** bytesOut, long *sizeOut) { + auto file = fopen(path, "rb"); + if (file == NULL) { + LOG_TEE("%s: can't read file %s\n", __func__, path); + return false; + } + + fseek(file, 0, SEEK_END); + auto fileSize = ftell(file); + fseek(file, 0, SEEK_SET); + + auto buffer = (unsigned char *)malloc(fileSize); // Allocate memory to hold the file data + if (buffer == NULL) { + LOG_TEE("%s: failed to alloc %ld bytes for file %s\n", __func__, fileSize, path); + perror("Memory allocation error"); + fclose(file); + return false; + } + errno = 0; + size_t ret = fread(buffer, 1, fileSize, file); // Read the file into the buffer + if (ferror(file)) { + die_fmt("read error: %s", strerror(errno)); + } + if (ret != (size_t) fileSize) { + die("unexpectedly reached end of file"); + } + fclose(file); // Close the file + + *bytesOut = buffer; + *sizeOut = fileSize; + return true; +} + +std::vector> llava_image_embed_make_with_filename_slice(struct clip_ctx * ctx_clip, int n_threads, const char * image_path) { + unsigned char* image_bytes; + long image_bytes_length; + auto loaded = load_file_to_bytes(image_path, &image_bytes, &image_bytes_length); + if (!loaded) { + LOG_TEE("%s: failed to load %s\n", __func__, image_path); + return std::vector>(); + } + + std::vector> embeds = llava_image_embed_make_with_bytes_slice(ctx_clip, n_threads, image_bytes, image_bytes_length); + free(image_bytes); + return embeds; +} + +void llava_image_embed_free_slice(std::vector> embed) { + for (size_t i = 0; i < embed.size(); ++i){ + for (size_t j = 0; j < embed[i].size(); ++j){ + free(embed[i][j]->embed); + free(embed[i][j]); + } + embed[i] = std::vector(); + } + embed = std::vector>(); +} \ No newline at end of file diff --git a/examples/minicpmv/minicpmv.h b/examples/minicpmv/minicpmv.h new file mode 100644 index 0000000000000..3a1a9b6e6f533 --- /dev/null +++ b/examples/minicpmv/minicpmv.h @@ -0,0 +1,50 @@ +#ifndef LLAVA_H +#define LLAVA_H + +#include "ggml.h" + +#ifdef LLAMA_SHARED +# if defined(_WIN32) && !defined(__MINGW32__) +# ifdef LLAMA_BUILD +# define MINICPMV_API __declspec(dllexport) +# else +# define MINICPMV_API __declspec(dllimport) +# endif +# else +# define MINICPMV_API __attribute__ ((visibility ("default"))) +# endif +#else +# define MINICPMV_API +#endif + +struct clip_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +struct llava_image_embed { + float * embed; + int n_image_pos; +}; + +/** sanity check for clip <-> llava embed size match */ +MINICPMV_API bool llava_validate_embed_size(const struct llama_context * ctx_llama, const struct clip_ctx * ctx_clip); + +MINICPMV_API bool llava_image_embed_make_with_clip_img(struct clip_ctx * ctx_clip, int n_threads, const struct clip_image_u8 * img, float ** image_embd_out, int * n_img_pos_out); + +/** build an image embed from image file bytes */ +MINICPMV_API std::vector> llava_image_embed_make_with_bytes_slice(struct clip_ctx * ctx_clip, int n_threads, const unsigned char * image_bytes, int image_bytes_length); +/** build an image embed from a path to an image filename */ +MINICPMV_API std::vector> llava_image_embed_make_with_filename_slice(struct clip_ctx * ctx_clip, int n_threads, const char * image_path); +MINICPMV_API void llava_image_embed_free_slice(std::vector> embed); +/** free an embedding made with llava_image_embed_make_* */ + +/** write the image represented by embed into the llama context with batch size n_batch, starting at context pos n_past. on completion, n_past points to the next position in the context after the image embed. */ +MINICPMV_API bool llava_eval_image_embed(struct llama_context * ctx_llama, const struct llava_image_embed * embed, int n_batch, int * n_past); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/minicpmv/minicpmv_io.cpp b/examples/minicpmv/minicpmv_io.cpp new file mode 100644 index 0000000000000..451157fdb18c0 --- /dev/null +++ b/examples/minicpmv/minicpmv_io.cpp @@ -0,0 +1,153 @@ +#include "ggml.h" +#include "common.h" +#include "clip.h" +#include "minicpmv.h" +#include "minicpmv_io.h" +#include "llama.h" +#include +#include +#include + +struct llama_model * llava_init(gpt_params * params) { + llama_backend_init(); + llama_numa_init(params->numa); + + llama_model_params model_params = llama_model_params_from_gpt_params(*params); + + llama_model * model = llama_load_model_from_file(params->model.c_str(), model_params); + if (model == NULL) { + LOG_TEE("%s: error: unable to load model\n" , __func__); + return NULL; + } + return model; +} + +struct minicpmv_context * llava_init_context(gpt_params * params, llama_model * model) { + const char * clip_path = params->mmproj.c_str(); + + auto prompt = params->prompt; + if (prompt.empty()) { + prompt = "describe the image in detail."; + } + + llama_context_params ctx_params = llama_context_params_from_gpt_params(*params); + ctx_params.n_ctx = params->n_ctx < 2048 ? 2048 : params->n_ctx; // we need a longer context size to process image embeddings + + llama_context * ctx_llama = llama_new_context_with_model(model, ctx_params); + + if (ctx_llama == NULL) { + LOG_TEE("%s: error: failed to create the llama_context\n" , __func__); + return NULL; + } + + auto ctx_llava = (struct minicpmv_context *)malloc(sizeof(minicpmv_context)); + + ctx_llava->ctx_llama = ctx_llama; + ctx_llava->model = model; + return ctx_llava; +} + +void llava_free(struct minicpmv_context * ctx_llava) { + llama_free(ctx_llava->ctx_llama); + llama_free_model(ctx_llava->model); + llama_backend_free(); +} + +struct clip_ctx * clip_init_context(gpt_params * params) { + const char * clip_path = params->mmproj.c_str(); + + auto prompt = params->prompt; + if (prompt.empty()) { + prompt = "describe the image in detail."; + } + std::pair load_image_size = std::make_pair(70, 70); + auto ctx_clip = clip_model_load(clip_path, /*verbosity=*/ 1, load_image_size); + return ctx_clip; +} + +std::vector> minicpmv_image_embed(gpt_params * params, const std::string & fname){ + auto ctx_clip = clip_init_context(params); + auto image_embed_and_slices = llava_image_embed_make_with_filename_slice(ctx_clip, params->n_threads, fname.c_str()); + if (ctx_clip) { + clip_free(ctx_clip); + ctx_clip = NULL; + } + return image_embed_and_slices; +} + + +bool eval_tokens(struct llama_context * ctx_llama, std::vector tokens, int n_batch, int * n_past) { + int N = (int) tokens.size(); + for (int i = 0; i < N; i += n_batch) { + int n_eval = (int) tokens.size() - i; + if (n_eval > n_batch) { + n_eval = n_batch; + } + if (llama_decode(ctx_llama, llama_batch_get_one(&tokens[i], n_eval, *n_past, 0))) { + LOG_TEE("%s : failed to eval. token %d/%d (batch size %d, n_past %d)\n", __func__, i, N, n_batch, *n_past); + return false; + } + *n_past += n_eval; + } + return true; +} + +bool eval_id(struct llama_context * ctx_llama, int id, int * n_past) { + std::vector tokens; + tokens.push_back(id); + return eval_tokens(ctx_llama, tokens, 1, n_past); +} + +bool eval_string(struct llama_context * ctx_llama, const char* str, int n_batch, int * n_past, bool add_bos){ + std::string str2 = str; + std::vector embd_inp = ::llama_tokenize(ctx_llama, str2, add_bos, true); + eval_tokens(ctx_llama, embd_inp, n_batch, n_past); + return true; +} + +void process_image(struct minicpmv_context * ctx_llava, std::vector> image_embed_slices, gpt_params * params, int &n_past) { + std::string system_prompt; + + system_prompt = "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n"; + LOG_TEE("%s: image token past: %d\n", __func__, n_past); + eval_string(ctx_llava->ctx_llama, (system_prompt+"").c_str(), params->n_batch, &n_past, true); + llava_eval_image_embed(ctx_llava->ctx_llama, image_embed_slices[0][0], params->n_batch, &n_past); + if (image_embed_slices.size() > 1) { + eval_string(ctx_llava->ctx_llama, std::string("").c_str(), params->n_batch, &n_past, false); + for (size_t i = 1; i < image_embed_slices.size(); ++i) { + eval_string(ctx_llava->ctx_llama, std::string("").c_str(), params->n_batch, &n_past, false); + for (size_t j = 0; j < image_embed_slices[i].size(); ++j) { + llava_eval_image_embed(ctx_llava->ctx_llama, image_embed_slices[i][j], params->n_batch, &n_past); + if (j != image_embed_slices[i].size() - 1) { + eval_string(ctx_llava->ctx_llama, std::string("").c_str(), params->n_batch, &n_past, false); + } else { + if (i != image_embed_slices.size() - 1) { + eval_string(ctx_llava->ctx_llama, std::string("\n").c_str(), params->n_batch, &n_past, false); + } else { + eval_string(ctx_llava->ctx_llama, std::string("").c_str(), params->n_batch, &n_past, false); + } + } + } + } + eval_string(ctx_llava->ctx_llama, std::string("\n").c_str(), params->n_batch, &n_past, false); + + } else { + eval_string(ctx_llava->ctx_llama, std::string("\n").c_str(), params->n_batch, &n_past, false); + } + LOG_TEE("%s: image token past: %d\n", __func__, n_past); +} + +const char * sample(struct llama_sampling_context * ctx_sampling, + struct llama_context * ctx_llama, + int * n_past) { + const llama_token id = llama_sampling_sample(ctx_sampling, ctx_llama, NULL); + llama_sampling_accept(ctx_sampling, ctx_llama, id, true); + static std::string ret; + if (llama_token_is_eog(llama_get_model(ctx_llama), id)) { + ret = ""; + } else { + ret = llama_token_to_piece(ctx_llama, id); + } + eval_id(ctx_llama, id, n_past); + return ret.c_str(); +} \ No newline at end of file diff --git a/examples/minicpmv/minicpmv_io.h b/examples/minicpmv/minicpmv_io.h new file mode 100644 index 0000000000000..b3631ed160391 --- /dev/null +++ b/examples/minicpmv/minicpmv_io.h @@ -0,0 +1,49 @@ +#ifndef MINICPMV_H +#define MINICPMV_H + +#include "common.h" +#include "clip.h" +#include "minicpmv.h" +#include "llama.h" + +#ifdef LLAMA_SHARED +# if defined(_WIN32) && !defined(__MINGW32__) +# ifdef LLAMA_BUILD +# define MINICPMV_API __declspec(dllexport) +# else +# define MINICPMV_API __declspec(dllimport) +# endif +# else +# define MINICPMV_API __attribute__ ((visibility ("default"))) +# endif +#else +# define MINICPMV_API +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct minicpmv_context { + struct llama_context * ctx_llama = NULL; + struct llama_model * model = NULL; +}; + +MINICPMV_API struct llama_model * llava_init(gpt_params * params); +MINICPMV_API struct minicpmv_context * llava_init_context(gpt_params * params, llama_model * model); +MINICPMV_API void llava_free(struct minicpmv_context * ctx_llava); + +MINICPMV_API struct clip_ctx * clip_init_context(gpt_params * params); +MINICPMV_API std::vector> minicpmv_image_embed(gpt_params * params, const std::string & fname); + +MINICPMV_API bool eval_tokens(struct llama_context * ctx_llama, std::vector tokens, int n_batch, int * n_past); +MINICPMV_API bool eval_id(struct llama_context * ctx_llama, int id, int * n_past); +MINICPMV_API bool eval_string(struct llama_context * ctx_llama, const char* str, int n_batch, int * n_past, bool add_bos); +MINICPMV_API void process_image(struct minicpmv_context * ctx_llava, std::vector> image_embed_slices, gpt_params * params, int &n_past); +MINICPMV_API const char * sample(struct llama_sampling_context * ctx_sampling, struct llama_context * ctx_llama, int * n_past); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/examples/minicpmv/requirements.txt b/examples/minicpmv/requirements.txt new file mode 100644 index 0000000000000..f80f727a79307 --- /dev/null +++ b/examples/minicpmv/requirements.txt @@ -0,0 +1,3 @@ +-r ../../requirements/requirements-convert.txt +pillow~=10.2.0 +torch~=2.1.1 diff --git a/gguf-py/gguf/constants.py b/gguf-py/gguf/constants.py index 67e23dcc14840..57d0abef53f1f 100644 --- a/gguf-py/gguf/constants.py +++ b/gguf-py/gguf/constants.py @@ -620,6 +620,7 @@ class MODEL_TENSOR(IntEnum): ], MODEL_ARCH.MINICPM: [ MODEL_TENSOR.TOKEN_EMBD, + MODEL_TENSOR.OUTPUT, MODEL_TENSOR.OUTPUT_NORM, MODEL_TENSOR.ROPE_FREQS, MODEL_TENSOR.ATTN_NORM, diff --git a/llama.cpp b/llama.cpp index 5ff186a579996..1612490e85e0a 100644 --- a/llama.cpp +++ b/llama.cpp @@ -1692,24 +1692,17 @@ static llama_state g_state; // available llama models enum e_model { MODEL_UNKNOWN, - MODEL_14M, MODEL_17M, MODEL_22M, MODEL_33M, - MODEL_70M, MODEL_109M, MODEL_137M, - MODEL_160M, MODEL_335M, - MODEL_410M, MODEL_0_5B, MODEL_1B, - MODEL_1_4B, MODEL_2B, - MODEL_2_8B, MODEL_3B, MODEL_4B, - MODEL_6_9B, MODEL_7B, MODEL_8B, MODEL_12B, @@ -1741,7 +1734,6 @@ static const size_t GiB = 1024*MiB; struct llama_hparams { bool vocab_only; bool rope_finetuned; - bool use_par_res; uint32_t n_vocab; uint32_t n_ctx_train; // context size the model was trained on @@ -2483,6 +2475,7 @@ static bool llama_kv_cache_init( static bool llama_kv_cache_find_slot( struct llama_kv_cache & cache, const struct llama_batch & batch) { + const uint32_t n_ctx = cache.size; const uint32_t n_tokens = batch.n_tokens; if (cache.recurrent) { @@ -2533,16 +2526,16 @@ static bool llama_kv_cache_find_slot( } // otherwise, one cell per token. - if (n_tokens > cache.size) { - LLAMA_LOG_ERROR("%s: n_tokens=%d > cache.size=%d\n", __func__, n_tokens, cache.size); + if (n_tokens > n_ctx) { + LLAMA_LOG_ERROR("%s: n_tokens=%d > n_ctx=%d\n", __func__, n_tokens, n_ctx); return false; } uint32_t n_tested = 0; while (true) { - if (cache.head + n_tokens > cache.size) { - n_tested += cache.size - cache.head; + if (cache.head + n_tokens > n_ctx) { + n_tested += n_ctx - cache.head; cache.head = 0; continue; } @@ -2561,7 +2554,7 @@ static bool llama_kv_cache_find_slot( break; } - if (n_tested >= cache.size) { + if (n_tested >= n_ctx) { //LLAMA_LOG_ERROR("%s: failed to find a slot for %d tokens\n", __func__, n_tokens); return false; } @@ -3781,24 +3774,17 @@ static std::string llama_model_ftype_name(llama_ftype ftype) { static const char * llama_model_type_name(e_model type) { switch (type) { - case MODEL_14M: return "14M"; case MODEL_17M: return "17M"; case MODEL_22M: return "22M"; case MODEL_33M: return "33M"; - case MODEL_70M: return "70M"; case MODEL_109M: return "109M"; case MODEL_137M: return "137M"; - case MODEL_160M: return "160M"; case MODEL_335M: return "335M"; - case MODEL_410M: return "410M"; case MODEL_0_5B: return "0.5B"; case MODEL_1B: return "1B"; - case MODEL_1_4B: return "1.4B"; case MODEL_2B: return "2B"; - case MODEL_2_8B: return "2.8B"; case MODEL_3B: return "3B"; case MODEL_4B: return "4B"; - case MODEL_6_9B: return "6.9B"; case MODEL_7B: return "7B"; case MODEL_8B: return "8B"; case MODEL_12B: return "12B"; @@ -4297,52 +4283,6 @@ static void llm_load_hparams( default: model.type = e_model::MODEL_UNKNOWN; } } break; - case LLM_ARCH_GPTNEOX: - { - ml.get_key(LLM_KV_ATTENTION_LAYERNORM_EPS, hparams.f_norm_eps); - ml.get_key(LLM_KV_USE_PARALLEL_RESIDUAL, hparams.use_par_res); - switch (hparams.n_layer) { - case 6: - switch (hparams.n_ff) { - case 512: model.type = e_model::MODEL_14M; break; - case 2048: model.type = e_model::MODEL_70M; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 12: - switch (hparams.n_ff) { - case 3072: model.type = e_model::MODEL_160M; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 16: - switch (hparams.n_ff) { - case 8192: model.type = e_model::MODEL_1B; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 24: - switch (hparams.n_ff) { - case 4096: model.type = e_model::MODEL_410M; break; - case 8192: model.type = e_model::MODEL_1_4B; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 32: - switch (hparams.n_ff) { - case 10240: model.type = e_model::MODEL_2_8B; break; - case 16384: model.type = e_model::MODEL_6_9B; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 36: - switch (hparams.n_ff) { - case 20480: model.type = e_model::MODEL_12B; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - case 44: - switch (hparams.n_ff) { - case 24576: model.type = e_model::MODEL_20B; break; - default: model.type = e_model::MODEL_UNKNOWN; - } break; - default: model.type = e_model::MODEL_UNKNOWN; - } - } break; default: (void)0; } @@ -5024,19 +4964,28 @@ static bool llm_load_tensors( case LLM_ARCH_MINICPM: { model.tok_embd = ml.create_tensor(ctx_input, tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}); + model.output = ml.create_tensor(ctx_output_split, tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, false); - // output - { - model.output_norm = ml.create_tensor(ctx_output, tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}); - if (model.arch != LLM_ARCH_MINICPM){ - model.output = ml.create_tensor(ctx_output_split, tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, llama_model_loader::TENSOR_NOT_REQUIRED); - // if output is NULL, init from the input tok embed - if (model.output == NULL) { - model.output = ml.create_tensor(ctx_output, tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, llama_model_loader::TENSOR_DUPLICATED); - } - } + // if output is NULL, init from the input tok embed + if (model.output == NULL) { + model.output = ml.create_tensor(ctx_output, tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, llama_model_loader::TENSOR_DUPLICATED); + ml.n_created--; // artificial tensor + ml.size_data += ggml_nbytes(model.output); } + // // output + // { + // model.output_norm = ml.create_tensor(ctx_output, tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}); + // if (model.arch != LLM_ARCH_MINICPM){ + // model.output = ml.create_tensor(ctx_output_split, tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, llama_model_loader::TENSOR_NOT_REQUIRED); + // // if output is NULL, init from the input tok embed + // if (model.output == NULL) { + // model.output = ml.create_tensor(ctx_output, tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, llama_model_loader::TENSOR_DUPLICATED); + // } + // } + // } + model.output_norm = ml.create_tensor(ctx_output, tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}); + for (int i = 0; i < n_layer; ++i) { ggml_context * ctx_layer = ctx_for_layer(i); ggml_context * ctx_split = ctx_for_layer_split(i); @@ -6094,41 +6043,6 @@ static bool llm_load_tensors( layer.ffn_up = ml.create_tensor(ctx_split, tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}); } } break; - case LLM_ARCH_GPTNEOX: - { - model.tok_embd = ml.create_tensor(ctx_input, tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}); - // output - { - model.output_norm = ml.create_tensor(ctx_output, tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}); - model.output_norm_b = ml.create_tensor(ctx_output, tn(LLM_TENSOR_OUTPUT_NORM, "bias"), {n_embd}); - model.output = ml.create_tensor(ctx_output_split, tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}); - } - - for (int i = 0; i < n_layer; ++i) { - ggml_context * ctx_layer = ctx_for_layer(i); - ggml_context * ctx_split = ctx_for_layer_split(i); - - auto & layer = model.layers[i]; - - layer.attn_norm = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}); - layer.attn_norm_b = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_ATTN_NORM, "bias", i), {n_embd}); - - layer.wqkv = ml.create_tensor(ctx_split, tn(LLM_TENSOR_ATTN_QKV, "weight", i), {n_embd, n_embd + 2*n_embd_gqa}); - layer.bqkv = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_ATTN_QKV, "bias", i), {n_embd + 2*n_embd_gqa}); - - layer.wo = ml.create_tensor(ctx_split, tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd, n_embd}); - layer.bo = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_ATTN_OUT, "bias", i), {n_embd}); - - layer.ffn_norm = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}); - layer.ffn_norm_b = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_FFN_NORM, "bias", i), {n_embd}); - - layer.ffn_down = ml.create_tensor(ctx_split, tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}); - layer.ffn_down_b = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_FFN_DOWN, "bias", i), {n_embd}); - - layer.ffn_up = ml.create_tensor(ctx_split, tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}); - layer.ffn_up_b = ml.create_tensor(ctx_layer, tn(LLM_TENSOR_FFN_UP, "bias", i), {n_ff}); - } - } break; default: throw std::runtime_error("unknown architecture"); } @@ -9881,7 +9795,9 @@ struct llm_build_context { inpL = llm_build_inp_embd(ctx0, lctx, hparams, batch, model.tok_embd, cb); // scale the input embeddings - inpL = ggml_scale(ctx0, inpL, scale_embd); + if (batch.token) { + inpL = ggml_scale(ctx0, inpL, scale_embd); + } cb(inpL, "inp_scaled", -1); // inp_pos - contains the positions @@ -9997,7 +9913,8 @@ struct llm_build_context { cb(cur, "lmhead_scaling", -1); // lm_head - cur = ggml_mul_mat(ctx0, model.tok_embd, cur); + // cur = ggml_mul_mat(ctx0, model.tok_embd, cur); + cur = ggml_mul_mat(ctx0, model.output, cur); cb(cur, "result_output", -1); ggml_build_forward_expand(gf, cur); @@ -10656,140 +10573,6 @@ struct llm_build_context { return gf; } - - struct ggml_cgraph * build_gptneox() { - struct ggml_cgraph * gf = ggml_new_graph_custom(ctx0, LLAMA_MAX_NODES, false); - - const int64_t n_embd_head = hparams.n_embd_head_v; - const int64_t n_embd_gqa = hparams.n_embd_v_gqa(); - GGML_ASSERT(n_embd_head == hparams.n_embd_head_k); - - struct ggml_tensor * cur; - struct ggml_tensor * inpL; - - inpL = llm_build_inp_embd(ctx0, lctx, hparams, batch, model.tok_embd, cb); - - // inp_pos - contains the positions - struct ggml_tensor * inp_pos = build_inp_pos(); - - // KQ_mask (mask for 1 head, it will be broadcasted to all heads) - struct ggml_tensor * KQ_mask = build_inp_KQ_mask(); - - for (int il = 0; il < n_layer; ++il) { - cur = llm_build_norm(ctx0, inpL, hparams, - model.layers[il].attn_norm, - model.layers[il].attn_norm_b, - LLM_NORM, cb, il); - cb(cur, "attn_norm", il); - - // self-attention - { - cur = ggml_mul_mat(ctx0, model.layers[il].wqkv, cur); - cb(cur, "wqkv", il); - - cur = ggml_add(ctx0, cur, model.layers[il].bqkv); - cb(cur, "bqkv", il); - - struct ggml_tensor * Qcur = ggml_cont(ctx0, ggml_view_2d(ctx0, cur, n_embd, n_tokens, cur->nb[1], 0*sizeof(float)*(n_embd))); - struct ggml_tensor * Kcur = ggml_cont(ctx0, ggml_view_2d(ctx0, cur, n_embd_gqa, n_tokens, cur->nb[1], 1*sizeof(float)*(n_embd))); - struct ggml_tensor * Vcur = ggml_cont(ctx0, ggml_view_2d(ctx0, cur, n_embd_gqa, n_tokens, cur->nb[1], 1*sizeof(float)*(n_embd + n_embd_gqa))); - - cb(Qcur, "Qcur", il); - cb(Kcur, "Kcur", il); - cb(Vcur, "Vcur", il); - - Qcur = ggml_rope_ext( - ctx0, ggml_reshape_3d(ctx0, Qcur, n_embd_head, n_head, n_tokens), inp_pos, nullptr, - n_rot, rope_type, 0, n_orig_ctx, freq_base, freq_scale, - ext_factor, attn_factor, beta_fast, beta_slow - ); - cb(Qcur, "Qcur", il); - - Kcur = ggml_rope_ext( - ctx0, ggml_reshape_3d(ctx0, Kcur, n_embd_head, n_head_kv, n_tokens), inp_pos, nullptr, - n_rot, rope_type, 0, n_orig_ctx, freq_base, freq_scale, - ext_factor, attn_factor, beta_fast, beta_slow - ); - cb(Kcur, "Kcur", il); - - cur = llm_build_kv(ctx0, model, hparams, cparams, kv_self, gf, - model.layers[il].wo, model.layers[il].bo, - Kcur, Vcur, Qcur, KQ_mask, n_tokens, kv_head, n_kv, 1.0f/sqrtf(float(n_embd_head)), cb, il); - } - - if (il == n_layer - 1) { - // skip computing output for unused tokens - struct ggml_tensor * inp_out_ids = build_inp_out_ids(); - cur = ggml_get_rows(ctx0, cur, inp_out_ids); - inpL = ggml_get_rows(ctx0, inpL, inp_out_ids); - } - - // ffn - if (hparams.use_par_res) { - // attention and ffn are computed in parallel - // x = x + attn(ln1(x)) + ffn(ln2(x)) - - struct ggml_tensor * attn_out = cur; - - cur = llm_build_norm(ctx0, inpL, hparams, - model.layers[il].ffn_norm, - model.layers[il].ffn_norm_b, - LLM_NORM, cb, il); - cb(cur, "ffn_norm", il); - - cur = llm_build_ffn(ctx0, cur, - model.layers[il].ffn_up, model.layers[il].ffn_up_b, - NULL, NULL, - model.layers[il].ffn_down, model.layers[il].ffn_down_b, - NULL, - LLM_FFN_GELU, LLM_FFN_SEQ, cb, il); - cb(cur, "ffn_out", il); - - cur = ggml_add(ctx0, cur, inpL); - cb(cur, "ffn_out", il); - - inpL = ggml_add(ctx0, cur, attn_out); - cb(inpL, "l_out", il); - } else { - // attention and ffn are computed sequentially - // x = x + attn(ln1(x)) - // x = x + ffn(ln2(x)) - - struct ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpL); - cb(ffn_inp, "ffn_inp", il); - - cur = llm_build_norm(ctx0, ffn_inp, hparams, - model.layers[il].ffn_norm, - model.layers[il].ffn_norm_b, - LLM_NORM, cb, il); - cb(cur, "ffn_norm", il); - - cur = llm_build_ffn(ctx0, cur, - model.layers[il].ffn_up, model.layers[il].ffn_up_b, - NULL, NULL, - model.layers[il].ffn_down, model.layers[il].ffn_down_b, - NULL, - LLM_FFN_GELU, LLM_FFN_SEQ, cb, il); - cb(cur, "ffn_out", il); - - inpL = ggml_add(ctx0, cur, ffn_inp); - cb(inpL, "l_out", il); - } - } - - cur = llm_build_norm(ctx0, inpL, hparams, - model.output_norm, - model.output_norm_b, - LLM_NORM, cb, -1); - cb(cur, "result_norm", -1); - - cur = ggml_mul_mat(ctx0, model.output, cur); - cb(cur, "result_output", -1); - - ggml_build_forward_expand(gf, cur); - - return gf; - } }; static struct ggml_cgraph * llama_build_graph_defrag(llama_context & lctx, const std::vector & ids) { @@ -11000,10 +10783,6 @@ static struct ggml_cgraph * llama_build_graph( { result = llm.build_olmo(); } break; - case LLM_ARCH_GPTNEOX: - { - result = llm.build_gptneox(); - } break; default: GGML_ASSERT(false); } @@ -15996,6 +15775,7 @@ enum llama_rope_type llama_rope_type(const struct llama_model * model) { // these models do not use RoPE case LLM_ARCH_GPT2: case LLM_ARCH_GPTJ: + case LLM_ARCH_GPTNEOX: case LLM_ARCH_MPT: case LLM_ARCH_REFACT: case LLM_ARCH_BLOOM: @@ -16031,7 +15811,6 @@ enum llama_rope_type llama_rope_type(const struct llama_model * model) { case LLM_ARCH_PHI3: case LLM_ARCH_GEMMA: case LLM_ARCH_STARCODER2: - case LLM_ARCH_GPTNEOX: return LLAMA_ROPE_TYPE_NEOX; // all model arches should be listed explicitly here From c536fa6ef96224df23aeff5535e4ffafb761bd0e Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 20:00:45 +0800 Subject: [PATCH 02/57] rename --- examples/minicpmv/README.md | 10 +++++----- examples/minicpmv/clip.cpp | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index fad1e033691a0..da06608e05137 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -6,14 +6,14 @@ make make minicpmv-cli python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-V-2_5 -python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-V-2_5 --llava-projector ../MiniCPM-V-2_5/llava.projector --output-dir ../MiniCPM-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 +python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-V-2_5 --minicpmv-projector ../MiniCPM-V-2_5/minicpmv.projector --output-dir ../MiniCPM-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe -./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-f16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" +./minicpmv-cli -m ../MiniCPM-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # or run quantize int4 version -./quantize ../MiniCPM-V-2_5/model/ggml-model-f16.gguf ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M -./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.6 --top-p 0.8 --top-k 100 --repeat-penalty 1.0 --image xx.jpg -p "What is in the image?" +./quantize ../MiniCPM-V-2_5/model/model-8B-F16.gguf ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M +./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # or run in interactive mode -./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.6 --top-p 0.8 --top-k 100 --repeat-penalty 1.0 --image xx.jpg -i +./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -i ``` \ No newline at end of file diff --git a/examples/minicpmv/clip.cpp b/examples/minicpmv/clip.cpp index b09c5883f200f..b8a22cf180ecf 100644 --- a/examples/minicpmv/clip.cpp +++ b/examples/minicpmv/clip.cpp @@ -75,7 +75,7 @@ static std::string format(const char * fmt, ...) { #define KEY_DESCRIPTION "general.description" #define KEY_HAS_TEXT_ENC "clip.has_text_encoder" #define KEY_HAS_VIS_ENC "clip.has_vision_encoder" -#define KEY_HAS_LLAVA_PROJ "clip.has_llava_projector" +#define KEY_HAS_LLAVA_PROJ "clip.has_minicpmv_projector" #define KEY_USE_GELU "clip.use_gelu" #define KEY_N_EMBD "clip.%s.embedding_length" #define KEY_N_FF "clip.%s.feed_forward_length" @@ -526,7 +526,7 @@ struct clip_vision_model { struct clip_ctx { bool has_text_encoder = false; bool has_vision_encoder = false; - bool has_llava_projector = false; + bool has_minicpmv_projector = false; struct clip_vision_model vision_model; projector_type proj_type = PROJECTOR_TYPE_MLP; @@ -606,7 +606,7 @@ static ggml_cgraph * clip_image_build_graph(clip_ctx * ctx, const clip_image_f32 const int batch_size = imgs->size; - if (ctx->has_llava_projector) { + if (ctx->has_minicpmv_projector) { GGML_ASSERT(batch_size == 1); } @@ -1124,10 +1124,10 @@ struct clip_ctx * clip_model_load(const char * fname, const int verbosity = 1, s idx = gguf_find_key(ctx, KEY_HAS_LLAVA_PROJ); if (idx != -1) { - new_clip->has_llava_projector = gguf_get_val_bool(ctx, idx); + new_clip->has_minicpmv_projector = gguf_get_val_bool(ctx, idx); } - GGML_ASSERT(new_clip->has_llava_projector); // see monatis/clip.cpp for image and/or text encoding for semantic search + GGML_ASSERT(new_clip->has_minicpmv_projector); // see monatis/clip.cpp for image and/or text encoding for semantic search GGML_ASSERT(new_clip->has_vision_encoder); GGML_ASSERT(!new_clip->has_text_encoder); @@ -1137,7 +1137,7 @@ struct clip_ctx * clip_model_load(const char * fname, const int verbosity = 1, s if (verbosity >= 1) { LOG_TEE("%s: text_encoder: %d\n", __func__, new_clip->has_text_encoder); LOG_TEE("%s: vision_encoder: %d\n", __func__, new_clip->has_vision_encoder); - LOG_TEE("%s: llava_projector: %d\n", __func__, new_clip->has_llava_projector); + LOG_TEE("%s: llava_projector: %d\n", __func__, new_clip->has_minicpmv_projector); LOG_TEE("%s: model size: %.2f MB\n", __func__, model_size / 1024.0 / 1024.0); LOG_TEE("%s: metadata size: %.2f MB\n", __func__, ggml_get_mem_size(meta) / 1024.0 / 1024.0); } @@ -1939,7 +1939,7 @@ bool clip_image_batch_encode(clip_ctx * ctx, const int n_threads, const clip_ima } int batch_size = imgs->size; - if (ctx->has_llava_projector) { + if (ctx->has_minicpmv_projector) { GGML_ASSERT(batch_size == 1); // TODO: support multiple images } From 2b9190344ed5154642d304adddc7e75ad2ce5356 Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 20:11:44 +0800 Subject: [PATCH 03/57] add run android for termux in readme --- examples/minicpmv/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index da06608e05137..a944d9f78d64f 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -16,4 +16,17 @@ python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe # or run in interactive mode ./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -i +``` + +# 在 Android 上运行 +# Run on android + +```bash +mkdir build-android +cd build-android +export NDK=/your_ndk_path +cmake -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -DCMAKE_C_FLAGS=-march=armv8.4a+dotprod .. +make +cd bin +# then llava-cli is the file you need to put on the phone. ``` \ No newline at end of file From 0480d5faa2565a2358caa1b89cff2c87636e6f5f Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 21:24:03 +0800 Subject: [PATCH 04/57] add android readme --- examples/minicpmv/README.md | 51 ++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index a944d9f78d64f..794fbbb29ecec 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -1,5 +1,5 @@ -# 所有命令在 llama.cpp 根目录执行,模型位于根目录上级目录处 -# All command should be executed under the root path of llama.cpp repo. We assume the MiniCPM-V-2.5 model are put in its parent folder. +### 所有命令在 llama.cpp 根目录执行,模型位于根目录上级目录处 +### All command should be executed under the root path of llama.cpp repo. We assume the MiniCPM-V-2.5 model are put in its parent folder. ```bash make @@ -18,8 +18,25 @@ python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe ./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -i ``` -# 在 Android 上运行 -# Run on android +### Android + +#### Build on Android using Termux +[Termux](https://github.com/termux/termux-app#installation) is a method to execute `llama.cpp` on an Android device (no root required). +``` +apt update && apt upgrade -y +apt install git make cmake +``` + +It's recommended to move your model inside the `~/` directory for best performance: +``` +cd storage/downloads +mv model.gguf ~/ +``` + +#### Building the Project using Android NDK +Obtain the [Android NDK](https://developer.android.com/ndk) and then build with CMake. + +Execute the following commands on your computer to avoid downloading the NDK to your mobile. Alternatively, you can also do this in Termux: ```bash mkdir build-android @@ -27,6 +44,28 @@ cd build-android export NDK=/your_ndk_path cmake -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -DCMAKE_C_FLAGS=-march=armv8.4a+dotprod .. make -cd bin -# then llava-cli is the file you need to put on the phone. +``` + +Install [termux](https://github.com/termux/termux-app#installation) on your device and run `termux-setup-storage` to get access to your SD card (if Android 11+ then run the command twice). + +Finally, copy these built `llama` binaries and the model file to your device storage. Because the file permissions in the Android sdcard cannot be changed, you can copy the executable files to the `/data/data/com.termux/files/home/bin` path, and then execute the following commands in Termux to add executable permission: + +(Assumed that you have pushed the built executable files to the /sdcard/llama.cpp/bin path using `adb push`) +``` +$cp -r /sdcard/llama.cpp/bin /data/data/com.termux/files/home/ +$cd /data/data/com.termux/files/home/bin +$chmod +x ./* +``` + +Download models and push them to `/sdcard/llama.cpp/`, then move it to `/data/data/com.termux/files/home/model/` + +``` +$mv /sdcard/llama.cpp/ggml-model-Q4_K_M.gguf /data/data/com.termux/files/home/model/ +$mv /sdcard/llama.cpp/mmproj-model-f16.gguf /data/data/com.termux/files/home/model/ +``` + +Now, you can start chatting: +``` +$cd /data/data/com.termux/files/home/bin +$./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" ``` \ No newline at end of file From ec1cea718229dbf93904d12fc252a8130338b11a Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 21:41:11 +0800 Subject: [PATCH 05/57] add instructions in readme --- examples/minicpmv/README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index 794fbbb29ecec..6bb0feab462be 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -1,17 +1,31 @@ -### 所有命令在 llama.cpp 根目录执行,模型位于根目录上级目录处 -### All command should be executed under the root path of llama.cpp repo. We assume the MiniCPM-V-2.5 model are put in its parent folder. +## Instructions +Download model files from huggingface to "MiniCPM-V-2_5" folder. +Clone code ```bash -make -make minicpmv-cli +git clone -b minicpm-v2.5 https://github.com/OpenBMB/llama.cpp.git +cd llama.cpp +``` + +Prepare the model +```bash python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-V-2_5 python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-V-2_5 --minicpmv-projector ../MiniCPM-V-2_5/minicpmv.projector --output-dir ../MiniCPM-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe -./minicpmv-cli -m ../MiniCPM-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" -# or run quantize int4 version +# quantize int4 version ./quantize ../MiniCPM-V-2_5/model/model-8B-F16.gguf ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M +``` +Try to inference +```bash +make +make minicpmv-cli + +# run quantize f16 version +./minicpmv-cli -m ../MiniCPM-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" + +# run quantize int4 version ./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # or run in interactive mode @@ -20,7 +34,7 @@ python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe ### Android -#### Build on Android using Termux +#### Build for Android using Termux [Termux](https://github.com/termux/termux-app#installation) is a method to execute `llama.cpp` on an Android device (no root required). ``` apt update && apt upgrade -y From a491f45cbc215143c528a7f612533ece882f910d Mon Sep 17 00:00:00 2001 From: caitianchi Date: Thu, 23 May 2024 21:44:37 +0800 Subject: [PATCH 06/57] change name in readme --- examples/minicpmv/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index 6bb0feab462be..b37facd9c61a1 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -1,5 +1,5 @@ ## Instructions -Download model files from huggingface to "MiniCPM-V-2_5" folder. +Download model files from huggingface to "MiniCPM-Llama3-V-2_5" folder. Clone code ```bash @@ -10,12 +10,12 @@ cd llama.cpp Prepare the model ```bash -python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-V-2_5 -python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-V-2_5 --minicpmv-projector ../MiniCPM-V-2_5/minicpmv.projector --output-dir ../MiniCPM-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 -python ./convert.py ../MiniCPM-V-2_5/model --outtype f16 --vocab-type bpe +python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-Llama3-V-2_5 +python ./examples/minicpmv/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-Llama3-V-2_5 --minicpmv-projector ../MiniCPM-Llama3-V-2_5/minicpmv.projector --output-dir ../MiniCPM-Llama3-V-2_5/ --image-mean 0.5 0.5 0.5 --image-std 0.5 0.5 0.5 +python ./convert.py ../MiniCPM-Llama3-V-2_5/model --outtype f16 --vocab-type bpe # quantize int4 version -./quantize ../MiniCPM-V-2_5/model/model-8B-F16.gguf ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M +./quantize ../MiniCPM-Llama3-V-2_5/model/model-8B-F16.gguf ../MiniCPM-Llama3-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M ``` Try to inference ```bash @@ -23,13 +23,13 @@ make make minicpmv-cli # run quantize f16 version -./minicpmv-cli -m ../MiniCPM-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" +./minicpmv-cli -m ../MiniCPM-Llama3-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-Llama3-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # run quantize int4 version -./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" +./minicpmv-cli -m ../MiniCPM-Llama3-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-Llama3-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # or run in interactive mode -./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -i +./minicpmv-cli -m ../MiniCPM-Llama3-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-Llama3-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -i ``` ### Android @@ -81,5 +81,5 @@ $mv /sdcard/llama.cpp/mmproj-model-f16.gguf /data/data/com.termux/files/home/mod Now, you can start chatting: ``` $cd /data/data/com.termux/files/home/bin -$./minicpmv-cli -m ../MiniCPM-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" +$./minicpmv-cli -m ../model/ggml-model-Q4_K_M.gguf --mmproj ../model/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" ``` \ No newline at end of file From 7573b634a7787219828db6788c0d959d66c5b795 Mon Sep 17 00:00:00 2001 From: Hongji Zhu Date: Thu, 23 May 2024 22:09:41 +0800 Subject: [PATCH 07/57] Update README.md --- examples/minicpmv/README.md | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index b37facd9c61a1..17c49d68e5581 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -1,13 +1,16 @@ -## Instructions -Download model files from huggingface to "MiniCPM-Llama3-V-2_5" folder. +## MiniCPM-Llama3-V 2.5 -Clone code +### Usage + +Download [MiniCPM-Llama3-V-2_5](https://huggingface.co/openbmb/MiniCPM-Llama3-V-2_5) PyTorch model from huggingface to "MiniCPM-Llama3-V-2_5" folder. + +Clone llama.cpp and checkout to branch `minicpm-v2.5`: ```bash git clone -b minicpm-v2.5 https://github.com/OpenBMB/llama.cpp.git cd llama.cpp ``` -Prepare the model +Convert PyTorch model to gguf files (You can also download the converted [gguf](https://huggingface.co/openbmb/MiniCPM-Llama3-V-2_5-gguf) by us) ```bash python ./examples/minicpmv/minicpmv-surgery.py -m ../MiniCPM-Llama3-V-2_5 @@ -17,15 +20,20 @@ python ./convert.py ../MiniCPM-Llama3-V-2_5/model --outtype f16 --vocab-type bp # quantize int4 version ./quantize ../MiniCPM-Llama3-V-2_5/model/model-8B-F16.gguf ../MiniCPM-Llama3-V-2_5/model/ggml-model-Q4_K_M.gguf Q4_K_M ``` -Try to inference + +Build for Linux or Mac + ```bash make make minicpmv-cli +``` -# run quantize f16 version +Inference on Linux or Mac +``` +# run f16 version ./minicpmv-cli -m ../MiniCPM-Llama3-V-2_5/model/model-8B-F16.gguf --mmproj ../MiniCPM-Llama3-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" -# run quantize int4 version +# run quantized int4 version ./minicpmv-cli -m ../MiniCPM-Llama3-V-2_5/model/ggml-model-Q4_K_M.gguf --mmproj ../MiniCPM-Llama3-V-2_5/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" # or run in interactive mode @@ -34,8 +42,12 @@ make minicpmv-cli ### Android -#### Build for Android using Termux -[Termux](https://github.com/termux/termux-app#installation) is a method to execute `llama.cpp` on an Android device (no root required). +#### Build on Android device using Termux +We found that build on Android device would bring better runtime performance, so we recommend to build on device. + +[Termux](https://github.com/termux/termux-app#installation) is a terminal app on Android device (no root required). + +Install tools in Termux: ``` apt update && apt upgrade -y apt install git make cmake @@ -82,4 +94,4 @@ Now, you can start chatting: ``` $cd /data/data/com.termux/files/home/bin $./minicpmv-cli -m ../model/ggml-model-Q4_K_M.gguf --mmproj ../model/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" -``` \ No newline at end of file +``` From 94dcaba6464b812ab8924a4e3e2febcbeb8d1652 Mon Sep 17 00:00:00 2001 From: harvestingmoon Date: Fri, 24 May 2024 05:27:04 +0800 Subject: [PATCH 08/57] fixed line --- examples/minicpmv/minicpmv.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/minicpmv/minicpmv.cpp b/examples/minicpmv/minicpmv.cpp index d0c17bd537249..a885d8f19b201 100644 --- a/examples/minicpmv/minicpmv.cpp +++ b/examples/minicpmv/minicpmv.cpp @@ -392,13 +392,13 @@ std::pair get_refine_size(std::pair original_size, std::pair int grid_width = refine_width / grid_x; int grid_height = refine_height / grid_y; - auto best_grid_size = find_best_resize(std::make_tuple(grid_width, grid_height), scale_resolution, patch_size, allow_upscale); - + // auto best_grid_size = find_best_resize(std::make_tuple(grid_width, grid_height), scale_resolution, patch_size, allow_upscale); (old line) + auto best_grid_size = find_best_resize(std::make_pair(grid_width, grid_height), scale_resolution, patch_size, allow_upscale); // (new line) => fixes conversion for make_tuple to make_pair int best_grid_width, best_grid_height; std::tie(best_grid_width, best_grid_height) = best_grid_size; - std::pair refine_size = std::make_tuple(best_grid_width * grid_x, best_grid_height * grid_y); - + // std::pair refine_size = std::make_tuple(best_grid_width * grid_x, best_grid_height * grid_y); (old line) + std::pair refine_size = std::make_pair(best_grid_width * grid_x, best_grid_height * grid_y); // (new line) return refine_size; } From 629420ee397f000b4b04ede11fc903576940a757 Mon Sep 17 00:00:00 2001 From: caitianchi Date: Fri, 24 May 2024 12:06:48 +0800 Subject: [PATCH 09/57] add result in readme --- examples/minicpmv/README.md | 7 +++++++ examples/minicpmv/assets/xiaomi14pro_test.jpeg | Bin 0 -> 311131 bytes 2 files changed, 7 insertions(+) create mode 100644 examples/minicpmv/assets/xiaomi14pro_test.jpeg diff --git a/examples/minicpmv/README.md b/examples/minicpmv/README.md index 17c49d68e5581..b661b26466a36 100644 --- a/examples/minicpmv/README.md +++ b/examples/minicpmv/README.md @@ -95,3 +95,10 @@ Now, you can start chatting: $cd /data/data/com.termux/files/home/bin $./minicpmv-cli -m ../model/ggml-model-Q4_K_M.gguf --mmproj ../model/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?" ``` + +### result +We use this command on Xiaomi 14 Pro, and the measured results. +``` +$./minicpmv-cli -m ../model/ggml-model-Q4_K_M.gguf --mmproj ../model/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 -t 6 --image xx.jpg -p "What is in the image?" +``` +![alt text](assets/xiaomi14pro_test.jpeg) \ No newline at end of file diff --git a/examples/minicpmv/assets/xiaomi14pro_test.jpeg b/examples/minicpmv/assets/xiaomi14pro_test.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8762c9c7b14951270fc8d60c092491afffc130bc GIT binary patch literal 311131 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 z zz?kq!2erQ8`k3+7vW4T;XF%#~V)GJLNV5Jk@EZ>vupx_IoF~bl3Tx9o@yN+k4xVQZReyY5O} zKYZKm1QI>}0+gj(hh@lD;3T<#=gMsbxujaqR}xv#J z*AA_J{t)BXN?JeQ(7n-`+Z=ok164hjnf(J?*8do~edq{Y&j=3QVMqE0*u}Y~{6l4z zX!SR{OpqO2vNprPhVTV__js3JCK<C6`o+g6XJ%^CW!*bK@lPoR*XR{8t>{^kam#LGEOD_8j&gjPAH4u_&F8@`o^z1Ku)b2k?)mpO*KbHh_xB@(@U zvRQ%8N3lpb&@mRpZ_sOH4Ts6b$Sag{w#?}O}wl4B!Z=K-R)RF5`7C$0=L6G9L+pres10#UpKp5_z2 z92s(T@1l`$)6c|`g~WCk#;)u7XoC9vxG+BTiHUTgHmuUA)qqAived4=^l=Y|FzYmj zxgmBa3LBe!WDh%swaah2nNcC}<3f2MUY(0ehKXub?Vf2f5*f009~HX07FSW>Tur9S ziBcIC_(e;sOUFa7Mt2W-39rq_sf?{cXLMOMkAS+&FtL^0%eJ3$k&{=}cIPkFlI6|6 zsWP#YfWbFDvlmAbDfN|98?#1^TQXyj(u&C=P|*k3Q2Xkhf7_X5Ty=2`NcbNcF&GM^mNG>b4IDj057 z7O)5G1dTeq8fyib?rX1p9`1H#R-DZHUdOw*6}Ns`QN6YrW|fNGA|hg0ducYE+N=1b zV$GAMbUCyrzd)g&gX)fPc5K;+EfU$TQcr8p1zNIBVILH~-(0J~D zR$3qZ*%E7Qnxl)oRi?|Ll{ zR(~`89m-Ujs`NQ}ybm^Yvs~NjTV7f@UGkz0njmova~6}L+l!mlKvua9h4_D&>7 zWN$5S(&qlU&&)+1OI$_aD8UYPsH@V_saPR0>|DC=I*+KUYOAHEH0eADmFw1rRe()?Ky3$>pRu^Gu5qg`{URssB!hcGwdqN@ zMz#Du-k?5z!Cy{L=nT{2%(N10Q;7`wjGiZ1?F*Axh9Ni*@iQt*?k7gF6Tp7n8=^# z<_)sw=?+)1I*B}#lYK11cb%Aw?;x&Ye^~amI198#GfoU?(?1$~*m>2aVqny8S~~7D5yDjiWl&Bt$$`&2{P}m9V%rx?NvA-Z2Tc$Etu-#{FWwr z4N?UCEzNTm7BX@e;p!nZTG#@ISb;qNC~Ep}x=TK$CyXXO+EAWGNS z=&&@!M~odq=92)_7!`+jN%L;!wSWOP3@|tj@H@xHA(4s{aD(C8TJx@(z}ZwM5A-z? zd&;P-81GV%`I4*gGTA-pgN(4oKLDaTK@&i8f0s2qDyKkR6QCpHjiTKe$k9UG4_&w^ z$O@)*$g&NrHGJB3Q6HOe$m-j4VU7j4T9(sheED7N=`?8FLWze$nG*`|+QUQHDo*UD96)zX}5(3Y9gFFD(bLu8H!!`#JN!e*XSMuZSE&F#PBV2bu1@{t7@Dc|X4 zx-KUj^&i3>UXPV}MSFv1uTIGf!QPG~zo_jSfLKNK#%k)8wPu~w#7#=|g34{CWb#d{ zl*R#cY!Frv-33h?qTJZ`nG-JfIIdEOwjZJ`bz3#@E0Ot)7wh!i*ecs-wJK4z^&+c4 zqdP^d9>j@a{ap&C4XN~pj0b%~`KrCH_*6d-+WC8G96|gf5+oaFm3&4!aDM>)7UVseutHl>UDJr`^VHE7aeY2R3;cvSykHpRSQRV;c#TWkD!`#Z9m1PzoX7`k zR$iA~C3_h9nQx3C^!G=+K(W}zn$gn+t7Rm<)`*NQ{64I`6#`yKO&NTaLj?GTOB3Hy zZK{kOp2hX~rO0kK@beFJM*Fj>9@gC0U#9^=vn=1PNqJa|vuZ|8zgo&)FuVVdKfakj zI5-=1`;;;f-fGLo(5n(MEPxU0)pFutRmd%yf~+F8F1zW+q|EhRCPcX_EYO z>7O%SJ0y>`@$ya8I;rotl!@36v4S71gaya>?Yls7Qn)E2^)fF1={S91BNm z8&l}9#l_tzy7u4wh(-(-x6e?~^8(WG7B17Qr2MLh*soKA7jB_dY9C;?rQM!dPZqs( z1Co#!)zr$#xRo@d+iUqb-+m?gfeld6A3Y_#aBL6u7btlE{s7T$*j1GaSIDpWgDfej z`~){RY4S2u_cY@xhcy%u5A>UyEb6J^_Q--?unjLBYLg2#KJyKgtU)A()6Th8Ypf9V zgzmJ(jCi-R>Tu#-xi2uKXOS%qA-3>2b=4a681{9c6K8nLecH8VRlpiXU>oJ4-BLDi6>|5I zlaba{NLg=+!)58>TA2VrTzv7RrE)ZO#30Zq(!Z+{E3*q1^meYfYUTMKwLN~It@QBP zGo?%-alO}PBR)VYV`hEsvY_EZSN)ozHpvy0vWkcK<@@46B-TnQt?!|G(W8jIl|1UW zrflN&1pbU>qWm8iN{mIf^fBiGbIdlweGC{MF#LP>uZ*eIamy#h?|#AKAkeXlAqVva zI;C`Hrn_3xukGusqJ)RjZ&;|=6e`$1VF)@F&;&2pJ3AIV+<3b(Nx&#lr-a|imh+$Q zcBDrlO?C06i)U21P}(|)g?#&Jww8O@Ww~LdoO?PEI~gfyY?ghJu|p4mRhX1QH!&ZD zr;+#uZD*O&kjF#S7W$3RWYtzv6}#=iD)4n+@AIRq3a0pYbx3uwF33Iy{c8yE07eJ` zTswT|fHVR)N6f!f!sn3{+gRZODW0cyQ{AZ1%Ih?rQ%<2&g^zxsV$*k`CgUV0T(>l3 zra>7h{aM?^$8qRlPs_gBUI>(EQ;I_7Tx(JxfJ}OZ#;;52d!pgy09LAp-?DiQUfW zP~CE)$HOOAm#|U+52VdQ$=(NAC-JXMjbNgOi8jZIt&mfy>l zd6g7+Rma{+T~M*L(?c&e*-Qp#S}^%;W9#J`K3QZMD5!b2jtQ7VLNmTpQM2G+4p9AZ zr`DpD0Aw801l)WMpI&9v#IBd8S$r^DTwxCGTWUpVBO&~$?;ADYGn%NsC#x5Suer@U z@koUiyrt8P0&#Qp-m$DEO7GMY8ZM#Jw4#IV!b`l zL+``h0Y0c(zhcvW#^X5Q6q#{K5Ww!^ZXy9(52?-YaR3*E-oFZM|z7TYuk&umOjQGh0NUdsBp2xAfBJw97 zafQjG9938}d?^gH2ZZgWY&PfTwtR=FWhu<;O$+rIp{J#E2_(^IjzTu~kd6)HZ z!_lI(zyC7MxPXy1IKC){2)KC7SWs>Si$$jZmWygmvv*hLrf6HyXJbk}9&#S)k!mNb zb2)rSNGT0oZLi!~khTkV6gEF_>O1sMjd;GRURlh{(kah)*zk35r{~R6u-KMB%4~MS zzkg4;$Ojy$epem;)u3HYU*UtS-bK10tSB=LQ_fR96;J0#8X=KSkD$?DlaJuMY0f2Em#`&XbOUS@jPw~SLBxi zwv(JHfO`(ozFx}mcAZsSn>un%OE^e?c z^s97yqc3+mP4&>-v-EehYi2wEpj?<+5zHIMe14msXaCLZL98%N(9+(eo}z>Qjd55V z*gd&X`?Ykk#mp+LK52?CO~qj_J5)uXXv~TK{Do!Dlw}g92iEnqUD<)Uam>Nmxuk$8 zRw{CJ&(92NrMBOkwzU`YplFU1qmoR;8~V3TfN$8g`KOE((`Ien1nj-L?Xr>(uJKqx z-mFfWcv+(Hs$Hi;r!p8Nt5TICj#z~i7UE)Rx|)@LyONn_E2=@n&fu3!j(1kGx`Ab1 zH-7C*(YrNx4gz^=8B^7<=ceFCJof>Uhcpn*sY(4z4r!jWm-7t_S4>bYT80)=(H;nC z_1AQ8Hw$-ewbD$v4!mYV2LosKv?N$PecSyh{UCo9-5t@F#J#lgvdS z6AW+PM5X8sdd9c|SgkAD6SGtAlI0&U)Zf#vDb z@46_BT!_&V^r3v_>9U(~iW)U?boQ3cq!ZAjL<3dHfVE@%Ii%w?maiM_!WHH$BS9M2 z2J1-h*i_QS1gKZFsyBZ2t$EVfElC{O*38P^@I2(M^M6%Nx@#L(g;ykV_pfGdF-Ou; zQhkUa2HfUke*5}qMg*me)C{0O<>uSH^4Z@$@ck$!Ve!wlgUs5X20TZ0*8o0XX*=ad zs(ACb4+t$%$a2iR6P-lybZDJg9W3NV7pZRvt@AZNR}^6fe+<{pekPkqVcujM27#4A zm%3{?dR-e1^`in06$vHWQ_m%-sIEY^vhvLHsFsL`n0Cr*0g0|P(rBk8SR|*5vy}PA z@)x0;D`U_48KE{^od@GzVCD^{bzZb0%@GZBx0^jgx$BOWWqA`rIZ5hV=6BE?mqk-P zQW>zG12Kq$(XEwcuISxNxi{6%m5K*tSP?f%TZ4sHP!-dU#hv*@jwG2Z(hK;oK`1K$ z;xh5CR3cONE$gE@L_;b@=N|iv0VLATX2p7BKeDbqHHSOvp)#=`2N_XTB$MX}f7Icl z<~01;OqZ>qP%+P0US3|IEfPF1-E@bjqFKp}KY|%YU$x`P7rmWJN-+UOET}DfHrx2w zo1qJv5LzU+l6|QnAJqft>Ch{hIRpvOE)RzFF>v`7zXyU7X>yCyKL{?9(a6U)=a*U$ zI}Oa~q^{VkKX+pPNdBbYtK+=q;YpGBO?403izyjZ{-ZcO22$V`_rL22uDWv-)o>mx z+g79ALV%BywSQ*pn^aa784RuKfNXG@;;Lo}(sHDbpOlg`2pvg4r z&!iGXubOsSR-8;C`rS1}mkE3Ba?g^pc7^l#E7#|632L zZqbTWMtgc_2XY8w2?d0!W($|tA@3E;d%WUAc>Dv%MYO+)a;0u~^pIKilI@3Cv1(+c zKm>R5ZE$*wI*!NaMGPx$YF&&AGM5)-^ukC<=M!P^7rUpb6sN>Jh8fC%xs5+9ReeMx zGgai-UDXam=F=B0mvt$~qk^2WcFjfHl{&f$Uasea_dcM#AA!M(;t1db3Bq~v58LA( z&ztHv_DpPK?}=MUd`uB z(8`SpaO2F}?bIk?s2@%}^ZDDSaJL2bqYPHS-wA53_5K}~#FPhbg9V;SEs+f(C zQz3~8@X-X0z<(J-b0>kz2GMqN^|~KEpF~#4tTP`PW66BWWCtV2r&)y(p(>imUPW5O zgpo3(peu)wQ+J9FQUTneL=|MhX1am~Cl(AER>rfhR8aj{Hi&=FtP~wEp;%V(UjDgp z_?jnTD8&;(BoExn%KaTLPZrI`30J4(mLte&Xvc1lx4Sm4C#^!duy7EoE0W|<6T9Lw zN1zQ$-}<2fb%;35(D;2qtHbdg=UvgWA^rj5P*$CXr-u2-8Q3}S6X>tC{U+yTg$AVn z9n(z}=KwRBbI0K@8$&(XY=ptdyNXd8qNKb(S>O6Lv3v!kN0{3Yq=(y0u|jL~aNy~< zc$HGtuUZWT1;?69NoxOgM1FWD)VzSp#HXv6zrD6X$Ac3Hbn_oZZg3Z2% z{qbRy1?a~`36#FT4`W7%nFbz#DN#-sf|f2_d+9aobiu=nmNdR z!3{{o2 z7D(;eCY4j-)L0;;57}pm<%1ulJ#$MrB4Bx>53KD9s%T18{+)D;&m;*dCU~cyW+;vb zDbv)JZHsxdtRu|LHu{7@zK9>?7=sU3Zif=77M;RAs9X-2D9o0nN>)af(DkZQhwOlVN7Vgi>9TsU? zXvNT-9gcU;dt%|O@vg*bj%$Qrl!q^)0oz_uX*<1R$G`jRT!E zG77$<3ATsA3qf+FIadevSBTvaDvjly#q{y6;cn#S^pUW&IQN)FPUTaagawz;J4xEe z!7ctvIacc~t*!v}gR=E6l8=Ro9DfI|K5ARCNp6*ok4%(z>_+If6&PS{M85RI9qY1; zX&dT!D`65G$tY+O*{AlY60x9%lwjWKFj$RvXfq(J@O5OlMy3a=;iJ$>#as5HT(ONM z^Ta-qu-XT*!k(5DWF*R%9iVaGy-)BI+Ez$u+Ekj<;)g&^95D&B@EE2G^?@5i%)qw4 z%aK%eP1~vDgsk{|6gUS$Df-brA+4X%E}hnNXJr{jO`<)(j(d2 ze6ANW!tdrIm(0~I8?7w!4X+gm`3f2iWs?cUPL)74#`Bs@FJTcHi`LDOq{55er*Bu? z<;8U$yN%p;f8j|tT>c_0ov6e>)X@4cbk~eu-57RdN6oGd<+bPbna(K zEsBxKH#G*~;M3{S3{roqCU5%iu15QFgzyYnq&s$97!sN_)FZ28kuD>M8{hS}Iw#Q! z;QOoM+Tt`dpUH~wt_%Mp?|F3nmazje-8(0CdZx>FadVnz=g_R0!-y3k z7GQ~tQ#*xbeJ9K}&v89$k#xu7I%B&M+Sk?9W3c?9#$SzRx>$He@!j?F&kO2>ht?+< zB9_v$`8kO->!7oCO%EgjA0yr&`xFe&=ift7yVwK%$@|oA4)RC@xZpXAPX~3$1S^J` z-3Fb7bj~YF8;`e<0gr0rCN`=XfgiCi_@!EYEeoFJ3-71dvt^c55pwP0yGh?H`E1kR z`BfK?1(e`c!*|A8s+iVzWq?<$)EBG*Y1ZDcT4jm{FQ5Som~>Vp>;?pI)dNEa@V@^b zNBAB<+lc^;qRw+D^0y=0#T{$TnCJtd6frth_Z~2sRi3CG(7Ly6zrm+dX>&3l13h^B zDjZ31N$4J4ULkjeIN}JJL1XD32c5c{30ba)Xlk3L^-n4@hs5Wt+0-!w8ceZM+S*bD z-6$a;p@_)l@Nfwdo4v2^9zC83>N$R=r+w-X+?Whp&Uyt}_!eF&A{2&(^1)6|pYmM& z37KOkctdis0Y*indDhtT6szoBY%NS}8G}mhvsXk{`S(dquvg5eL=a8Jq6Ts2z;j znI7DPM6YJH!|1?~#!F9OHVlTQY)&Dzb;y0vLmh0lKZ_s@cuL&pu-=+}iX)AQ(thfk8&tPYty&nIOCrUw1WIy2LU^ zdXI{V#vC(*FYWBUcd74TcUT|o_|k};IMw^(mLbUD8Etct2|r^~v7{zZyB23jd)owS zUtmIusY9tT+%iQfro5k2{HM`nSBi^q?`5U%PClG_%PVxJ{27${C8n z=&2o0bkhDb=M^}RK`*{^;_$Bajj4`1L$qQ+x+i#F)`#}CT^q~1&Z^V$PQ1GlY^YPz ziFD`ZpqS1zS}v^{Do5$kA;IXnp2GZ(hWreW>&tGY)lQ3tVJ}=eIh-j5A%P4-c%>#$ z@X0Uy@bEzqO+C93V5zpWp$w-0d1CLMeipuvkYieKB~>i!sP7u&95ACMQbL(5Bs!xV zY;thd)-{Xg0#8nZbgd2-@YkKprBGnl_t1M=RW9Seo{VWl%EJ1Ct8Mu{&A0<21z*cF zGRv?Gm=9+x2mzjy8cX+uCK-7=-JL0PI=;*yy4=fK69URAZzDk+`yd6}p0HA}#6}=$t>l z?t1+J5{??kQCKt6aEAXh%_Lf~y{&C;#P|`>@2tyAcAYD>J=P*NecQ*)#bPV0y z-JK%c2n-+qc2{ZyrhFmaH zH3bqcQ!rSe+$*i*RTcdn>klz1+h<&@alj$=>x8V1+4*Hti;mIZ0bw9tPHRi{&3*Zr z=1yYm!ME>E_(s%%F8sUp(cP%X!cL~rMiRAZ)VFq1Za(vfXhGrDLeHFe^Cl1BxC+~D z&Z{D!V-%+RW;&C1lCDrd|Nh?rs@`k{o7M1=Sck*dSE9% z^wo(wu-%5YV7#D7rDn~cczQD$^E{QVC?>k!=tyDmaha#S*ug^@<;nN8BPpwHk#<~A z(B@$TV&QBxx&zy-%!xWMyu2>dnM=_4U zYn8}k&uQwzE~s$deE8*ZS)yeja`Y!|BGK{A`xd&QS28?*wOYdR%LNuhFtF zXQQLwrn!Fnm}XuohNKe|EA~G?_docSk;KdP`}f8Y8$W|zw2=prFE8v$tP(J2mP)9- z+-!A_0LrI7!+VChA_?r-l%2wE!%MxQep#euBff*-cjdiquIS(XS)YiY(G@|m0Her{ zZ|dA<)5sohS?u|po$s)H`c_G1*BuQHlWYu-t@l??pdt|_x%x`cC>sj7#i{no?lHTH zOxNQ+qIzZQ-9~#Cb;17^ngUn0{|~SfoPp#ad!HAszL~qpy_-{wP))H~jX>RWt8c+m zBJkOynpc!kbMNL>bYPcv1D*jN(HIySzJ$Q#SqWOjz^s7Zskk*w`ncf(twiqJ6%L>y zpk-^)_~HbEyZ}+92j_eGK|s(MNQAl;4#zMRy@(#)&$Lco zpMU<|nYk>hKAy2STV7gS4M>D*;y&o;>$53IM}OJNaZd?TL)x@@9mUlBy)U9tb4A4C zjN5hj`~BPJf>?1jZxAoqXO5KCT4pGT2#?2@m1ztc?+~Lv%K6#ir5%N^JDS_XJD{yN zLwNR=Ofnq_R7dVeiR5ROx9oXL>03j;Q@ZCiRN0SyYXzn7N(6h5s;)+mOD_$^Ymot)!9jM$KQ%a(0o#+f# z69LoejS*+XISqPdXE(>rGDKPWiPvD#AJ8Oc@6$In{#Jn-RLj=uD_z|%glo~$LqU`e z7k@+8qB>?}Xp;a-GK0dc(&>XJS@;Cop9TVl5Fc|YUD}ZyJOyGLlO_8}OZxxXyb*)p z89c$1c0l~wfcnfV-kK3KhAyU@ElZgzd@zbu<(@0u`{l|59}TAkd%n{y2NBRh+5Thi zt6ZlFd^@=!oH=ovoRw8LE}yu@>|0Dr6HNg&1ak81Q<`mK!_w_Po<+<0QqSrSYH}0z zj695APL!OVUOe5N-zKzBb0NhVtyvaOF?*}F@kXav3W!){pY$C`-{_0ZbrERgUolR9 z=}||+icy%6d70%XMPp>T$?w#nG-PE$MkfHFQ66`3Chr>Hvtu3QHr_@=yCescNu|+D z{k{LSXwgUAh0=gr4B~AXXkAXPqRBoWBF_DI*9RSNieahP`^%B;rtI&hQtu-`;h12tIq*o^UUmrqw6Vk9y2&%{tr+SsxPnYzi68>ZKR$~&D9PICcmZA{D?SqjnKTwC4o;V>!^t$*vjy>0J1A_Md zx@ElVpWhmNEjV8fL|eElYN}ugnnQLfG4!tdh1)Oe40Pc{aD@`;4{tN_YAurD6GTYp zbVT?+e%S7h^KC8rjgeS1EjU7pg3nXN6aR8LQMzSjz+c|l=Is;L2C`mvQqG2Ri3lc8 zr0aZ?EJd$lagZ`9Y>eV96KqoIg^W4NbV%no#ILJ<=Sr`s`#xJ^|m2MVR%CfLsz4pgy3v?m><2^e^&ZyMNv3?&;G@u!b?{ zsO*Vvg^N8w_q$qE>EdfCAfuvIQGSOI(03zgD6eF8WoJa#_LQW`z5zXggkwAe1LftE z+&_bSOIcghBpu9=JfAz)trxleY+Q@opz-{yY)pun2a?GK{XzY)DPm|vT9jm|ovhWA zF!+eVg~Zmraizp(*M@7@++tRJ=GnUDR212G{N~@!(*~E-i|v*EEhD$z$MbdlPcQKP zqU*Q)e=x)5gt*v^W~9hqR&0CQdv@v8>M#?hdi4ZBM-MFi9F<{LEv2aJ>QjtnFDS7m zbD}UBGTeddHG)zDp2&1xsy&?vS4w|p@y+cjF&lK2;H>l3?_P#cSrC@^@tZR5rp=l= z@JqBLrKQ4^f8{wxJMSs#0MLyW#TRj!o;6qoA;x%9LPEJw_xIzX5&Bg5x8tu3m3Q}n zf6(m3ekMK19IgMn*%5_Ezj*cJDY+K0+AO5cpIN55gSupBgr$UGB4ykPP`Rt#5m3~f zrYs_ZfSS+OfnY!yMj#wxL27wtw)8ox8ijOBZtY%Ld<9Gw+n|BLJxb@LHZeXyg9Tq_Dq>L z6zk1C0{K-J^VK2O$g!%s7{xxK-!%Xg#AIX`Xf9FCsnce)5yDDhXG?w0LEBUJAt9z5 z{A(UvLR@EeVDEA5-z-gs5y%{(#JnF|yp<}2)~mU!e{h7ZnM-$2B&C0&p0Z-$L5azl znFa{Ys1?N;Q3rf@;Yc;-=i}%tB2`FAZpnHjra4qdP}on`-b8oqaWcvBBi!`B^2b2V zvUl;AeqUAWplq_O!wMGey*7X$imh;y^}lXc_kSH1H<$ZjDGhQ}9DvjTG7o?3c4EpHH;%DqPU=ir3&XC5(q|4M-6p8q2;PYg zf9m=BH|jBR-0i12yGdsRBMY^m#~N)w$Bv(!6by?a6#<#eoerofr?7=-WyeJFj5o6( zN9?c-X3d&nF(cuI6>0Df;RO59UpfkLStqmi>NZo**mZT&&bw_0uo6?qLsx4Cg2f#8St$K@Ty>)P} zGD2-*_9F=!cw-?HbL8Sv;zfK2W${mx%ZwKKYYriolz9NUh)G}bQE_t(Pu&dSXwuh6 z&FElKs8#vVr*~IT3mT?jedz{GO{N=GRyx?18@iBCAO#{KdG<`HyCfyc-;&?lANqg# znqm5`11UUOXYr$Es*wP*Jl}!=ETrCVS2Z;-Rlkb6f)%TllbIP)Z6%3edK{vERevJ> zA`4O7c3_7N?0%anQ&2#rW@62#T<&XfBE$L{ZQQcROP;!g zpK6m^mhy_PoTAYip0KFITf*F1Dy_Dbe-+e`hiWw-O5c>55|JZ@d3LB1g4Z9pX+OW4 zc#DyC_9Ll;Ok|z^amrB5lRqy?iCN9=8|K-kyKr zv43yRllsn+TMTfXUE@u;HDGKgAlC}PM+}Z zRA95iXl9EWV_2dmL9@I0{q)?5XT4~RYZD2;h2U@X{)}n;)e)6VVrD;9^GcpvOaGo5 z*vewQj8O-XvnpX_E&T;5CUhl`DNo$4Wy2lJ1;OGRoRwrtnUA1Il|LYqZP!^!6fTPR z@1&8Cen92ju4x`N&@264rfq6U>ID$c1(JoE6Ra+=$8;%qrUEpT&=~hn+Yolfs>BUu zf^}E!x1F*h84r5E>ej|@>d9g$C|Ojr@FIx7OKeL_J`O#0due@KT>9HAw!pzVtjyMw2JzxNYx9=% zX%W%o#nLYw$+BIyvNe(T)ellKe?ndGg&75@>Z>qJOXqima7Csz_-hTtE4z|)b=Ywg z8f)gg%H;~RFp_?Tq_PhQC!R~ z))7W#*g_duuZ~YV&udmobVe-97)5KCg3i?)a$*{Rwx%pQ@c~ka2FmnyAGx?@3ae83 zjhuBakzKgGcc$y6Ltr7w;M?PV?0!VFDGr*$VDG>QYdvNi2w`#ShvwJ|fBFV;K1 zlk3A3-T1q|2<>1~Auxms9rDP>AsI9H))eIuXvcPv8yvGyNol#+=CgZ3tIx^F{)grm z|GC6okS43cab`^;(nL7NVNw)XY^~eV`O|gMZH>j7 z#p^b}9Sw#J6WI#>hf?TGq~;sZ>6Z+r;wq=TzD&J&?Kc zKrB%lmvxu46D$RB8wRrw1a@MiR#_AwG47OQmP9nYo6hgY>xXXMGBw|zMY-D-+B#GRa zh(NiL09ggdg@xy<$c-=x@5k`L@^;>$%lze2!r_3fvvBhafUKk)Ya^%5Fn=g%X*Ish zr{^8Lh0mLv(y@RlCM~G00`HnKryZ_yHsSmTfSryi*_A$imZvk4>d-W9YYr{k7?r>W z_tKV8k3yf&i=FF`(!rbE<8rtIqmoaDl9{!J3G4t9lB}_&EqxoK1-Jl0vh!u++Mffj zOIDn}27fjB{d>S5{U=aj4sFX2@#InSh!}r`vi)QeK2&+q#2az;gK@SO{)STCB}dg; zQ>f~;4$BIsVaQ;hCn71UQ-1w}=Is*PGQ{@EN;-B6-VtE;O6UN++N|V%K1w76rz1P? zt&9)M8+YE0lNBE;5gcRpy{n=R`97Q?ZJz{y{Y>gQVjb=A0>{8 ztx>);1bMp$>*#Z)d3a(xds1g(;J)ISV(6}0{c8Pyb#Kd5Q&m)3g0L%7)7)bS&+bwQ zY1PtlEux2&zB&3VG)n^aXEwa?Q9m;z4&+91iI{)2{7a|c5@@Dt@&{s*^-*dv* zR|12R*(gPC#kP!Pgxx``%2m(HJ8IQHr$rb+nw^$zX+vYG5UOA~GM(n`27qJ9)BB;& zYI0*{#1QUc#FRd2@0Wj=HCSTU?XpQ&5Q)txreidS`1yq%=(C!5#u*OmjM*whmONY9 z7(=-tt(e_Jy<_k+&?*qD^$wzHa3P(bHjt!ZH`TGfFF#U-*9fJ4v+<9MkfeL)%1~9o z9~&-GkoCnw=_E}R`(JL<|CAA=8<$31`()6$ihCux#5Kqlqaw>wCwph_<{0VElJP74 zKbT2uQ)m67(d&~Lbn&%E<0Z>Ih!OD`s#>&3#W6V0 zC7?j|{1d7t%P5N#1w9q@%HDs4rTn~&y=@{beJfZP+ZGCV?)_zLINFJ}agLE8 zpl|F|}4UK78tRBPrSYSc#KT2XS#V8!ut zmdwOH(;ekPkEtu+HN-=I$g6kP#5rF*rj|mI?OQ~xIc{}JuP-O#fo%)Y@`TZ^9k4@N zzkMg(VNMti=(v80c=`EJqVvg}_4OkMe=I;S++EQ~gkXO-CLizK-ZE^f6x$E-#;kh{k9VRFzu`K_W z-3>Xj2ztQ%L?&LjVLs7P<5)fvrm=7PSJMfyQ*m*_k5hj~ne?bQUyZBV_i1O>O|VMX zqRBhEB68Y&IcD6np7_LZ{nJ3-p8UoASj3?Yl%2u`g#oA(F92CggHH-w|6%LNQ{=;o zi%J^WkOb~lLZYjQ?Q#pHu=?Bvx4HENPy{Ogi@w#=vDkO5q;G5G1 zAA+x6m<1aTTJ9NdRM~?ZqN%y)IKi!@rJl((c?8L!7BE7=jgU150XxXs(3ODFh=X+U zV^Ql)YzL16J)&EFCK44C6QH?iO;D| zgW!RMs`mWNTe~*Ho$!7byeR6JaVh=`z3tD)w~7$DhMx^mU1JA8vuwRyZJJ<^_9i-&@U*# z_@$vE*!vH5=?hV}?rZM*`R#vzCyEJ+f0$!+XBlqGarYO01WPL49CBP6=u8;3IEcx{ z+Jr1PmN1rQ<~BZvgU#0eIt@l8k2#U%U19|~(-H>H&$^hG|BNXqf(M!3J~CaM{}UemXUju!>So&v z-W1!xHPU@hIrLmxOsmMZ=;sVoYAHn=w2?r;?sbe}OvjbJp;hVgl^tgS>z@^eB`f){ z=pZTZqPrZCUe#&!6o)1*U#MQcT@|RW1TX&(3 zu)KYCfpJrrN1y&l2Y(dLr5+)^X!qbbS>?F*5kL9zorw4U{NrURuLlZ|84v)}LOLdz zM(TG{nrn>-nJ=!m{Z9e@m(gqU-TUcz-P5a#D;^*4KAG^v{8p7QNG;RhGH$xYJsMW( zp0g(~+PbV!2?Hwe3p`>94Meh`*1J{uaKp`O$*&z;W=}g#?w`l5_gfDQ*!_k_BGFL6 zwUbzYa-W4+Rgt1*%$;hptNc4*w(F#TZBq~?obOMZ(<$)|!ywg4_4OlBf!5QDd%F$+ z^*Fmuv_vI+107V+t+0mK=D=#dG!Iy;kws!Emlaaziid*ad(SiQ<31kCnA6(0E?wyE zQ`g$XvOi8mes%X*pinZEQ&{UFpH8wbyuRMj($YO-iOminE}c8z6lq2n0sP34QkPqI z@(F!jX8Y&q!}i5k?*>})2Dqk&SMzR6x|tey19Lnus=CyZs;^wu)pP{0zXw)`q(GK& z&~;=;O3@A|*;8XpIDlU?N-Ie)A?Ya2UZJmT@?*J4Pg8Dh=((eiv$cYOv`1SSVXkVK z>|$+}3XE`>V7fl4U4|%#0e{aZ49fzkGe&ppcKa*Y>6k?Nma$H430RoNN@(A@{R5w~l$4O@xiRjhCN@u1OC;x8l<1U32%0u47WV_q8~c;DIw zXzSV^_AhmUf|)Dvb|0q#A2N}Ae#khr|L~9cxj2npj(oy7L8NGtVDp*>G10`_b5@?= zK2*F5W}sd}Nyl+jjc>c7nB9v@Z34DhLSZANa+>Q?k%s`m0d)=A1y&dlAi=ARqDDp+ zTTR@m_$I#3NMBWajW%oJj7WdN0r>dX&OdGo%Jn;J)CH03QAGO;SWyBd>%WY6 zkKae7I>+`_g_60~hPlxr?=|v7WJ1O5`)N=xKC4;0tD0&S;ZUT>J-6u#?5%R{5ccQ5 zL}4N6)9BUtq$X+>Ur6UtgZw^_Aiw8*=q_g->=lHyB_K|yz}qA zTR*w~d9fi5@tHj&slbd@d?%O!QG}+w6TW~4FytetX{y1zYpcs$qb@rsGgE^-sqnrn z?jfim#p~O5TgT=jd|Q-HyCX^)+m_AkRM1yz zOYyAFEbsk`Ib*l#U$eKY#7(J7Y+mUh|Tt9$0Igcg9=ro(J^y zlD0-Q%NFT!AR37WlwzdeBb6FFGechqWT=j7QUi)#s#ZeEyuQ>E>!D;p1g&_&lMR$J ztl;la(;SN%_U5R0hK0kqqcVnysYO#|WgHQc9lbiqI2!TU#iF;+KHo zNgYY4G)TA>>t-h^lw6*YH+Mj)Nt~h*)|*TH zO}f{bg*ER<-i$83VaejFc6=w=lNooCe)27HV+h#HIg)x*9#alV0J|cG>Q5psNTY;G zR~S~fcAmAb{nnDmqC&n(m#^r&`l;CGU=a7vUkH)j%A-vDkeCzal@n(^dd|y-Cc)HE zm0G1#e;*?aIsw)*1O_n(fva&tG40~2FYVK+5q60DHd>#lH`}()d4gw1i|3=X$oJW+ zYv8i886V6JO>_scvM~QJ0u*M^H@Op@3bkpV7~F8L-JcqS6t*L5J-66hiB%X#K9$H~ z{Mh)!e1vc|$X_E@&yO_EQlAv5p6&rMe;?L^Ct?nR?jE*3y)@YLOr1|-QFL$jzDVBt zzw94&sGv8h^JH7T=TZ2ruaZ8InfxOGOgbv96?^l%Pu zE2(522nmS{-_L&jgTB7VurjrI>j!u{bGH4uHjWVBOmZM2VwBGL`=}V!9wL z^^jP5H|~cOg+fmvDeQ~shKzgkV}b^XYs7xM=Kv4=+_UmeXG0f*7H_4l3B6CC#Se~$ z*g@k*+H8w&MAH&$u`bEtrBtpwID6NR2(_FP@PNX33Y^P}Mg{60c0-YnCH!E01*Soc z{z71gONje*!ngIsoiX0NUC6jGmF_Ri+?*>mChvHO9g@Viv4i|rpT=C-x_6kRH~5>D z*v$6|!&dJ8sdu&WrjAh^Y^|cL62H)DI92v&N;z@rxB^hYsdVBZq4bSNZ~#hUW^>OP z`O?-epp$&=Ou+m8he1^OUs6;y&B7RRy2@IX*wIqdD(&^a$l=Is`@`L%&p0dqZt^^I z;`zTO+ueSj9-sTSO?uwVr5^@%WEl1KeNCAQM2$Uc(?Xz$>}hZvrLC%D#l|@Z@ZzK@ zQYdOv+cR0QEE#IE^BD1H-S_TVB-y$77iBs#FFYCA(-z6)kCa>3@g*_z9if+0tEU>X zCv;Jqbh0~l=~H`Ts(Ld#=9dOMNt*k-QlEMf@{Eb>&e`wR_*|AMS`CZR>64H%!`16AVO>@;j(S z@jTivP#nowx>%k9TPcl&E?PEEE>X8r$3|Xp2F&mbzIge?$Zq^e-uvYHA9;7q@#c@= zdSj@^GyM|!3ccn2#Up}~bD!$O*Nem4oG~#~me_Oc@Y`?|L@rNHuNRtYrn>Xw>*c_U z^?yx?Ybx_CZD67N?aXxFAI`YqcB(5lj zoD1%|%}2iAsp$RdJ21Hp7%MubDVvr;68o8cXsN2;BrNCcWe80G$*03;$Q%5ez#@vB zN!$!QOG@2Q3QcbP6Gmi2QD4!^>GJBWtJJ6^17RIVpKwhOeD(|eurLeCN6<*hsJ2Cz zmJLpXZ^uW@(c(=sLH#vBk4%-YN0bCgas-MNmeunFYB8Enel>-`LIT733IBmXTi$@< z$zgwEapOp9bkx)b1oMU}G$H6M8qFGLVB9D$6;cxf_8?NZqe5k zGclIsskooVqz5ySBi|}9FFIr1XG*|>lCc@dtoA|Xb6(1!4%Lq-3_B|a8qD0drY!kV zPb@gowo;v>?Zq}0ojHOM3~2X`=+0z53;4vA-XmuBt&E*5Iy2UIuEl0AM+oSV(o2OL z%EmWY`7>qvbq5f-8nWIYSNJ;t=`@Ngg2Qt5dur;p_klgz6wlt< zn4tH9`Yk1*DHC=>p6Ea?dBW=E5ovrdYPrP5LL`KE0Ptpqm7JT1if;Q!v!;j^w!Akxb~20$AE59jiQqcp$G<@h);G}aOVurDdMw5<(Cf&CN3fW2jB;K zZ$Fc_r=+i3q_0g8WnBm}=>4OuBKR|%;7&)qjbU2*6o?Wsjyw%;bhbBLV@R8|2+4lc zuMZsrSS}2Sudas_%fBgC8_wZU>lkKaqUa+Q&xW1a=MBFXofa<3|qT`h*W+V2a=AMdD6b+ zvxI7j2qpDf2zCymE`bQMu#h1DCECnK?;m&V(*E8KIzbt8zrduO6&-SZ73gU76TFH# z2br|8smYXzman!p?B%)-$OoEgGL*56zo|y)k%~!rBWVi)1vu^ft3YRd)tue-Q))Yg z-*Z?*KZ+Mw=uUSK9b`|JE{E>OYVL?xqc31^0ktG!1I724p9sEP$A7CaYLw|>!xN`s z!_?5q-UGr9btJf1#5O-OgX$F@5RYCS!VW7iyPj7tmw8%hm%{a~9abwvW z<5V;25$oSt_^~wdQJaq#4o#tl_Gvx;BwK4#?-ZNtF|;tQ+f)hp()uyefZLot28XB8 zh8~vG>`|N$y9uG@xWdd0RT8U|nBJHJiy{am>wy39`=}`Acc~R>g}EUvy_DsMOIigV zMIiIq8yvMm9H)9|)`16OSL;J$l97j-e+$%ne) zmDM86>a#;puEw4tvK35kfecD^6+b-uFIR%V2gka^VJ)YwoC9gQS}h*cj?q$fYvw~D zV)-DV+*}}%L7VMq^=G#lH^P76iON=m)ApKc(T9(fjr;= z&K;qpAE=+9<;a;WU;dQ0YQNUHKBWI=-M|$L|0kzfX#k>m+~A8@ci(t!*5~ABjAZPz zqdc_?%iI%~W33h?P|=S3g!@4gbY)7$j%W0>YnHi4cR;l&Brffx;+pAYb~L(Ril!u_ zQFVNkHXrVU5e7h<_n^U~Tu&KwZ zxNh6Nk{RmL&wpP&;}TTXxEv$0TQCMj!-=Cc5bY6rw*#i)q950S*Cc#2H$`$V8aJmV z@LHcLJm;$H+E*DV4t{oP#VUy;o}n}O`H?rYkcFTYddR7L-%yrSFrokcI8$e$yk4Ac zLlLaI$#lR+cG*1sD?&;_wAc0k`g!=?8w_6n)yCF2y~&!N+R-B3lj4pJ!(##n9ATZE z>3C(k7_0b^sotO4!)ug!SBQ!LgPk!|q zY#@7Ng?S%464a)PBSnqc&NRlbCk?&p_6{{+@AvY^` zPwG9#bR%!oy@WAQ^+hL!6{WjD17^mX?}1;5I`x3fTdbjMsvE2<6$*g2U7aBVlHs$#&<01(fLPznx!>N@)>n;CsiIjQ`~aHtHZ#`pXk{`K^(@~oBGDc zP9d~~NcNa9V(XOWv7BeQgM9HUr&hjxT(=zp7GBfuV&9UnF8FDX;OHYBF!*vrXV^ za(>euS^G7~pYo!D!ejAfqF3RRsW@$8nidZ$4coXd*8w9DM3~1T4#Bj&iS@i!3PFY; z+UqnoK9aR;yX5ra-)~PXy##C1W2;3)s`-U)0xRrUe425KUz-g*j$6+iOEA}8>yo^2 zD|_?iBp7}1cpwdasqCNIS${A}?iiAAj3$;Dg|GR1aLBRM*pna`)jzn6`nAW&L=k;?8+ge;P=Yc~I&@3OWP4FO@uwh$g3V>cpzn@2qfDVw|px#tDD(l#{kk`M&Y-ZCo8 zGSxE7v)W2lT3VJU6(66f)vnzj7rjEY7L~Hlv_*FCxLs|r#|sHbUNEKcS+}S(O?z1H z?W7Bt`atb7A^QsN9t0vCQ%!GI{GR@I=3xI;!aq&uhT-T?SG9GWLUD->*w%;MYQel# z*yA_KEKN{3_4>gkW})l~zLWYrtn{>;F67PyBPW=kJ;PA7g?x0Up%a7DUsOj~nKgS- zgp?3*Gf`9Z9f4ewG+P0!EXZ>?K4tJoAtAz5waH9wL{ZA>>^%MTEBtjEtEOV$c1c<( z#=v)OytKBls-Lh9H&jhl_wON^za|5YvxNaj7L1W0$Y;NmG?3f~KGiVg4tm5@B8!^R zCyzVZNiQ=y4z1!XJLO+38D28!{*|EXQPA2wOa`MPFY*|Y>hqkEY2fJm3MGrQ?VQlB zidpmQwo7Ve;gQa3_e@>VRVVEx38rcuv# z3sq&Fn@PuiPCPoVih#8qtDOZW#eZQJ$TTwXc?lrk#{@nF|Sxa0! zP{vs?9sx%puTf~xUkOMxMyQ1XVj;~))#NHt;z)oZM#>@w>Uitl93LyR_SHTKS~^s8 z2XTZgmX=tW6&rlDxu%Jxo^?I0hPor#NL3$C zQ975CYsBb(|GQyYx2 zVr_c^%{yt`>D_6&Og1*~m9KU{*cE*#E7eVos+sVg5Xr6MvY=P$b=6P`$No6~2KQad zK?~wWT{JF0ka#j4Mu*2wvS6NCugN~ykY)-f)_0m0wdzEt&(q6oB0JTXwmW<@xx3t! zDauOj7q$^+7B13WCi(l8WH%Jp*Rc_&uMC5Ol zH*;vz-%H#$PxkdsB`^EQ@wC_RF}4bQ3tLfAa?#Rs6|hv`DUG@Eq+zZI7B2us^bPG1 zbs7XVmW?7vyJ~vGG-&7CZVaUPLI_*CLq&!Bla1mdWdHty2Q%K7DEB@YKynzN&9yN# z6Ph9-VemgDvc@JKqd+9nJqmCFN)|r-6?U^~VhLO)9u8dK6d6~#_r>W3)QG-;M1~D> z?R6SL_TceAcsoa~0*Q-Twkz%!#FpU>$y5ja?wn9c>I!?!IYbS-AAD!u@{p*!Ja*TR z@knGer`BIYDzPVF9Ms^VIedQ~o3FoIxILv0FA#PD-*8v#98=>3|I)Kkg9~l%k|=Jn zK6FEhOFhHdBU-yDgnYIgT*N^XQmJ?UB6W-^-WTcNcJr5W0c)6<9k zmaGad*ni~M9j7x-4;kIEN;Hqg_|5abuncXWxj|^oA$7xiLm7~TScmM-_1@-p^3(P_ zDcu{jdFh=2J`+vX8TM<*RO&o%MQ;5Iil$>(b ztZYBS#=@Ups6P8(Wn1JbSu}{<@D=TO29GbhTN95Ncdt~$Ljzk!Z=R~BXz5?^H;M-8 zBuyscB%8CRirYiB1k$-uoV)adMHuZcIjqFgGjtso@55a{dFnhd}?RP+`iBb`QWm8xh7?_d2BiVQ$zln^%3 z^BjqDS`&_FxE|ibZa&Ig(TK`{2z#Fn z7=?3=HS?7`&l$6zPRs5L+G8@svR#a3mZS4?q?pu$bjlQ2@iZ0x@;X;`n2Q%*A*0T5duJ@39cZR! zHTR#&v?HSyo}|7X*r;MU&^z)DMXT1cG1;`~6JSvy6Rl<8+rvux^oDo51#1L! z{sGtc^*=-Uk-6XB?H3t6ovEhx21G3bsvFNun-*E``!^e73-B!6s6&=Wy@cm^aE+7Z z4e`K{C{cz{nwNyaIq=W+?e@gO=+=BU1{4Nr>%X)E3_rZpsvodP z>^SMvtVI&7(X?mSdJK?~H_!u6E-|80qVaa#5LfcUDW6)+Py7 z>Dwilm}|hO7NATwyF!({N*fI2vu4^75lx)Ujt{2#pbkM5ntmzs9flMes?4)}d7Ims zn+RD!r3jsEw8ZLUo>J`m%(T3|KeN!f-DMeISB}DQ{Qb}udMifk#=1-_gvaM`+(_-C zYJD@vIeKaxC0DXx*ZEBIQq8(qXSQU>E63lu3P=ob?k8R$`0Ly{(s_W>+NG=UH_HCohG699N%DmS+i%HO5MT7N;Mf7)y=yl&~dV*M3s1@nucWK z!tQrNf5vo3m=Arf`#TKx4Qom(w%j{4`=V15#?_%5m^aO^2})jq^LJj<;@d7B2cFEy z=q3@*xB_T{(3P;f9Ye7Y&O|KM9zL5!^q$$T9_tjbQRHRz3ex4UNcEm{xTsXhxeqK< zg)^WDP6eyylI2fV<5<(qqh?`NW}T-S!+ zHzo|Mp@gpJ1mJeuLc-6J)I0baYx5PGISeY<>gRSgj~9{@m8qm5*4PcY&l{%^pOXFV!`qcqy%{ z6>uK_2huN3?EX;`kihlfUwUKN!VHaiqHbmT8PK_Z<%X=RTkNpY2R{nTtOb2*LK_ix z#+tt(q|c%4x`%q6wnbZQathu|vQ3ohKn4A)M{z6(%Al>)j-LEyAwZc$Hc17GbgCwI zTuaVs+g7!?tz>~i*Nb^m70soQxh}yE3g?$LNjc#jJ>@H*;@sZyQx0)u^`uXqyDfY$ z;}{9^U-L4o8N`>jBHM_vCvI|~|F?x2l|V{Rwg{tx$U2{a5YB9Ef`?qhpu_U>~u^N%wX-&Fv>4)?&gdP8%p^p09|Nl`;L&sS# z(B$I6HtS#0noz-1>>^Ug?Ztn9SF?ld-%WYXGe_W%&wECZ#jCtUiL&x_%S4-${!=wh z)-#z(>a@cH^ZsdL0O98u3Q-w1P6B!voz}!f zYf^QEn!^KF+Ox3y&&bU-QeMWOvU8JDrh{6wLeV#dSqQ=;1Nj`Ubk(AIK9K-CeYNFj zF4^g1?|Fi7r0Dq9|j!YsVgwdgyEN`Y{bL5f@;%cMUw_--f9Kd*WOZ5H^r>clj zj4$jTGZofJae)nz9ROX(z_2AGb#&b{m=c=w9{?Nt@g+KX?qBZjvThU0I^-4m#zSSV zOMne${V9vBRSS(G{-bqL^5J)o0JK!8ZbhaWUm502G9CJWTG35O6nG_c_og7)p}jIY zNmaT^k_kNT|JV0??pLeUs|P4E_tot*M_W*L(A_2A?OhwBtlR6_zp)tc z8j~`7o<1n%w^d}j<{VAi1%@i_XFyQcd82pdVm7$B+W+LCI#VDdKj4!zDolGQ|mHVf{^u#(n})FH&F*IfDP%{Z0Y0X(dvE3H&~i+ zQ{CB@l#f6@R_4=0PRuB_UB_DGVNPqL4#pDH5u&p*n}vKd}^O=G*hXtDOsTeBVHHg!Ac_~C-B<@98& z7I+CMkzNz`Hh7Sw1M&)#w-j#-?+g*VoZZ7wE5Bk}&*Er|F6*_lqOZzzT@dgfH0IKA zEB#`E&wHthBCEzzWBO8}p0|l}ij7;Pn!jrL5Obo6^$Yu+*s|vQJ(AjkD{%z}85ZdW zeQx7P2T^j6T3kcNk%Jz| zi+%FC+YfMzu~2`*(ZO;vdxjkflhT<=s9^cS8qa(-a*alDM3_6G5=A|Dld8}y$~E%; zq3x`q+H9jR8(do4p-|l2rL?$P(Bj24NU&lp#ogVV2vD5h{J6I`1b3%+p;RU_b2n?Q zX05r-^_O+d^PXpK=s@Srct%SXnF7HE=bfmgRUWH~mPJevc%^fku5>>w8)(Kwe+kxn zL4hAP(jqUU*?XsDN4HC^78=!;1mwrjEr6tfbX?}1<=P{QsO|Gi?^_X<;~Nv8ML@7< z8tVsUjlnhpISa`zRGPzG&f)ANkC7*F6?4;jbYohOhg*RHO?qzkpx43bKsx4cw?tYHp)$QR(L1Z|JtMN_eJLmx3ohpOVagSd$p`=*uHm5or`TgkT^YfWkk^< z{Q9IVanDN%Mw%OI^o~N2w#u#?5pPiV8bXpN`>Ln%iGHv64!fBxdCkBZv5={$`vJ4k z7mOQAuEk{dQ3;~Fu0@xTLTPn@_7Bh)wc3q(*$d8jE?nJ|c7VI3`7{o3k(-WWNq_2Z z6r12@O2b#lvcWBLG%c=arQD)zq##L?C#U?F7@c5Tky!sO3Zn#?AMKi+^j0spg|6DK z)cJDCb5p04XG~Y>AAmJSe$fNz)VMTf#jk3RCffR9i!3irzluba`4RslNo@;T8|iyu zGSyLK_Vgt_=|q>Vt@2En_`8g$CfB3Zd z=6CzayrQaxKy9 zvOGoJHSBKm{XF+1rz>6XcZb4!Wl`CJf^K)i6VAlGNU#LAFw1Cd!qiokDx7gqBgoyS zJuGau(u+0{I>ZR9cKPAw7Eo7J(5rRV`OG+`LRrG-P*7`8RXn+r$29cN!Uf8XM^|H! zuTD>F>mC&>XZrcH#<#qeFUFHP3L~-F#j1fK@u$e02)}1FOayWsO2!HQI3e6OZURop zA=Mm4d0Uq08?{GRfCSYk+QgL#$^y86%mHjZ>4MlV6N;D>Qa-SyuF>jbq zic^jhg&PoKwW$T-79L)adn(@j9G7*Q)>v*l=*p%ZAVAwJi%f>y1Xr*bhR|fGcPc(6 zN;-F{2B}~-=em46SY6pn(&4G@5c@gPRhhgMzl8+aEs|ctYPRK`j*L9!_9y?VwdwB&$dsf z!YCk)DA~l=Qpk?ZKiLNUyHP^nyrV{Jfth_F*%F^yq4GYeG6I*zgC%VUN}lpe+z`Fz zAu)q<*tUM*q$xZ1!LMb)$#~7pAfLxc*<dj0|4?~K3xyo9>^792!7IrkkoD|(m$by})8i7jtvw=83Pd&2?b z@ne&Bj)T=t6yV7XDX9^@B`l!LrN(@TMO;!cELPtBn+4JSH$}?lcfc+e@Bi}FBw=|wWgv#&K&TCKB&HN#eZNF@x&Cw)5DBBkFQ+Kwt#^t=HR@e zhP$t$1kL5h73(F}wo$2mVHJK_TA~~ieHD|Rsycz##f*5T7#EQ?pZ_iwcsqC2ZDX#B zf!}4jwsOOJU{sh}vxm=fc$qTR*H^4FA!%+w#(N0qn-g1Z7sYId0-qv!1gVL1zCDyY zq!cX#=u{8zN`P+^>)xJhh@6^%+SIWFWiB&!=aMU>zl>X1sqmZ+Z=-R(n$2jDAe|+p z8uNYI>}E3ea9ou)V!b4x9!P-o?B4W-DOET52dxwZqql5Pnq5mgocYXLzSN)B5hq8`5#HIEwc%K>oWYaNKmo2N=mMa3; zhG!@@1UYH*jxWiK9^32E|JuuV6fG2Xn(p8DmvBQTf)XZ?0Tk;6F9lTUMoQJ7oaOaF zzB|nHpg@591iF4_{Hm{E)*D0pmJQz`Q=dQe^7++P&vd4gZ2t|3w3Xlro)%E5+UYhf z#NKPBu*Mb|nL&Z;DfBI9B%#>@<|5NU4tV(OFF;?76JU_b1;3VWCdgJxU|YJq53QU1 zg|#^%d*wrIh9_hB#616e=~c_P+fbad&YqEIc$2(W&&T*)Lk8;$zc$hsv6*w%t_|Pl zvc3FqS7dKVliIlWxW^w@TU@iM_Vv)mDwpizy|~J3q;u}5t6Jmfe^@krFZCY3D~Aja zW}o>!x6*?&vIxD1>Y9M21sBy+OnG)~@4*eB ziA=b*gR!Dol_#!SGTW(hqA!P#E8{}V1e2Bt6VZ*FP1_}cq&Eymzahemk_GV7E>^{P zPjaetx$^F-OvWr*~TG9h-z=C5m5ssL;cE z?>1je$<#t=!I3#zL%Q)zgIAa8+#R}8$7HM9_NKfQdHu<4NX(i2P4pgs{W z@7GBbG5`XCr6lhm z#6?}*%98PEbR^sLSnod$>)@bwbY1&CXPzC>z9R>OGqR1Q`zKbbQ*O7ce}DTi=M{&S z25AVrcyFaD&>-D>p!%nQ+gco)mx2PSO+)ZXW@S-}{JZ&6kOPwj!1jxjn8Y`ugxw2X z73oNe4D500<=86Mix@>W9?GMN={Lv>1K#m624SP@%vn|kbFg>()yIWP3~xg(>dc{X zwBDgzRNsLGx%1kXrpyg_3Qk5@$9;y|nY#pQWOMiEq{u3Ps_kSvY2M|Az9bHO6~?<{ zj2J<&mojKtwshLe@c6Q^5Z0VenY^NW>&kc-Zo%zcu5_K z3D+EjyitK_W5)rM0FmeyEe8`Vx<~;pg1v~4 zBVZ5QsK}s{tIvGsK1{?XZGgLD7`d>4yQ~Ui;+HZvWJ=D&RjV7B3`z~4Cgy6RT})_1 z$RTa~etkAS`=(xCws1N;M{jC>*a+>HI2|p*Qhr50ZIxp0G6dtb!v}$u6j*cN^}BLoJ;dqR8MkMk zkliSy^N1`lF*PFKtBG-$+HwOUfRvVP93j9P_GTaqU^e5Y05)5;pFx@h4zXblYp(SW zMX}vPD-H9@f9*Oks)p1xMpS&kCQUKuKfU504-)cL0qpZv<6D4!q=2cF4?W_R9S`R zPiBKK%q}G$^}%XJA9Tcp#bqQHYd6K-R)z^P(vU_^LzN_|g@T99f2}i5SIrfrYdS3zhJlH_;&hm5N9Np5g>(UV0j$jLvHX62#*s@c(fl~B#s zj-}5ilvmpl0jurIhQi-&ITwwDC#n6$ro24zrj7V;P%RdoYuv6cy6P?dbm>4Dm~Dr5 z=sBt38i;3R9BnW=$KrymgfYvFM4H*k5Q?e@_bA&fmmgNDOut@}>(HU#`5i!VaZv4% zVum<@6Is0li?>MD>0j}q%jm@KJjeg$tSHrvEa2uI5^3&0%EiCv`Nizzoe*hHED%RW z@ETe6Up@M1UFdJ;7>IF+kht+qeO2M8rjt~qeYPAwi^kXw3Fd^wk>s{E{X^k#H;g8! z*w{|H`o+h78wO`;qF!_Z8K%H>r0lxYTownmU%`ey3A0m^&JTIve}M3X`ASGll=Xm3 zLw!8ggBN8gz$dD8QW8%K)Q0na=3=zwRSz29`TXI8hV540vBAj8bpL2`p@lS}Y8M)Q zOY{l{4JFuyuS^+ctBH-pn1Gi?a9Nqe%wCF~%VTzzYaEn(fjbl3(30wFPRb@t8^&|X z-{iqy`)2jkH_r}dtHUbp0@Vxps@(ZfhVzuWl|iw8jx$UIfYjAYN_RY|Ez=`D;KBZP z|3`v&@@rEQp5f%=I=bJQF#6(RTGI2X>f8E^28(fIdI|Hoixnv+Yq69cqi{24@vFzW zLG&}vxbG@EMM@ZAk>T2qt~_poh7PYQzh(d2y%p4oD`xPTae*F_nPXgI6&$e52BUG6 z^yvAn#V*YKih8OGT0i@>oJAqrqo5Txj!WqxX3o7be0lsh`ZmE} zo*^!dh&4!)4L7ycXcoqqVnQ#HT_av32jf7G@=RtjT=R`G_MqIcp$k>D)Rng^W_!O& zuWW9PC0s3GxL*^*8kAaJub+zP@+CV=sYk97z=;PKM*b&^<2c?y@-}CW%g1zstNetb z@iDUoP z)-nbrS5?q)ZJ<_NtMhrfh>h^k>NtTq=6mjbhb69c+z>)iapR|C_T%O4I{mzp{9@j! zT2xrrXJEd(fIQ*%z({0iT`5*DOh#)cuMiO_fSC)I9@2?oS<--9^C$G;){b_V+N!~E zm<6N|LJV(rA1%%Y&RHjeE^D=g^8WpO^~R+Y{r3pOgR`n}WSNjQ3w3{vfSOB!3O9|8 zp^zZj1gjJ`p16<}K(j`8_;wsp#l#(^s3eB2g?2p8K`tpU?W6>VCQ0reJj zpr4v8c@=&%^g=rL%-pv#upKIInmM98Y>I@Y6n!$YKq8gFs`wpL6hKo`?08rc*E01a zPs_K3ZB;t!p~GvH|5FBDO_$_?7E559zpEHP5?=-Zy_phWbX>!f@*fl>5^;)Q-><|#EgZ^ zY>rcQf9+N~4n~^cxW|HDZ`anezLQRi`D3KkMdx5MA`o-S6^iq^2C^J);;T@Ivy?pmN_V`Ymd5r01uP9yIxMV>+J3ne2%ZCf!O=Z5)2yZS>&V+dLL<({3_m3&Grf( zt7`6DMee#^ViRM~1=uLDsqpkYA2;&A5)Wln{is|vj8lZyJ@#i5+nuP)_EAk{@(7En zH(tpNMebe^UmnK-S@IJidxl=zo81#>G-?|zHjOg9lZ-)a83o|_BjK#+jlilZGW*Vd zfOFB)axh^(JwWY)B+geG21Lg}(MbnVp!wMYv8GaEOJaZRk;6S@s4$~=8}jT{uOjNn zjA$1a;8ADfAUXItugv+S`;Gthi_&R{_qjDrUtn_^HWK2gRry*o2RQuId4;dCKT7sU z0{-jWl?e+wXON@U-bcsyjuAfiQV^B00EVlA-7&iOwixKHDis&~|G0G<;)NdU8sdJV58S{w9W&W9;Xjz6$yWomBet_3)c4tJ4_c z5VhoXy46#J4apA)mOR_030Ms-^+$y&qX;5A)!h{0OP1?sFHnGWLTbwjsdW3paOKH0 zN9m~g1P%7!re{0Fs8(Ge2w`-_n@dR_dy~P2XTQd0sIWCyIHL~WX86imu9wQck|c1q z@cz?Qzk25De*lsardynx++Tk~4Ed9FCCu8HlTGHDO^dspaXxi@-2%yrQ6fMZ zjxFQJy#-`mj!0l?5q&F=`l7+T$=rRYH4CMRv^PwX{x5P582WLPVi0e_AW449-S3R5 zheI~pq5%JJ@A!~AqmWkwLPHN1Y{ESNrNWdd0S)nQwk;h6DySE+upT$9Sc=0^yD2nq zYW1MG zjT!Hlfha55a^Da-LiA^FnfQ43Q)nm8NcV)O}J-KHi z?b-*IJFuv&rhB3Wu!Im1pfM|6BX0RV(@o8$Sjzt_rP}(o|9I%uRHo7G8?05a#85#o`gK*iYL*zY$ zO_BJ%;m^4YU}5pJ2L~r*JU)_3rjfBize=HLdz6HG5pH;?HL?o`3S$#da&ixo-LElj(j?mip4Pcl0b&W&Fs~Tre zXUvn4|A+a-Ec#iWp-3+1_umFgtKKWLhv3G6TljNt`QDF-y7Om@Te~0sE6ROgYbEAk zVxOVziczo@JX8PxE6AY!^+x)phm;h@WP^#izRd{n4Jz>I{-7mvS~qH0+huJgeLGRf z$pgJT=n_w~CaB|WSqfgHRm!5_fgExp+2lA46?UbhFVXclpX{N~kRl!zsM{|`&W4ro zMo^=Mr>SWl69@fDKy%)}ty$I*VRp0Dq!EuRI{?X!5q1F!b= zGS;+zo80yb($r(>Rd;LPVL&-7T|zyekGnW&08+NE)8p4#R^}0+o}&8v-X^-y?UKpT;F zhf`5*4>C}tr%Ly9-Y%+n2x1go+m)6$VjIuGsDxP~MWCnSlUlA2M;P)c@FVisv%4#& z#ld8ExP9_PBfqPj1FdA5PQnI0;K2T>3hwfI~n-g-Mb~=`E~8I-)_&*eeX|z zapOM#CqnnRyll_3@i=XA!%_HCBWv`wgK}W>iD%FE@qB_CEF%ys%Pcmx;_qS5*h2i< zMuPsXf=EnW5ON;KdcU{uSwnZu+rDeMsL@bq;5Eu3_vdD zG7AUgoYMH4g-BTnyimzj;q-n71gr6PUkUA^nEZ2K{10q8m#eNqL9E{7TCSPHeQI6q z=&o4+>@-%1d+q!kePTclZ?$zus=Z?L3h(?MU5QlRcD+9lTcNRZsX-yuR_NeXm5x~E z88OWm-T~>kc6AfpK=%Dowx2Rh2F+iI#~Gobb?AyM@(x@#VF?KAL#CXyaOMw0Gtap((ERwUC@QhTW)47h4QzB zbvK2Lj|QMNEle>+F3dfwKA7jyk3zErPu*YCvN&viv(HrMBkDJe&ldd88m@lzD~@^p zWSCcJmqR6qrouV%>cta8+Z)c?CB1Uxndtg|3I8a9!d?P7bV!If3m_kLI)y4flbp5& zdTZ$qxhn(b^;NWVT~xKIZ_K?jlXNOSjzL&mMD=FViS^X#^mI*P1hfX&p@!Rbu{oqJ zs{m+W1!Qr=Xu>g+LQnLeKxCEoBx3A8{0UCK&R=6`TgvNx;a;*tfd?Z zFeA}u-2&q3$h;-Qsn4b5A16#4kC3dq4_@hnN6kPg*#THaVm4W6i8c~?WLPAmDUhIO z$#;vysM)#kMVZ76CaS$hze2d^(iwKD3=?DBpl8GT`HoBZXQQyHDOGm~_kQ7=eb*}q zQ=LP@#7fwliFr_JoSK^408cdhqst8;;DjkjjXM)#@h-R>pE4Nf9mN-)7@NU)SQ@CZ zS5f$UKp;3hv}oji-=M>#F-+c^_hI2>a)UvsyASoCab72yl1ff)`?JPR6FPgUV{_%~ zlTa6ds5{_TwsKp7ET#F5V72Df1Mlfv_$hIm21|P^9ieSZ9xec@CN`lh0a?taae-X! zVvsh-xg=<6XO_X5d(yow4|-15a6te!CV4~`A86rjzMGfaF;Z&mEU5=?w}Ik2;wCPu zT}vu@oje(7dH!jcMs{jcbfU6maGQ5)q^3r60_rq=AR+tMvu3dVoE#02kepUD0@JGU z6Nm*UrXyl-&}BtqmKUnO5@^;>E@CRfAK66n&54AvO7`d4x3OX3d!pG^P-Py;FprvU zhxU?1tknJ}%8}TYG~IlxfV98f`uscfEMxOMj7a78Sq!?g7cY`y|R2`2I+P&e)hRaeR znyzG=oSc}5Nk(3ww@7FM)pNb{!NUNtgS_s^bL*<5S|X-ec4KKGN7YjZ$07>Ug*cK5 z>UJ;nK616jX^pPnV#g(^ZW99Bs|@A^I${N4(^ zw)tgQ(N*Q8S}U&npBY1eNm_mq?Ra7~9C^VfUEA_ly`inWgP!*xJ)V?J4v@dxOgrN^jWumMp7X{)o8~XF%D?b+$R&w_p43lHgw9xeB&o73s8n| zUyUj)#Y;lFC=^N9N%B<;=Nuy~R~`0=SaMUr8^2Ri%xTC-a}A1&okvQ}!OV#0$MZycqQrFQt2*lw}*6T`*E7HX(*uoJXYq`hRvhB37ZPH znm$-1by<7ay*)Ioy}%Y3KAlJ(&t*`x#7f&Ji0kr%F5iEmnej}+c^r4Fzq`9*-7t9{ z3|`x|sg{=nwH=&}`D+I|oDaSIP#|+W6r2KDuhy>s4yhHOGN6|3ARz2C@{`O9Qrn z(85sq3e#+vkP*}@`25zuud&kD70z~=?jR9@Y)e*dak3?4zTu2VU-O!7qOL@9U#!u4 z$tHjsNI%BD>YsW{S%XhHU_&>baj0n@cWGtQk&p)-t8tJ_5DlZIr94ey5MV4TV-!kc z#7ga-2@p_>#XbN~4|Z<6ub;cU__PJG+AZvmVnW}d=a(2Dhn$J@jLN>HD2}$+qhV0? z?4Vb3F4x>rtr_ZwA$LoYLkd>3lOA;xpn>d@2&Tarpf+x97+GYqF6q_lB(Rq67(!fjD;oO|n-bPvOTz`K7YW1Pv zaSxW_mSynb&L}~hll~kS4}S8FN3b5LYS#01xEWPaM1EAslWV9*%I^rSEUbU9wkqV; zP_@jo{|VGg`^I0F+l}XpcPIo*r-kC~CPqg_N6HDdn>(XvcghR?)<0(s1wFa;c@e!E zZ=Y>@d>P_n^M6^>qK>m3j(%}o^gjD-oj&zV_X>Kw-t_w%uwY@XaSaD|vF2;)z1m#c zWL?2XC)q+xn__=Gn3);m&sIV=Kl$+vRZN=YXb4y5w=Gxe1cnc5C)5QQ`D%;_GrPu5 ztHP7|Z{BBRV+mQbQqIJat6x>`uIu$<4*%KQHSmgotVKtfm28T>`i6kJv=6B}vW8}< z>6sWDP5OhVd+E$fU21>AMB})HO@LEIEgE5ZkfyoBK4{{nVAz6pr6ibSzwl5EOH3(ETALM2*Sq;6E^_+Ds9H`8pMvWa@l6fA#>L}^ zn>vi~YaN^C(K;+X&gzF~Gx^)3U%|3PpL&AC;8>o@zk2@x-evy-h@(%@=dZC(^j!{$ zLEdbWzkl$lIb})q{G>4xCa&CmmAgD5=aBBD;nK|NY5Qc=-}#i3u*F36=RG=J z$?;W4#4orrKnZo^SxygHQxT?z<7Fs{Ni)-AKwInqngr{Uz4CfC!irXRF@wU;f7Puc< zq@-nA5Lw3oVks}uPRK8bUNnc}{$bcOp}8+^6B4}LH6*e4a! zJszITkdYgy%5|nBhu^hY+K{&Phxb<%eI2Ni(!|baR)LGqke@K)H{)Cc*nz2u@zL>#KkIf*mCW`k z{!@}_4G>C#QsD{JTJT;-e47z%x#M`VCa7+Jf5T0q+ByFUEc2iDHY`2$!@4}pt1}fQ z$^MsY0JN2gYlZo?1AMpO+M+d6|H?T785X`ZP5%SC8Y`u`Cw~IhQN1B=Ivrf6)U-KU zg9*;BkwK=um2CUmcZCEsZ}LywiMxsxY$`0$W|6jj?X2`J9v6Q3ory>C5H%XsynTyn zk(0q9&30!~w)drVS}J*y@~(L|hfvMfa95}GwYUgk2lcuA@kLsV1IbXNaycwC%WqwNJ{#J;^Q$)#%?6mK37qJ5u zVx$NnCzfI=mi+pfGHHnSmC>5qMoE;sHjIUZvSJexTUzeT0JVn3yG$B{804AehImSx zIYD;&#xy}-{t^ijO3QPNP1{b^kEvhv+?mzJ;oMpk`6?+nc8l_+Jldg|EgzWa7C)-7 zT2~E#GnFuhFbX-i?@k^PPpm9AeiI)0)m0EW)Vl^xDjy~gd{#-C8o?v!=k3G6mxNb* zq(ekuPS2$`%)^ieVYr2WGT7%|kZ=D0L^b~aQ!g0M7~MQ!nm4LJeaF_I>Bc6VpXNy$ znf48b;}mUE_6FXywcHgg$ZJ^at)$#7d- ziS0185};!6h8O!vd>LC4h%?iyqwqFTB?Abf!0(grjCH z3KJ(=63gMVa){Nk(?xTU zU&4pHnpl`T%^sXs0+i*Cullm3&IC)wwsQUG-Tb7&83Xy01b1Q?!3#AL_mHsiQajK$e~!Pd_vWRGYoTKRl(Fs74|=f%Hlf`g7f|y!&$p6$Vild0^K37u+b_fPbxc=_ zpPije3k$c+bfqnu65}SYoUvg9c_atcN!_&P=4l#|E4P{l7}!eQa6*sA!OZn?4pD@M zlyOCPLL|yJZCl2b$~%fYegvZ?LyNQuW{%~Gg#~y>o~ARq#v(;ca-`Y&)(Wu|1@X*g z;3Y`ibjX+|ZmeNj3o@@uW!t&?N1j~C@hlbMAzdD1xURw!55{_HmG5%$NoYE{ql9#B zxN; zEtRhGTE^kr;Qjtobma8O@0wHHRg8-MGVz)#^EBRJa+cXEO-i&%Lq$bHr8NADDsQwN zyJhDFpEM?ZE6f`kVG~VF=+2|J<*GOjA+j!60wgSN0^WY}m$dp{gHq^U^P<0@ZCgKn zY*9bHaM}F-nQ&V)Lko*IT`EAd4yc6tWH##S#8;^}bop_pwDS3ZQ6PNc^q!0oYG^7< z4dkj`W~7d-5}@G6pf0ugkQl_)P49v(s%Nq^*Y*#vMw{Q{`1kX(3+a#ft%I=EzrBmJ z#z{5)nfZG9zM@&|GM`;~9D;M@TqWmTN#Wk;_^_hqm#Y=Ar%MrRc?Jv(I6iUDGtx%k zXFjbvRiXiqCcwJK>AT~fTcE0o^R1oP#J9a)+Vy^UR~U7?`H?g6i!=1Ir)BrAQ0sRM z=9P2Jp!t0=ue!?a@aAINTo%(fJPNOhjd&f-jm_{YO?4yje#XRl&Pb-AQk#|09R|R< z!ZosMLI_{H+=M!{8L8U6Mr^4)Ei{?mnwyN-gHyqdLeKGys?-%0PN{qzbf@_Tcxety+3$gTeKNAe`1<#zB>&4sNMpd9oh58KXv)bw z07=G3F`QfMXy`wY49$DpYn;9GLJLSkK2ZAVkc5OQo*j)?0FETAq;XUIfS@)y*VTc; zCi$g?=S;MZ%$>EH=zQh*2srg=JsLyWadY^?g@g1Jc#p?SMffdW|*r5 znV{CfMbea-BWX@fZ=Gdek0Jp3xgd1(!}?36>!h=&9Mcei7tE;O0N=@U>1F$h-6(>>4x%~Bo&g5S5AwuW- zp%nm?m^{pe^mVAty!iS~LV9;Dcwg1(32vam7sZ3P6jpIrx4`mmoM&M7z)*G(Vpe9& z@Yat%<3sZt!UZh@$}*!Mj+3^{l?PYNIz2)#Lk!4WE8u<7=88F3+D>3ZBBXTEBDiN6 z?E{0>Hv$?W8|8zq=v-k(%qXPj4LL5O9!5^$fR?dN%};vD_vA4(k)An86^ML`U_(ER z8y?d%Wnoa7uz47)xk#UchqnAIU<=8o*ijXSU3nS>Xr%1NPudY7Ir4# zcb<(i&J%~#+jQ1;8R*TgAUPlK?at{v(AXPcku2s|geW|Po#BsQ)Yay$I|)tM83{ci z5*a-hzsQhwN4g1SSj>@SFY={dXVAYi!mf6e?u=b!H?ik9%A_PQ(z?{(ZhXo0qDoi* zjr;l%(~G*AE0GOw&!;K|%xh)FccCUu-sBRyv{Y27Ps0$s|lx3-WUB7OhPP&&7kx#1yKwajc5-M zI?hOCXI2U$D`M%1aUk%;q`+soJ?dx(m{>b`@mEcc*TdG;29f$dK>DBZ-+!$m>i+>M zYH}=alFr@{OkQdm-=ld+*p5?pljxsRCEf(h@vtpHa;wrQP$wRCSq3EBb5e3$C|?(8 zAZ}cQ_Zzd{*fZ8k9)^GUincc2Xvn?Etfc+rz(2AhmU|+P?UY>oqpgy_3 ze_=S5o;wK7{SC(wl>IxLP1MgY8?CjR_hof+5u;K`pZ{M{WJu zLzqfRIPMnZ#La)mJZj{-60&U`+@Smq7lf-Bm2qv_`f&alIERIfADfL4J-M>QU76S& zo-8OGvEtdjCWra}Z05Bvvd>9D`m5;ypDb7heiv8ApjqjM6dxOgsG&f_s-6^M2VR9b zwGeyuP;oP6Mnmy!OnEj^>XBW+FG{MUn*N=w+|&LuQTEwgfKhP~hjG)P;dU(%N(fia z`pw=NGiT;+8;R*jxzvYGc(^G#rQ{b#cEPs%@*|nAsf(}$T)Gh4&{v*5P$o)BvwW&w-(2dI0ay^*1+4g?_ z#Z;sbqp7MaYx~BjtM;LOxxp&+QSzx6!x*NLg)q-%8G+H@Zh72^I~xh(0&ydiQ(T2x z9X)TW|7R<<388H@hJ6L;Hly`F65P^}iJN1nJAT{pI;A!*3KzdX(7CB~HWJjncIYGZ zrT#=jtDKc_ZfD1Mp9BW(+ijgo9|sfD#~y6)wmYm@xAbQd%A|RV=MjE4R`J6?C=`jZ z4PRZ;`Aa3Qi&^|-rINfBL#cuxFLcWcIqm-tXN{B+`o4T+%Z^{M0mubH2j3G~ovz5F zs>S0}b3oW6@z9G|9TMQOr^A$TNAs7$8BOjyp@DpGzD|u5?dilcozZ=YG&G zxCrHQ*E)0Nq4OpeW=im#-9r1OJ+Kf_ghj%r`HJc3*EEpj*Jf4TTZ&Bm#I^L@0L^%r z;BxZ*4?J;gwZ2(;w1v#dMT;l7{~^#M@umQzsp4aC>`;8%Y`eGtR$s@J^fwyEZnAkE zk);)C@fDVp;8XIja53||hT3(hpF{cVrC1Q? z0GgKgY`k?$=iPNjqD)NRV;&pR7dnFNF8xSnZ1FqrO^JW78&!JrrQN*Sd`f+_q*mHm z(xRRfGeTw-O(Sk7p{m;9js(`qwi>koGFjbVqVxAWm9@<6kvnRam@Ea`KR>J1va#uAy+!Xr-Esc|P+g1)o!I;& z-P=<^5#qbg84`Y;o&J6f^h_2&bJCdxWjI*>w8>v!@WST}mYTmO8I|Z`bCRQDUVBt` zt6Vm4sbF0Y(vUZE_|i-IN?tKfy+gS<2Tjn(S6t#8`Fo}NyzV1^k*00@sRWy&iCrN` zbM|6*6k2`)64#TbCt)4C!JBucEN8}`&F6Ayw@7BBoGlo36(=%`;b2U=2M3K$I^(IHqE0`qL$wy;`=A7yGPsyaY zTJe`|Uob5W>ha0S^02tKW1hHG z?o!-IEI4l@_=K^(cBz`^qM)x3ZXe?d(W;6d{cqbBw2=ASK0=;|cJ9*6Z?Fk0Rp*xh zuNl9V=0ajr>)v0I)sy^ZJ&eh8lIx6p56}M^td?`G&D6XDBAvw0;CF=Oi!j^Lt9gJ8 zad!sFEhjES{So8J3c&#!it`=`Z*B7%*IImQEpq0K9eF zgntsDmzKu<2Z#Yx0dVBcu8v3UgT;v)H@rpj|E^#?Y3Fxau_lqM$|5zqZ*CT}a8q)3 zH`t)`nXuv#Y~|Q{t@xJo$d)vdFCdZ->@13kT$4dTB)-x%1Uq~vp$E*md8_awoJifu z_OOCzvmE9aKF?khw@@kGw^xIJxi#fU%G2qXo3wn*v~Nm*5Ehl(++v=lq_r>Aab<+JJGn{;;xlnNInDAi|aUi0otDu;GqD z*fTNvmd+YS54MTZ+Iwp4E$0By={yIVE{=B$${rAXWze{=hBGbSkI%Rwi{I4{2rNva zD`HOxm>)s^Ho87(T}k|B!;*8Ct*skr#Mdh_hWW>ocq@pgIgp%L`kKl6SW{fW@=9^T^&^uO=P5BffS*~jW(8_Z<rV26_|> zmA1o2-xYxC-dc4ErRq=`*6)IHT?iVs2i+!6YrrcFD3iq zH4nGA1)CPI$~YgU-i#;ak_V*ufDbgQ^ddDx56i7#!qq6Y_#XhNKvuu3v7BF1Rajb7 z&nT{{=S-oWTF)3%GwOiS{t9Fs4OpbAq;s)Z7IGGCUbd-Yu_zVIcv&Ru8;07=ga1hwUgDifI zotF!;d|o5wWjXA_Ply?bZjcmj8vHT9R>rd%%`!{T%TS<_h^CjJG85othBP~+|i^}kVK_z9$xXhFl{{Vz|@d3WR)o~3XoV2PAUW@GT$Kkv-^8nv&qtpY{fP%LUk=mm-*OeRD?K$sv zH=0JysboDd3e+bzDsq97>KL1)EF-eajIfYlDR@^A1pGlzDu8gFm=2D;7|$s6(BNgr zEY~v)=GR_TYC0N^M(VR|%-V1_j0vj9>xioKsjMNbBAfkPKw2#$<;(^pYGmG#OK#}; z`e2(Ydm`OaceI0d8j!6+nd7fyY=%aOZ|){#TxnE<5rLwyBg>D8NsNMsUSS*@PBzPu zna*=BC=LLQ!iUZXoFTHtAI;YOQmv*zGcc$_2m2+0@mGhm|r(z(n?Q zZ~)aspp2{nQ9J4KS|>qolt4s4wJVsS)@szMJMVYhmyJhS7Y``6Z2HwCX&&2C9QCph zT#qYUb(w?F;+7?%3JZ#8^q$|O1I)E*!#`f4vO=@9~H$z#w8 zlY;wgI?C@FAT-3vimZt~3{G{)45u;_Shy8#ab846d$=ksETO#6&s71szGAtm9nud9 zuAUl2Z0OdQHj&xcbthd#_{IrW^E0&pg86r8mY=j%1W+@p_G3c_0u9DA=o5)0c ztfLkxa#T7CmC9DZ4&tCdXw@Kr=!IMFV@pfz)1ftnsd#X4VoaQ$pH#^-%raC-BzLNV zbV_AVF{6jW)QI2(H=5x{0wQnwQ7L1$m0Q{N2j<1hCwZ?y?OHDJg_@YI3t1;jtuQ`V z(By5DQazfe4`N8_wH6iHXiTI|BCNg5ONNVfhy^-y{bNuo z2A#szt#o%ES!*qBcIQ0K`G#;NX5AS$ZY7Xpg$CJN0$OPG7OAsa>!OGYCMkgg^$EUU zK*CX|AY)_Pe-$RE{{Yz9zwhLAaX;WLEG^lJRFpE-*{(8-9xu_DX;~6@Lq(1f)>Y(k zOKH))$W@L=z)VG_-)nDTtCXQ0qM%Yf2lR3{wZ#c{0G2$ z7O)x$zU{+1XtZoX(62^e%E-3jn)aVe*o~#BtgNYI<4mVXR|bn5$7C%5PH-0L@p+-b zVJSqV;uu^FDz!bUMA@2Jbzf<+*=`^l@8Fj^dJpRW*i0rCAeZYmQ8$o)n`^4;;PBR+ z3prrpVTqcA?U=QM!Jh`%nKP4x`=8Y zV)|8I6q$M%jZ2ho8d}b#!?1YV+%3^-I|+V0nY702>08vZF-xe|6@8j`T|+G%-=6F37FCkom01vIjAFbp$ELTRG4D`^#^4O@r0z>5GDBqhk8T zSYzF4?ide}% zbJRGJnYJ;4H~#<-&;J01KS6)`M^b;qUL{4}*~_;C%`2lRT{8D{_e#0tIn6~4*>-D} zs&v~Eb27nI@xvaol9vaZz+upXxa8h);+2+Z_ z*A*QVFd#c~{AhEV)8Vv40OlyjsS}8y#f2gF0Pz>@xJq#V-)w2^=~;HGmk+1Q3r;I` z(6DV15{~8+$&IQR8~uo;#WeLG7teg96l7PrBIx((+v&jJ5f>PMd{6@P69`qt@wDwV zn>3pbY8TC?Ez*_HyHT_V7GZQFHN0Cw1R9;}>_|;yGQ}AX-~dWuCODkjBoPtD+gU!0 zPMf;ZBJ3~C7b`qEo^dPLw;bD~9|lB9^0Sg?b8d)Na-Br9aa>xchJa_odZP7a;sro% zQ*Am;TA-LYRH6EJgXKGMnV)ck+}ATcSd3f-YQ7p-r6gAnw;WXdJyelaMqOV-R{{{g zAa4ArPi`%QLYadXj+2h)SFy_iwrc{`FH7w`8Bm-$E7I;wH&g*@%Q7^y_9<2tRb7tO zb19U!RO=^Oak*TDB^IFqM|L`B)1~2tlS-}v9WUELNp>8xT{7gWWVEZ_lV{oDEqgmJ z35bOg$kI6?DH$y$E~<`>rqF7}0=o$=tr^1SDI2bH8n5kW~8B>(-cbt z%U1sYDnT+N-05sJqqHgRI(S58aj3c0JS3E+L3yB|m=Q|4JO(fn<==B|a+`?P{L~&e zymgx}(zzx!*HYJQW$c3p$axu3d3@i)vNmkqnyP|KBy@*-bn!@{CYzDjB3B8@;;1Iz z86m225CPPF8skb<`8u>O7fz{~;q`g6%}N{;?`qrQlr&go@s;k9MUNZDlF;2}SX>p9 zZYJ{-RuP1!F+jyVL8d~GIj7(cAhB%~=}0=oDd|~z%ZselW-}qky7y7HcRE0-3W!8V zvfEG*osQN+*$ipaMqNM}f_Bh|h;qQ&lBm^$DXoZ;9!-+OY}*|6Wi5*-J{bspoB#?c zByGD+ikJ$;9g1Nw3$TvhV+nTOea9EkhCl4sE?55m2L=BC%)$@FH0TnS<50^{t{#(= z%-_&tw=k7M_AqW7Qp5K{*N6&WCy<eO;9LmuW0eyb z4v=f919ilnoTbOrEm*)|D2C-P?hG6}LLsuLboP_bZn;w@rR;RdUbRqTGXo)> zT~M@i(HFnR@pt~a&y*L(390}GKoW&Mw8Ml528G8ytR11t9J>1^jddi>$C1=?aFgt9 zkgA=RZQ65{Ny`%CWO&UgMc`M1*B85jm?5r|o&I+fBY~=gGE?PJ5vCDQB5C!c+--iB z(PPu?&repIu^dWCjEh*8mm6rZLn;#bIH2kX1I+|5|@iiwP@xL$gWxyY7r5^ zNdb7kG|Xa+D%4Il8`Z;DO=4}sSGPTkT4U*_m21e$uo5l1H8XIucH~l2JhahcBBg?| z(z*)j*rNofvg4*xnwI1M;Q%RjAjCgt2Jh3WEIg{D~M~yZvln0X6;6S#Kv-(sYn%R!wfJCFv9`AT6$Q7t*G_Q zwk<{vbVp4|A<%~9bEB+EYA)oaQ9+QFb()1bt3|x_S^*S)jZ8c`Jg_Jfzyeb3ELlFy z700coNtwv@{u@FV#sDX4J*N~ zFwZ$0uI59*86&!5r@HduDZvE=z;iDhxkIEYZ`_vu7_fsc!U6relPP9uvk*x*^ zk+Zi@x`|O1^R4<+o2}JETP{@;dSps?M=s!9W3mMZ7iq5$TcF}|xqyy#hz9|hj-!X9 z=(l4qMX9dLDi?RCHjWZ4uwBKhIHLI)J59SbnylQ(&%IKF?K)r&1|ukprKDt4r!#HI zPLzV$t{mYpcxp8%RWFO_$)iQQ+kNpubDh)bp`+947KdaqNaSqA*QnBRyj+eJP>R%g zkg$;NKxCm6AHTt}zT)Amzf>vGIZa69ufzcZ7o()cpjvsgSdoNt6gX$ zc!ozJn(}&4mBlFI62BhiMmdp+1}`_2OahtrKEO~WMxWYqy!8rMkdc`8A8B^4@NS2rm?z9#VWEabjf{ZV%a+AT1k>DZ=QIgq%57L@kB98Q62DwPN9%o zNJkMhCk;BKH$eh`dKc_z5KP^pXBe1)Q-<&TIE^E zAU5^L(cyV~-DTsi9QqmF)#9hqjb(Lebi%6jY_cKP?z?2G+O>vtqsLo;BQ32UqEuQF zI7I=vfaP-2Aecb4grQEfziJ<38T^z<1?krU=$7=o3n7A2fxYTjDoI3?aOO&))fHWHUiopVIp35Be#M70!^Y{*$<()|+H>GUm zQZb8W$ThhP!g0_Zndu|TDiSKfB{%xv>7&=qO!^&V!>5o)%O|~4Mmg{`X9fVsPY80OTrYy z*4X?{3SsiY*-n)5-8}yQ9+ODETmJy_l*7F-o-5%1@@Gu88e2vO7H)b(U&t#1tVZDh*H` zSBZ`kgNO}@h^4Pp;#K|QMg1p-*|we%PpmfI<4vKz-+Tppt&TfyO4lE6@k6gNq%7$+ zZHXhtNTC3VksEJ!nhGkx(nqHP&vTqg1`UInU@qb!BZ>CAZ7(#!MTCln`7#N&qT>S6_`*=$ zVmm~7tv_ro{M!-3cE+^lpU|In?H)+^86M`Xfoe>Vl#>*e-;GY^2Z~&xgWrg#g+c<5 zoEs2CY120WK;jhh)MHM$cTM@pG9Qy%vGer_=Gjb;BAHe@aHi**GCX*pP)L&QN~hk# zSs;}}l|q;rwi1NQX-9H8@XYo;wCuO7Pwf8E?GDY9889EFU7KVMkCP5HgZ@2tF=a7u!3g@T7Q8>~lg-bpH=HKf%Dt{L)&+jfL zZY9!^Gka)9bQk`#&Ysh5#u~YX>`v8b_jrS4PC8Rpw=h&%EPddhTPn#BWmhdhaGAmc zF`Gpl%2Jqzu*^cg+B>*6a4_Ir(8i5(YvfUs7K+M<9=7o#xkbL7aurQj5tfT7F-80P?j+~$qenQ~Uxzc*Mt)JUzFh7yX?-BWd}U&M3} zw34M&w9l-p?svqm1X^_%s}$CRgfw>^g-0=4{{XmlOEmsO=B?jytM{*P`YHSC)4QY4 zHaDmDhaW4uJ)7}-pBMeV#p2(lE;DI*nD&A$lFhFk`f~b@v0=zo&axRIt**$nzieSn zNqVWIipa<91te>8TG@Q3JbHj+BY=RJ+R-730)7+M%GV>PKKX8HURAxz-^3x87cu7~g)59K3h-{Z>>BXZWwI9d$Y`L|1oXO=mb<9x~nMfTDM z3rXZ=;hc!b&eWbI)_Th8E~)AwE;s5IxSS`aNT&*7a+8=+&;J18=+eh-y{8oK_MHOC z=OFa~L(1U5eoOa4JAS~3Y;d4IDTwCOHq`8*25m7N*2$_mE}@SHo1;90_&~{9qrxL_ zGF$D`dP0)4b$5H+?cc%Q8%`KnRnY?WH7;Iu z$tiPnug`JZTF7J~s5HI`l^ahdjk+WmVPQ1L278%qktVkpIKjnCgbFQT3L*01KG|y) z1#DNrqb1EuFhf0YH&KfjeU?O*_ISJ1i!0lDf>Qd(6)~D+k#8Y_DiK^}5I}Euj-jB? zAyS}-5?TCxlTe`%Me1SfjdX{$ZQ$WCb`u<)>(c5ciOT00#< zrI2j7oQh2gids5Uh2JPEMp{KM#ZA-kx6Ie5YG-p(5iZ~-gSymf(cjnCZoPi~&sWv3 z;@G{P&-N<&O8)@zERFvFxgGFhQZ$Rx*4`#ddA_^&zkI8+EoU~H6)GY$$kcJ2n&W%i zdyvRrjEdA(;WYzPMdvqLe3us7$1J54>`@ZdAws?*Oa15H_YnHN`(k(F-90VgBSc9z zQX7O?l2E269mQl}J27ZAp2)4nw1#pSz7Ewzv~`A3?qzt%1xS)A6k7|8+F(Y7UUBKv z8U(G#c4(@SmbX?#M(d)Qb$z1!Wg`oz zxk%}adL=|<$5ZsO$!sSU0<_wRsjZaB9c>vQC{=_Qb?jm7};OP4+-jBJ8L}f<}Wb&tNyN&FuL~;(oVhE8O$0&~o?j#c!pa21h zN!HfJExN=nxzTIZnVOW|4S3!+j`PwggX2Do=T%OXoe176GCESDU6S7+Q3~B$kB?8{ z1!86l=^;!8<4wq&Ce6MU2alPpx0@RD)Tt@f_p)b1fKDV=1YrRg=ALJfaljE zWt(8NvM9C>pH8N>j+!8`2UVeS)bclGRThu7->_Vo2h)|;AD&bpy4%z0QwOn_qSlo;7cd`PQz4)1p|TPf|uTJ>m> zsTB}da+ym?okWv?jJisBdSoGwRG>;n5S`t5?m}C*eHk=gmS?wsKPD-^;ci2Dy1YEp zY>SgTok;|OVMS-6prFy%7aQPeZMOSzh!=C1M~uK;tJz&fXgJv#!8aby0FD@o_Cg3w zsT;e&#u3Y9#+51~tvnS`$Wiak;U^P_t-t{-Ly$|vQ3DABP$_n6k4rRzIXIKSfwNpAv(BN}i3aF3Z*19goM=8MM))F8w7C*& zQY&pZ&rwHp9oW--AfuF51m*%4lpL_6a?}zJC=L*K@a)}OqjnOw8-;G(ZkuzO6;jIfquAQc+&{G&^s2KpzJQ>5&b^cS@mrT=-rp@s@2>a3@A&B zDB?pP6@0!PbC4>FQ0}4uk53y+9V+HcNaTFYY6i$eR>K+9q`PsKIQ%kedOe9*f(NL! zLM$qs83}FZbhLW45YRxt+-;Pc_ffL+%~VYynOI`u^pc|o!CK+Nv)qrTtM@f9J|f#! zh^~E>qSsNH8AynNWpy^3e)|wIIx556yerMnkXo(6)^j=?v^-y1#SJ%KyGxqe>9KlN z+LLVe8qCxh%iv~foym}ETE3a1X)U-BPC5hdvpx`(Bt(=4v)#Z3JwrICa+`6jQ*zD? zFB4NUrm$-cqxvz&St#tcpQHPo%Xsz^lgKEd$f^i#I+8523p|?2^;6xXceIGfZ?7V< zGaHe{Rr-y?9j@E)Go{s;D>>5BIqO5{dAh^>3+45Q{hr^a@?QE&$?0d=zrBQ(TNdE8 zkjcsUsNIo zk+K|omxWSpA`mx*7+@G-h68yl;?uI%jU%r`#kpHmwb4LgC`frJ8t`S1gyL0g)|pL8 zjbz7oAiTsM2Qu(DsZ-^FeI2srDU2te1~rWI$?WC8b5+TB9^y3uuxpr(GO^p$Z{Xs< z?<5}+_&D+hLMmd>k*Y<+qzqz^7f)0`Ih-rR8Xz?Qw9QpWVVad7%Q1TeZ_@I~Z)p*j z%U8`Oa!3MU^8waRlEp+MLO z*;3GIl?4pN8am8qFOv+eaKY$#-9t^jM0WwP3Yg2 zdbH|Os_G%B@o-k*lg&YG8%}$^Y`iW}iK{%DZrW$X@`+;z?jVkI;=8F1(;+DwtrH|X z1~^qnaU(@*3y-DRM{%z&$F0`Wbi(HX5atsU!WG%O?K1NgjSpodZ^QopO$(vQXJ2_1 zkVn>ebYBgUhCo~-R#PjnVW4Ij01=r$8T@CgYNrqy^h#<(6Aem{bCOO`QO)JDIXs?o zH=50eWU^U2kQ;Rkgxv$Lk$`s{z<25UkqmF0?!fk81*%7xOFh3qz0}3z_Z4Txd~JqY zwg8S)6KbP^NeqiDEI5qyN?%E;B3g)MrUeGkig6IEP3|Yz^|qZDnUYjuqZ_`RS9yJO z?Iu@=l;mI1I9WDOL z9mFZ=l;4{2vDC2X)KTQ`$mftPzaaU7JhzW8ug*6ibUN$GQX{XIQ#iD>k+fd#O-wH31XiLjMqS9tW}=AH0ybNO zrriP?;?o_DbIir>y7Xt!-X&DhcpR7WZ>N@H*6fKl%674mgH>j!^@ic9`9q-8k|qfm z30-cV8oCnbowpvhV-~FuIjDt0w4F|-!?ZslWIZD8>ry)ekngcwZrY?c zqA4mB%_&>jb8|kX_K~4Bn!u_gM-gHg$cb4p&mA@264L>6kj5}o4qyZ?Y4L9_OO3d6 z)TSNE+Qq3nV}$6=opnGU~CZo5|Bv=74EZ!=4wPZz=$~3CD z2(ksFbQPXK8>S^QR3MARxtK4v>F=h+y~+AkYEh`w)t&H`g8-p}9@a&u;|AY<&!$K* zKo$#C5n`I+AU&TD!+fGc2>`Vn1I9rq!kwC6bZ*h5#JOsu!n*fqGcINkg*id)Fp`zK z%}$21cA?Cgs8fo{fo|91C zS%k|?qc%#HHF5UpNvd#_YEvR<>MKVn5R|VLH_)kxL39O+L9I|-PDtZ>PgFKun zz^==9tynb{^MxSDYNihRK&~V`DupqCDAuJ^YcZ?@5pvn3JgwwiUZpy1-*lkzUuMJk z7X3#RI({TQS0yp12NMa18=<8aW^U~6 z4rYg6H?a*nBI_NHBIPL%(mN(?gKE4SNzOKT72_i%A+(;aN5U0Fb=9;dEn1Ei7?rzC zz8QBhXq*g6k^caD+7N0tX6+fi;v_3%SdZ;GFm{}BFNX}%Y%W(GMV9T65t*^^)zRa* zMZn@R(&bg=*(z|h%|W_)#N!eWplnEei>$r0{?Kyy?=8@(=E=$T+URfD9jl!~KCMj2 zvBF{^+DwZfN2=ljQ3)LAixMp|F94c}Yeo%X(-M^8bL+;ewmlVCuBo>F0BsR6l!oet z-i?cKd^++I8<)o(B~p6Gl?d!gRx+^)inNHbD2>w`qJzR}fQ>LZ8$Jb4N zHl1$r&wY$>HqDH`!z3qKO|)$;VB7FWwAn)T1<@El+OCOlmrAInD5K2QNs;3kxzcy=iS0s>;dR zW-|ricat zH$bQ@^VAm^=@bdVU@<~AbobLz+%9uUZBDO3O9>EWTTDd^heUCt{_hMzf zJE!+Oxh?9gHbw}wi*%73Empi5tTjFouI5UQ73w1uA*hHuF0RF^i)i&$Tf7A=IYq8hI?3T^ zoKEjJRUmSe=?K#G<%C4vNbk@+Ucb0vWh|RYXv**);hEhUplR=E>SFA1wL&VniLoL% ze1Tj1J=U;frG=_oNQ(d>D3t)90#X>k#!x7Zrr+hzMOSxp5^U)aTfA{=(c7U&q-#V` zYEU=ZiOH$_G}4xqLWw(%#>+qhQOFIZ+iA1JCFD{r=P>$)l@~`CT0Qt%?AbI&Oo<*C z$hpeZm0GWcN<-B-F_QQp=)=fTH4cxJer<{j)ih53Q8)<%1WS)m{f$clbBCYU2xRV5sFX(m@5=1fQXco z``okHoKJwB8Hn<7))z}CP4|<@r|0vGd0J{1;pI&^K*kicUgLQ88rKa`0Wm}=^2`+X z;^8@Xyn9ev0zlK#T$q+5kI$3NL$WmaZgZRqPb1yDNs+{rE>bBPrZQC#C>4~xkl}7O z!2n8QHYl~7Mm00lq6XO>(ljF=T>id)01)~a9P%Wd#kUyknw}LmrVbS(ZMfBHn2RCY zh+$CXa2(XY2m~>Nh5+F(YJ91o>_r|&FR2ALS}h`^H8x`%%=AxVv967zrt^BKH<4;8 zrLG?VOXv#Oy%Ot%f#|km3I}s{72$YVu!di=t2lJT% zl~cBJ4yi2UaJ8E?8RaQqy32JLyiGbCFE>@8OCb&~NT{jkPgNsF5j)(miR-G_P zk=XBwNJXYRCjGAxnTlQaIDDB(8>0j1{cba^lb2C*8E5O!gM2o>DK-1XEPA?H4fZ^f z391x8O&zpVP*R?&udpIJkivitGoFn|%*8D-8PmX6WfptBm29S58tY-1Q_luPKO`xN zpk)OCF!W5=plYV-0y`K-Z*Xj1)1vyHJ)!wN8`J(u($_jF*?A7oSn?&ztBQS>ruT%j z^k=tL2yjfe>S%{X;2NtHL}Riyn?X{zlv_m-5C%9c$_v)E>u=5*K-V$dm26u6pIHRW zK^{fmayLM=P1WzTz59*ukjls^SLG9nBMF0=`<~ z>B(;TT*=nq1VpZBNzE-ft)06n+(rR9qUIlIyo7JOwJ;g{G}bQY)38 zH28j-PrV(dl@T^73)OAF-U@UZw5f5oON9mk)cn>rRMZ39&XCc4TrE+^unHbu;QIu}GpTR!2jX7|VTDr0NJ2DS{PpmZuTI zs5ZpIPh{im6m;N{tu}1E=7zD3oaMP&tAVt~l^r?#IOJ*yi7rR7+kGLZmR7N@FjiJY zX<_Q#ARQF7DN`xxR53t)P(7tUZ(8HMVFx_3oe6qRwRXmg>lco8#I$Cb z8e*uUyPYU+LO45-zTW~GyK<9mk&4_gf|*WgXBpYF$NkT~?h+o0gIRgG^w)Vvtd*Cv zIO**4CflQCR%|91UJDH8RJ^$tq@pp(xQ2w_ZW+uqPf@-FAhv28X^`L*zJqj2)1u>` zd!D$slUQe3>|ba|O|{9xKb_NhMN3g`CA|!};U4KnR=CdlUMlI^?hz1g6n8N|L^^Mb z8-CF;#_sw&x%Z8x>bBsQ6|G(qa!u~G!sUWH;($_2Z!}jGQPNVKZtIB?fUVR-*vAI> zz@R*50+gpYY~Onq112Wj9l)|74OC_uPl>XwzXOH2$GxA$%bsJWDl$@#+D^oyOX`t& zzrv6$zI;UF7XeJ;YKXbZO|8e5FDPTqSi7ahBT3H0nY%<%JYdb48tz!-(w^(=>ZC;A z_-#2+`=Qv1Dy46rE`f@OxFBN`z-Hl1umvFi5eh9KwH&Uj#%CtoLRwzVWwK_@8zhLD zbu$J)1UEH8r2wCO$9;gEL<9u8fQCImpKmkFhVDUSwW4VSb;{^kO+!M+W-KaNDUyr!2y3drha_g~Vy~Gdg9cd}dJ>5nf z_!hT#(d%>)%8-DiDx`Qy6lE>~89@;3_RT^skWNxN9hJ^Tn@ED|3fF62rOY{}6yFNl zow=#avjhJCJps1f*A<^%6o)%8HbzjWD8xr*9i+%YR-hG@&=*{_5FCQyJvvTSof6do z^C{GXKZ03L`rAGK0Q$;V{_g`*wO=Y4gE~uy{vJoH~U{FkLCRDBl zOi8Au?1UE=Dx;$%nwlYnadxd?5_3Sn1UTYfb(Pf%SS>Q1R+iU~bs~Gn*=vHfX5`$w zXSJ@`a(K4fE9N>$(h>n8-M|csOvNyif*>GqF+fUTFbGmvWr+7}(&w);T?jc`&cW%c zZKZV0_WuCipa6C18}0+_A7@SE)&2X|=eMiR+2y|dKc9R`Rpx60sCJ;yyLKtN`-RNR zOg6L7WJE+daV#Mmf@743%k4U9hE<7}%w>hM85woKNXRS3bjF-@?TcQn;M+(SlUZ4UF7g=r0$&riFbiteIzY%-HqZZ^zJ zpHeoTV>J~zXH_v{^mkoEk(5xlO}Zn5#BDbmygZhTM@jc7ptZ`;bF*Bltmje|akl7e zC@G>YHkOmjmf=BgCo2LvqC%QAdQ_?rXq73Rom4Xj@PPi~VhQsrA3n!eYR5-xNX3c=+yVN$b;X;I5&t|hp5+UJR2rERpeu1^8l^nKQMk=T2r$DIH92G zYW$GrIgvTNmCV_Ej?@RVru0Zn6AO4Eq?V#cEISssL%2}ThzJBR_omrxhY3G+QU`>^ znvk}ynn|?Se)DwHMbw5+k6{KypupJ%rNGOU=`2XjGrI~@S7eDJG)}&@_E`ijQUVDV z#*1OGneltFsS8!xR9e#)W7fN+15P(Xh1fZEg&)+j<;5GIjN1$&4z9ZaU}^| zB_Fz)YlsMfD@9t|HgfP2k8uGxxJDH;vebUjw9tg-IoS#wd&(N4D`b2TY)_ZAL85pL z6J^Jkk=guP)@J6;dlzqG?6g?UT&~6CH5ygf~9 z95V8}Pc*2=@#C`NOk2VS%iUC+>JJEo)XGEV1w7IfR{@2)nR5+#CZr8oE)tw6U_4b? zo}1Jl>2B!T9htSqb+y7Wn*2Q>ObPn3T-{Wp$0~BLCIOaOpokB&FdvgGWzP@zZLTh6 zpgL-0s=8X@de6>IxW)G`NG|whB_tIVuR2uJSg`2679^pL8)`yeN!q07FJ}IJS+X0S&&Ws@J8spobTi=fWbTk!&O=nB>}*7|*0&KZOwvNM4&QULp(Q87mpv9X9?G=T zoQ=jtc~r)0Bs$fSOcd)>LoW{JrXphr0Kg_SK{0~w8iu3kK(nU?g9g;S;d~91K(Hv} zVga;b#HtCI^vr}EZX|aaL@cy~wgoCNsy4{p@c5Lw)OD9(698jZEi(DLIhJW}*QIT- zoBLFi*yj7=w&ZmxXP)i2A3o)7B({>I^ng~5lu^`CKVwm8`10vJ$Ac1&-hZul~0Ktg=F6)#?NXODcLoZ=<^ckO>Y+^6<%!M^te3j!dwKq4}}LD zY}zd<1*b_Zpy{G@{G~eUC}{EfX%{ftUL4M8yw!DP9qq=kofO+94^q&1%IvkhAGOuJ zG)Fqy9ZxeCM-cp2_e4}XdB)z7lNyhdq-Au4gw7+PEuy$581kcZz;c`qu!orK?mA0q zqc>mWwMzPC&llM-!MA|Eq!JyE-X?llcBeVq&vF3`QVNlsH0pzqZjraB6lyq^+=k4y z965sJfZ2v)W|N=ECO6HV=IkR*tqv_J^q~B*WyUO|TwUYd3%0V`Y9UW~I1Ie5jU2lu z_dym=m(2M}Zxsyz{6@8Q=_44I#s_MV%S>r_iY1-)c&s-#cU{wJEhB0dBOr-Z(cud( zWven-D#`^pMJN3h(i{SZSW*l?s#WIf&l#VH0L7*pBTNI9h@-C4T&sF6I~UAc?e4N9 z#vgWOKoDZkNI2#UJQTOe?^4BxF;#^MTf$k?J|w%o&)?Omar zP0&^2n2$;ef1V!~5XiRrsafl(xp&KzVbI{8rxO z3#OxSwA3{=)K1tnZMywd{2wy-^4_jG%p^2hD1EguEQ4nu>w=KWaw)CQ9u;*(hls5) zR-cQ@+Ynd6jEfr_N)DiPyCt6$n1iCZjU=>Pyeip;E}z=R$1v7yP&jfh9q=ZlGMu>u zB_ZFsQeDd<76#=gfj}E^+?oIdF7CbfghHu)hg!Gg{T^fN`TopYCi*7b9yKku9W`6B zCaM|RVSd^bpEBXcTTqrUaWlEIuP=l45<=0cI+6l1M<^kyGmA`zK`V}qVzGosVu5N? zEDT$<o=Xd6$*wl7-IU|p$moYRg(IS%p`t#DQ=XuR8Mx>Im`8*J!UAX%{Z%%% zzrwAj{G095{8eByKUS&MExLV3uJYg^M;N_g>0(&Vx)}~}Oj~V&t8~dooGM31b)z@e z(D?WcO`He>s5=}=ASLND(L7hCHLB=;X1ajf_L~_S(3Pi2>RN`@vx9b1qy}OGb>k}; zAz4tZDvL-)CvwH+Lgf*-K{>?68k-!zF;RKi+G;0%@f8Rr>8Fg7@-NE0+p-B-*%*!^ zXOvux@~_h>xT>_+=u4$Ik$B<=K)x;Az@`EKl%gHdZPZE=l5}FUZ8s8Ga&}T>w>y@R zCMQeVI-1igZl>IOD^14~q%}e=c;Ht=B=iudcLQ`Nm%~B;V)0S|3oB}~cUo>o+I?ua z^_w)N$y^*uC%|%A^}0iby;;6E8((dvBip%^ng0L??G#m2$*ikA_}kvIl&#?{HkcIT z8iyL89lC*A)sotk&S)cY_Q?sMT5}rcQ0>a;TyV*Iil!(%9D z6sZqLOsO_AdPOP*YCa>^B0H6|<}ziN#whCIkhG7)jI;$@LtmyKK{-U^sBtifN&!>& z;i;W?YYNL}rtj%4jY*q`KtKEOx*q8ry7>nCkI(et#~L)+m6>U+axu=J5{|LDd%W1m zP=nh!or@WAvRP)VfXPwWN4m=$_t{sH*3h`j9v>ro&Qnz>=ozt0^vqI6c8Cj>fV-!OYkWLlImEAl&lJNWG~BvVu&(S>o8j=S)PL_$>uA>8eT%`y_H zLZONuZq$^_u%oP$@Y`!VSF&YcF`*VlchDRvso*Lh5+S<;cv3{5ARagn*hgUy;Sc~3 z5cjUqc4c|3A83TmqNAS&Ol_yUZJOfBXTVfb+=fJAq=~63h>Fpcd+nA1#kUbEka$F< zDTf*XTU)ngM&@r4eq6I_5W2jj(NF4<@)lP2ZPJw5<%wI=sw|{OtvLButLQ+62ux!) z8-N?QDVVLI9HJ!RF{NuUb6Rp;mQjhTmaViU!3Zd*BKB|$x>DZ4k3QB^_H;y6Ns z;Smr8CzZ#^UG%KeJtG{3rVa!mzFaZ+K?03xZKmZnWT#NXD^rZWo5jRR67|W-Qhm`& zSyi=HG~p_}9SiP!;%c{cgU>!vtBXk?TBS3T4vL1l-U?_WFpVb3TH(M1H9hUf+t#Md z^_q?@0>E`VO=MYH3DmaUbXfGl#!VdiBHWw|#E#`@wB73}#6#i)U<$Ow!oGmmYdRYa zcZ)#b6YSA2Y0dutt6AlQXyDG%A_u&92KHvzZuAsxUR8X+jx?7u9kkj{XQLz}8@*B% zmypnx1dN#N02}3T3HAqJiU491a1bMAHa~MW`7q^RTV9RxQY?*CA3E#LS)TuQ9y8)y;7Bu)f#I{s0&D@4Zw#%UNK5P6ixz4hb)okZx&ukmCU(kYh$@s z_RZPwN&;Y9h0#dvSe+r697K<$I)_k8QfkWtT10v(u91{Vjr0Pr9F6Atsk+oVq|GA< zGXciy?|<>uqWXn7rdXFZoX!?cV9(xZz(xoH_C9cAQ(jEH4}AfY%j z1sWy_fZn8G*tv52dfMq}s4~u(7j)6PGzjY_ne+VmtXGNgSsS8oj(|zKns2SWjSz0(xcfRJt=G{2r))PjeEN>7z(5Cgq^3t(t zAXjjpRPfeclswJAPs;F*6xv_>Fbm-RM_QGClwJeHJ4JRuYSu|3S%zBJ?aw`J36pKE zmQ#@9rRSus_EtfB=T^*BM1?AoYU=v+C8R+)+sCE`pa-c;40Md!e1)$2C%d{GhIgbR&sOfnI}Fo3-0WMy&t= zkWSR3s}jmmex7yWsp*e#NzHpLOhZ|b+Kwc3H76RPV$nnvoylniT041l=u+{53i(Vt zKm|9%F^3v~F>6TK%ITvQX}M$8`AXAc#l*vBFA3e0d#pKLv(wDrQCbmskWiOF22v?0 zoTI z2@NIM3a-+vES8(x#WVP{*T4dwh=z!ip-iO-Q0;O0B`sj{byV`_&1Js_SV%LuBJ7-V zWQ*beAPS%gznQlIIY=W+e2P3@8_Trw(N0U35v^+S67P>r##CRNkl6BygCa<{_gi9I zXrr=ZVq_gDO3dYWN4SXfMeZfjaGl0x(A6gx9BCY;#|_$ixM))5by0RbV0l52E3#Wq z^iajlJ(%j{aW_omZTHYEB&DpT9LTFhMLOYktcAowoVACUQ1q&79*L+nm^Q-suoyp8 zT`Kafg?n?zH`5sRX$?Bus;?&RJa)7Vo!@_9Z?YNtwK|t z#~|SXI73qnU~iYP`1`hT~p4ba;5YB4U_CNkj z>L~EINxC^=9p`H522gp=t|XTldyT-T?geE!i!CLig3PVVA-y5Q-KJ`eH$^TMr7<~; z!e3VWCv>s?9r_>t0QNJI$M_R~*n3m3y(caj;bRDm!()0;jK!KkaKVL~=ewK=0 zOf5nkn-jF<1X`~uoK#1J0*y*$5_1Xhh+~E-qpGYo6x)8Icaa4{Xar`&@qFUuWii_R zp6hZ{Z#R2F&??m@qo;?UANLl~}rO-Q3kkBI4pyL2DiG1y{900&m4-ragoohDcZa#HWzSoN} zbq(ara9mT@Jc8?LswKGFN{OllDN?E>D2mp^$w-Ih!oGoQgwr=Of3$hVVx5k|QC-O?0f4wXT&L#R_?X zx2e>nSjDOpORf^_t9E&2NnT8rbNb~-jqKc;B0Z!m@*Yc1Yo1Z0n5OnwT3V_~bq>g; zYM@isF@QvcFqh*Pq#%HROs>Crw%`7qS>W1UnIDmSp4L%i$jvZ-t$n-V zX407LQ6yFop#(+5Q2^*CL9a~wBe(t@aL2h%!Kl zWjAQ{@fcH6HB+oq@0hg=sG=MKUIGn4F@U@vZT1M4`~tf{{ZOmx&Hw09{~#1 z%W~5lqfJapinsT9*wa*Uprf5+JxbnbJb^bp;z(L)W(`fS??hffSFU6grRrqy9SXz{ zssq3WEg(JObOP2_QS01azr2;rTu{n6I7-YM(xhww3c*a1wqA+#4NWOzMmmbyrdlu% zM8-gI({VQqxR|uWL<%(~g>BBl*&@Z2}%cMnFxlY|B3+}y_ME?L4s6(%_gmTbi zGK|Vos3Ni5DDM-J1ZUoSd|b>M23o&V<>k$fqL09V(?V9a4Y^2ARuPph2xI9ia*puG3AO8Feg1 z%H&l1Q3w7GlM?PkJmi+rM|<~2KoRalN5dZB%k=<=00@SPNSdo@c-CM@agCs8i2*Y* zj<&O%sGllaWV0e%1KliKDB_Y=Vk$GN7V5Fw2*P5nQv?YO%0W2^@_-!bf$#b~Ud^OS z_EkIR!>G)NpAte-BHc+6*(deGQpmTVIb`*bxRO;?6idr)paSJ8QW^^Lj9U$Zo8d{Y z>2?h_eIO`S9;;c!NeCSkP*wq}-UUPj?(H8B_qQw*`>+n2DzZ$4E$SPm!|N@b%Qf#x%p7QI zo2TvF$_$}hXBbQXQ8wU%IJpi|>|M?T0TPsV$G2FfwUI2Pa_neM)hx$IjVBP?swWKf z#ZA%5l#=6Z6bf>ax?YIIw`yyzLR2*%r|^Q~Z8mBUq61ifAbOsObz1#f4xiEk%_mES zyIOgl<%zKdQN0V^d^Ay83G&*SV!8sdtaj2yOGFbHjJAq(`1nD(M$>9F0@ZZ0&gynM zDm-b1oa;+HMNm9b2ljugKq?wbO;%5s>e z4f-6v6nOYAv7Wc>FK@$88*J9L6TVw@ftbj0EO9;FWwcHYWQgWjY{^kEQ5MzAl#T## zD$3I85&$@W;8wGs;_7xZou(534Nv_|u1&9Ycky`OB4jzGI+{(KCda z)gn=jSwvI?M|c!yLb8Z03hhcQku^hjZ@6i-L{Ch^m;(p8SJeAOZ0>V4oX+-nTKT-r zXF56T?sq?_mBgtiD2SVJ5dQ!|z54$Ew(G(^!0I@R8z0mf<}~w@RHch#c_1J;*O5V} z=g7LFhJ=coVXALJ7d3!;1vk-oF}hx@IWmUBBHV zpf82iV%lovQsS*?n2Os2FBB;yQ+B(d6|BN4E0Vf5P%`6^Lv$RKDUe!iM#V!OnF2{$ zmhGaHO=Fp>_S9!chEUYR_Bt?mO+yi1Cf?gDKSiO!Bhc$HYuSAq<;y)%K1Ll1?@ zF2{H^8lqaJqD0{JjbC!p@!t?d<%J^!_d1?=jTQKnW$Z>nbl?I+ad$fmuDG^h35-!S zLl~jH+yVsw8y;(mkhaUeZ@Kj?gf(hTx#|nAtfM6=(B;OKC zi^o~`cO>mgNN+t;BZ{+yk*TzjmJ(980IGyqoxoEN+mv0#PTp;z^$P;9z40ndBB4lfwrK<)v!Za_M!RZ&rDssnr$Dmgj_uw1Z!T!$-r~d#)mCyeGffx@E?9LA>TpJmy>IKQP zL+2Y_o4|crdp-Eti?r<;Yb_YvMaf5z?c$vYmdu`|#v@ZCFeRlcnK_)wklaZKNZsFq^y*#m?=PEL|Q4fH6YvqiTF=TfJhkY*IRn_ zpQ?tGIe9wkq=ZPnRx2?Eyj<2=&!sFVIIm79R8tX6rmR$CoWabmM8>MVxaF#Ix0`Z9 zUz&2W+LGYWry2UZ>SL4DQt6VeM=uIgxB3Z@12QS_Kf*V{xCt3*>x#uz@o+L(0zA(B zF+`pn5h+WsnBsE?ZAH3htsYH`Saw#;YS*Q#TOG(vCPUgsY)aQ6MoiZfrz;7&=_%I} zDpMjTyxAeeMFNAB%Ghr>>H(?=!i{2cLuU2x%GPUXk=f8-R@gHsmO%56lro|L&}5d4 ztt^lXZ#}vkL(Bu?Y#Z;txOQZk?39~I*6K`}--;0YC~I47!*02TlW}3r3{uOYUJQ#DD}sYvu-ZA>>Zvi>&ov&3sw(Ie1+d#H4RevpmZZ~oc%`pMj|R^e zbU5C`v^jHX#FE<c+}qA(RXI&y5?zurP|L{48>|Ts zMBGN@bEzJoh4B(cT8(dC^w+2Weqi-`{g}GNuEo~5q`sfp!nUOS zOSJg7*WKh<^293@$Cj-tHnkEdt)qZbT0|=9#HNE#I4JrhDtUV1en|MFW-HLWx7i_^LRZi)WB58DC+>2eB)RI(z%q<&rC&@G2sH<$6 zry-3@S3E+4P#b0g8n6W#bq+koA%WvOcUGpv%k?&*$!Z}wQ@iQrXt z0SHt$^(kpG-2rF6zh&tGkjy4E3PcK}A&BN_kUEJq&eJkqT7zxgly7#n5fs^adW$N= z?{*KBYdof?t+Ag+M@L_+EJS5PsD`-RlgQm~_?5afWaE@X2nG_{98r+wG?6X~8KappdXV?@*leddA~laB&);sv4osv3Mi@08!gx$w2mp6CtW= zRd2WCi4?klix67O4<%NU8&Ru$$x&%#WqBWk_uR;6$i)K`+qY_%yvDO$foZk^iKvFH zz&beIJn0oQCz_!HK@oJN##niJ<|nA)1sS9ZQkWj3bdK*^Mp<7+5Fd)XR7x$ght}M?f(y9l*={V9nycA%dq7Y7n9juZ9?4JvKRa*N!9>42P7; zj%zZ+d$!$0$cXL=Domx6WneDjm*xyaY?Rw#P8wgfDy-~5vrZlz#(=e8tc2@}5wBY4; zquvehg^i)0Ag3rYonM0tm2x2TaT#BQO&C$4QxRnd5z))(0abkGqg2&tl&2_^^uo%T zr@OR3)UC;FE>YHt;A`-6wnjy{hDiE(UA&HWuY!)ct>W^kf+G}Bd+5tXAh*D$0*Q9w z0|*F*zfKl+sO&2^Y8Mr=H5Sq0)7CXRm){a2rW}y2!6ho=Q`^&YioESKui z;IM|^I{~>-2?DuXrgAzR4RSSI4t^rx>7%E`&FPap%GQ-N-L8^zV;1EaqYlnmbV#?( zR@2%@dp(m8QsOeCM{5v)mXT#8(yli_x^E3Q%;syl1fU}9D@6G7?LZ}c5O1SU2%h=} zS=^jkmyA>343=^#$!X_#PC#)U7Fq9#n>;BavdW3yVg@1*k-BW|AH;fP(d0ncJv&XmOXt^MWgCiLbpayZ0Ej>VA@WFw&W$^+C z^2DbKv)Bj#6YCC-$ob69811WNoc9RP4>ITBS;&I=D*tru6C z0C5=odIsh$I=|uwX#W6a-$GyI^ppMr;3T2_Jn0CJx&?7RIxBXu8fRT zc&hO-1p4K1H|6VdT2)z&+A-212^QHx$72D_#Z1SgQMXWqI0)1+>&vHwvs$&$Oe;;B zvAkvto5k%$j(O{wbh%p!u0;p9Hw(;IX|;tMQIV3D&W>;}bLxqlf>F!0XgS>Er$U_Q zY3Zhwn%G^|!*`E%dc|pg`HpR!a3xgu`q`(_&2kf!>fR0}fk=psh*t=rpuNDZO4U#s zuD)SgbO}wZyP~L5ueJW%gL3b0V&*PMn%FBnoh!^vM`U({Da1}vNn`+uQ%NjoBn3o- zrHXC(XeX=`X_&O!d?%=ID2Z?vsItqG(#l1!eN8Qj#1L+h-)!>Dp$vqhI$X>+rp#pB zeaI!MBubTC#z7>8-#s%fE;8a`w*h_rW}Aks2Tz4stw^vaP<0lq-};x&->CjRuV-Jy z*SD*$mrcE%zji&}v+-~i(%6YLTC@v;pJQunT)taSPm3bCMq^bgaw<)68KpKe%th6Z zH8fO8WGtrKa&Ejd#Kmn^}LGnsl zja9Y_f{+GEkznW1P^xe~6OUosSuOaOOJUVo9YCz> zOD0rFnz@}m^&L!?TFw`$bA1xi zxwy~I21QJ8q{+f^kuF`(w4ce-UH zsP8DOa7Q^3)r@77V=n~~xQyN6Ek@DY2g{pbp|}N!th(fTRb+x;sA|w78-r@W>?T=J zV}-S=O^MT6t_IG0;INLa5-r0;%B6850Zec}UO`_a3WN`gB0K;|^4Ed4s-onej&`)c z7Pd6cE=JSV<>=*gN)k?yBv~E3aSWApqqIm2zlM_6GU_aP9md~(_;^9IdSO`9>eZ%d z87k_JsEX8l*Nbc3<SsOx4! z6C$IH9}o|SfB-~5;$6VS3DmpGkFW$j(j-w2zI4(FLhW-ijie``-e=*FHnNP}aw@cA z6SP)IZmDRh@p|cE!mJRW-|x^Xlp94ZWc1E*maj2ymm6RzJ*C&2Fx1m{8MlR%m98@; zp?k)=$!%EbZdBMc^sMYvExaosmNB9arunM2hKXD}4bwU4)om2xl^`2ZH4nSJ2H1MX zP`z0WPriwc;-Y6%2_-kwZ7IiTl1-nu)g!q1mUf*q<#V_N?rLNr7GL24nOue1uQasz zbjFcOjb>N5poE{SVqN?-}W) z$V*2+Y>@BM6z-Qf0-%LGfI^wqn4O#aFD|l&qX--Dj-Ivv_7+-j0FM2CbGbkRedX31Xrsk)YbUGaE8gSWe7vBTfR;Dw()4%P4JG~~(Qb(GXBD4j!7^bE+9ENwU zsz=Wzf~q(#F^}CGG(al2?>P&~@ zvc8nn+b|?1-B#jDX*GZn5gaQBNCm8YoK8Ov?sp|nbvi@<<~1;!4HMRvP&5(N{oaD6 zpqS@C2I}$?r4dBw&NSx}YC9^jN}^pt@a!mpB@oy^#sD~w3MCOQsXmO~?Lk?K3Ch-Z zGV`9kf){5(K#$yt4TgS-V8y0)DvR*>rn zskp$xN}*PX#3_dbCB>3NF8gxDlEW3z97yeD0Yr2%UWtlrrz>$xf+5{%$ttBKYI|%^ zA!-l}w#M8x+Y`$jUcP_{Yz9J9qoX{XBFZVO)@DXVd#7H-!K71qz7x^~Dd6oQB`45Q zLL%z$8Nx>W8f44U0U-(iP%jrnzrAr+H6*pR%w=)bnQr;3s%-o5sDcf#AcOa#+*42CE^0H;#<69$tiM+qW-4YNAW0H}0PbS**U7nE;&ZDk|#pUUn zBizNnB}Y*%f8m9(cC(aBo#C|va~T~Y!Yv278Zs|%5DZW{19afz4aDaGIgENmSH?I*)J$wmM`~t7VamF- zzFu*g<&_||GmzXTkjgpPE<|TC0aP*wf)#0s!YS%dF{zZoLy2k_H#ZSZa)%xRx2$Rn z+16W9RaS6lmol!dD<~+bXV!D~_i-vJDynKk6?HX*g-?Yo*A|wRYY46!ctlEJ0-W4N z13--Q;fmx*-c55rafW&)iCph@GSpcW=bTE9MMhI8PNAwb8YWs*`9N*eQt;LxT#vdrz&sN8M!O|jHz4q37yT>6_Exzvmd zrhQpyreH3@0Am0$01O7)3I_oY4a#8k?$rh3+^j)$C$ttU&i8FWa>bF`s%*g>CWSQA zmnxHO=PIgGreY0RhC@2NGNBRCQMuu-6Ss*?rtPHVYBidKCY|RP$hzO&T(zh?<9>Dv zXfeBr;*;A;&^6UuWf-1pOMqC&?c|ne8Vy6C13m0D7?^QtD%V_YHj)J*eDb$+N3$ro)6#<7oL&ZBpQ;?DI7YuJsy``bp8M4OqQ>;NfvM zsX1e@cABS$%yQO>$Y8DkAT|oMYZr}ac1Nx~$O?vDPSSea=g6XCC?$%Pc1m)>Z1jL< ztkyBWDJ-oZATHFABeS6iK(chB!O-o35dQ$5Mbq3P&g(8haJfkg0M8k+M{>xy+@~KA z6TC{SWi-^16nHq%(Gdok6(IpA6qL)y#n%>y&i10H#5WNQN7kKf2rT)Q#W|-Z;P&=X6vaL{yB|%>yhO2?P+zRJzxzAbBNmo@u3T&2b}z#099fl$4H=Rdb>;P)ur~M*EN(O=it1LGW7dbdcPV zhivSp*QZNb8-EepeJVP*!tMe3`{Kk4%Av)u>?RNa0`2A;&b@Iv64Y~WS($1@t3qqm z$0wFikzVD=3sP!wjIhuwh>Xf#X092Ew!S3=#0KAo zT_HrrYyoHqY7Wr8?w?E7OVQHi$m#>5(X!4LV})>qb@p}SCzFK9?j?gNlvZ9Dh`O4x z+V1BuLakIfMJL8F&IQ~+HY4D!m*4yL-~C+Q&td7)-L~P64edtc z)zhqFMr?|rl%%+-n8&y*ih|_FG_&W~Elf<4ZsjqgNxnWQSn{g*grncCX4v>@sru43 z;!z%n_(y4h{g6!)zxx@-fB3A&dDP-~(Z5k!aWQ6AejB}?Q+BV~d zvW$wC7Z^f2iJFmm5+q)MOzg1|Q>1EwUS{;E1u!{)E5D`Gv!{F~H@YOPL?Njb;27*k z;YD^Hi<=5bV%d7jiOUHFMQO-Lza(QfS83E<6AecJn_@Khoh^q|Gw=MT=_WRkX_qtmeVM1GB|0YBLPB)7*QDQ_WA(sg~TQ>hZzaW0H(~E zgu-e`Pv-P=`z)fuZM__5tSKEmyt2#qKy73etEDrYghN?Jrn-(R$k~4WsD|J{KyYQr zSmdq)of49ro+jBU)Fs^nbXB#-Rn)`mM?wYQIkI!uqB)UdX&T(4hop;f!mlm7E!C*t z@w&<)8UpW#z!$-_Qn}4bFH3W~$YO?}pliUzK|xGHsiLNfYsO1YPstf^cFGbn>S|z} zxlF38ZvEWCVuFjwq3OF-SZu(|+i{a|yuQM;iQoE3FZK;To~O=+K>i#>OSDRuvr-^*eLh zOPZFoOqfh9(gJTlWXXO9HxVQFlv0(%!0j&*!xXH&igJ)?iJX7{Vw$Bx2|#KETW`Ae zkuPc1#dDz9-K5$6S%TJ4Yv-DlkrSoF&4)Ei^1!Ns+o>vmoV6Ee6y`%EULY?l4khB_ zDNnudw!F_sPAiRKWc@dEn|);C#sg|RruUXC`B~E>yt3@nQXf)xhE=}Lhv533Ski` zMBXbc&5#svt5wxYGW;mhyodlU-t9AsF;a|9^xf2MBGOb1)Q{l))H*huJ~>4&Tcx#G~7{y7?I43phGrof!Hp1qBm_v+$jjr zG2Qc1-Mq*{tl%to*)Y*;00Ug&S|z4%03|r@kx`=Ny(_$NG4g1rETub{pBGxlNJ+q) z+)Zw0<+lNvX=w>S8v-C9iU^l-j{yg-9}f|y7B1I9$LyT~P+rqNN#sjlxOql6aK)bu z?~AjRrod#kTt!AV5<@~lq_8GGej*__IFOuef{EJ=Qn`-mq(g033faoF>vOArMSA!0 z`S$k*^Yy@B;f5Fn7-4{8xwcx)2UCFotlUh_uDBe_DQHM&xg3d<4yNH#Rqljzk_nDd zh^;JbOr!x0Ex@2tdb(yUrKUcewmof-o}HT2-=*{X5k;;k?a`iT!NF^?Op;akCI^uv zB!-e%Bv|Fb^{Y(4xfD~7#-i*zM)8P1XoYVfz*c@-x9PgypK1}b=M6~E%!Zqnr=QL; z4O;Dj z9mz;>vzC_%TJE2k4>=-h-@CkxiOf2{lB>ua`N&>Gn_iS*X2oXlQxJWgvR1; z!ih?-00bAnt^U!Q;vz0yhA{Ln33xTLO&h`1Hv21G`tF;P&4Fo+Zm>#}Z6iogCUPc@ zV~cKO=cH)Cf*k0W;<8(M+DO;Ob3+O=BXK6SK+twJMZ->vpq z&DC2C+bo|t$tAP5qpbR3hrvRV9om|)QQnJdFsJM=98e5|R>PLHJiwSpC@YnJOK5>0F0B-PO0iPbq&oqO*NhJrX@` z!00P0iis$ZNK$yr-k)X?rIM z#_xulbs{@2+Ho?ZOA<2~{q4KOU8u)JdOpAk$ZfYMnnRFW)oHq1gs579RnqCG0Yjcm zU*ElcdwRV6o?GwJ`S-^wR-g@Ukv6~^22=MtfC;wvp~fB0w?PmMy7m3Y2;%P=H94&V zIoc>uYFQn+p};WgUjtm6Tc1xsncvqK+>%^z+qqz)Ff?8gxKn!q6WtP%O^AlN z3yNt7=Wdk*;xxjut)L|iBa|wI1l#SWBgMd!)@>myFFF@9;GT+#*i15-`jUx+3*Ct+ z2?A<|9-?jnQxkBMOj3vxKt8LjCkshsQNH0qQbcjLlvGnxkycZTmZX}lmaJrzWTiy4 za+aYMQWi^54P^qQ067jrQ>jSdNc9b|Xt!rEwr*!XchS?3Vu{4ElcHfkUXBxzQ&XD{ zha$?l!4p~t+$2XL0Yze~ZlijkYnQ^u8a$UHXhF6T@qD-c0AiY~F>SU$m?IUNS=4pG zDYD~xsJMvnxQ?X&IU+)p1sOo?$T8qzz!<|Vr6|~A|pes0?4n_45DHBoAkr|@yOoTP zgB>d(ncR;mA|bAcdxvqTL@_v+M`0a+;uNIiR`z{?`LWrNP}ZC)2}lSj*~R7M%=SYf zij0Z6ijtCok;;~onwpf9K@+VQ!W;w*&L;o>r^a9klVPhKkujE=aQ&Q3(S_rF73@pV zLVLQS)$FVcsS2iKnGKZ4sbL{yHk!<)`&q0-)QL`=Qqpjhv~E#DnN0Nn#wWVyQ*Tk^ zL=x7q_jyL5Rj=4h5O76E8K44;`F2^_Mi}XW(WO(EP1~zA5GtOvN@k`)OxCl%`g_Wtj99pYjDkn0+>QwSw%l=eY?SJ8ZeSCDhv$dRk?{$cuYhBbnZ?^}ld z0CDww{{SV>b)aKLab}FR!s}g!G_t30S3h$KS=1TBPPhT2$Bq>tHc~42j7F2SNsP*S zo0zg@-6tTC4y7SCFq~y64s%lHlUv{QjspW8<(q{jY@An@n`=Z8o>~-EQ5OC}VLKsn zAs1)de0|a=#gRLVt>8F_a0`3C!25}|0*Hv?!*OsKZ*SCjTTk^@;oRf?=(icR{{YSE z^4r&dsAU?%^#1@qucw!n*X;~uR;x#+E9VbZ{dWD94uC$tE&PY(#~X(#x3laI&4A>q zR{0)JUHbha)PE>_KUUl>7+@G-h6C?Lje6g_{Qm%dX8!+

Fnqe(hV&{ZWR|tlJ2IJyzRxul)y)y~InM_k& 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