| 3122 | } |
| 3123 | |
| 3124 | bool clip_image_batch_encode(clip_ctx * ctx, const int n_threads, const clip_image_f32_batch * imgs_c_ptr, float * vec) { |
| 3125 | const clip_image_f32_batch & imgs = *imgs_c_ptr; |
| 3126 | int batch_size = imgs.entries.size(); |
| 3127 | |
| 3128 | // TODO @ngxson : implement batch size > 1 as a loop |
| 3129 | // we don't need true batching support because the cgraph will gonna be big anyway |
| 3130 | if (batch_size != 1) { |
| 3131 | return false; // only support batch size of 1 |
| 3132 | } |
| 3133 | |
| 3134 | // if buffers are not allocated, we need to do a warmup run to allocate them |
| 3135 | if (!ctx->is_allocated) { |
| 3136 | clip_model_loader::warmup(*ctx, *imgs_c_ptr); |
| 3137 | } |
| 3138 | |
| 3139 | // build the inference graph |
| 3140 | ggml_backend_sched_reset(ctx->sched.get()); |
| 3141 | ggml_cgraph * gf = clip_image_build_graph(ctx, imgs); |
| 3142 | ggml_backend_sched_alloc_graph(ctx->sched.get(), gf); |
| 3143 | |
| 3144 | // set inputs |
| 3145 | const auto & model = ctx->model; |
| 3146 | const auto & hparams = model.hparams; |
| 3147 | |
| 3148 | const int image_size_width = imgs.entries[0]->nx; |
| 3149 | const int image_size_height = imgs.entries[0]->ny; |
| 3150 | |
| 3151 | const int patch_size = hparams.patch_size; |
| 3152 | const int num_patches = ((image_size_width / patch_size) * (image_size_height / patch_size)); |
| 3153 | const int n_pos = num_patches + (model.class_embedding ? 1 : 0); |
| 3154 | const int pos_w = image_size_width / patch_size; |
| 3155 | const int pos_h = image_size_height / patch_size; |
| 3156 | |
| 3157 | |
| 3158 | auto get_inp_tensor = [&gf](const char * name) { |
| 3159 | ggml_tensor * inp = ggml_graph_get_tensor(gf, name); |
| 3160 | if (inp == nullptr) { |
| 3161 | GGML_ABORT("Failed to get tensor %s", name); |
| 3162 | } |
| 3163 | if (!(inp->flags & GGML_TENSOR_FLAG_INPUT)) { |
| 3164 | GGML_ABORT("Tensor %s is not an input tensor", name); |
| 3165 | } |
| 3166 | return inp; |
| 3167 | }; |
| 3168 | |
| 3169 | auto set_input_f32 = [&get_inp_tensor](const char * name, std::vector<float> & values) { |
| 3170 | ggml_tensor * cur = get_inp_tensor(name); |
| 3171 | GGML_ASSERT(cur->type == GGML_TYPE_F32); |
| 3172 | GGML_ASSERT(ggml_nelements(cur) == (int64_t)values.size()); |
| 3173 | ggml_backend_tensor_set(cur, values.data(), 0, ggml_nbytes(cur)); |
| 3174 | }; |
| 3175 | |
| 3176 | auto set_input_i32 = [&get_inp_tensor](const char * name, std::vector<int32_t> & values) { |
| 3177 | ggml_tensor * cur = get_inp_tensor(name); |
| 3178 | GGML_ASSERT(cur->type == GGML_TYPE_I32); |
| 3179 | GGML_ASSERT(ggml_nelements(cur) == (int64_t)values.size()); |
| 3180 | ggml_backend_tensor_set(cur, values.data(), 0, ggml_nbytes(cur)); |
| 3181 | }; |
no test coverage detected