-
Notifications
You must be signed in to change notification settings - Fork 20.4k
Add unit test coverage for llama_tensor_get_type #20112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
99119ce
a3ff194
363e6d3
0a89cda
86103e7
8627302
6e414fc
2015dea
544745c
182cbe5
506a490
3948227
aa8d567
d2586d5
3fe55f1
8ebfe03
4a2f648
64d6c88
d576ae3
3adf377
0b3cc32
b85a7c8
c7aa761
87be6a3
9c00aab
04c8299
2cf3eaf
79a8863
d0cb870
dd7e363
3bcbae3
93cb0fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,56 @@ | ||
| #pragma once | ||
|
|
||
| #include "llama-context.h" | ||
| #include "ggml.h" | ||
| #include "stdint.h" | ||
| #include "llama.h" | ||
|
|
||
| #include <cstdint> | ||
|
|
||
| // Reserve a new compute graph. It is valid until the next call to llama_graph_reserve. | ||
| LLAMA_API struct ggml_cgraph * llama_graph_reserve( | ||
| struct llama_context * ctx, | ||
| uint32_t n_tokens, | ||
| uint32_t n_seqs, | ||
| uint32_t n_outputs); | ||
|
|
||
| // Get the default ggml_type for a given ftype. | ||
| LLAMA_API ggml_type llama_ftype_get_default_type(llama_ftype ftype); | ||
|
|
||
| // Quantization state. | ||
| struct quantize_state_impl; | ||
|
|
||
| LLAMA_API quantize_state_impl * llama_quant_init( | ||
| const llama_model * model, | ||
| const llama_model_quantize_params * params); | ||
|
|
||
| LLAMA_API void llama_quant_free(quantize_state_impl * qs); | ||
|
|
||
| // Descriptor for constructing a mock model for quantization testing. | ||
| struct llama_quant_model_desc { | ||
| const char * architecture; | ||
| uint32_t n_embd; | ||
| uint32_t n_ff; | ||
| uint32_t n_layer; | ||
| uint32_t n_head; | ||
| uint32_t n_head_kv; | ||
| uint32_t n_expert; | ||
| uint32_t n_embd_head_k; | ||
| uint32_t n_embd_head_v; | ||
| }; | ||
|
|
||
| // Create a mock model from a metadata descriptor (for testing). | ||
| // The returned model must be freed with llama_model_free(). | ||
| LLAMA_API llama_model * llama_quant_model_from_metadata(const llama_quant_model_desc * desc); | ||
|
|
||
| // Returns true if this tensor should be quantized (based on name, dims, params). | ||
| LLAMA_API bool llama_quant_tensor_allows_quantization( | ||
| const quantize_state_impl * qs, | ||
| const ggml_tensor * tensor); | ||
|
|
||
| // Compute quantization type assignments for a list of tensors. | ||
| // All tensors should be quantizable (use llama_quant_tensor_allows_quantization to filter). | ||
| // result_types: caller-allocated array of n_tensors elements, filled with assigned types. | ||
| LLAMA_API void llama_quant_compute_types( | ||
| quantize_state_impl * qs, | ||
| llama_ftype ftype, | ||
| ggml_tensor ** tensors, | ||
| ggml_type * result_types, | ||
| size_t n_tensors); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,11 +1,11 @@ | ||||||
| #include "llama.h" | ||||||
| #include "llama-impl.h" | ||||||
| #include "llama-model.h" | ||||||
| #include "llama-model-loader.h" | ||||||
| #include "llama-ext.h" | ||||||
|
|
||||||
| #include <algorithm> | ||||||
| #include <cmath> | ||||||
| #include <cstring> | ||||||
| #include <string> | ||||||
|
bartowski1182 marked this conversation as resolved.
|
||||||
| #include <cinttypes> | ||||||
| #include <fstream> | ||||||
| #include <mutex> | ||||||
|
|
@@ -197,6 +197,7 @@ struct quantize_state_impl { | |||||
|
|
||||||
| // per-tensor metadata, computed in the preliminary loop and used in the main loop | ||||||
| struct tensor_metadata { | ||||||
| std::string name; | ||||||
| ggml_type target_type; | ||||||
| tensor_category category; | ||||||
| std::string remapped_imatrix_name; | ||||||
|
|
@@ -788,7 +789,7 @@ static bool tensor_requires_imatrix(const char * tensor_name, const ggml_type ds | |||||
| // given a file type, get the default tensor type | ||||||
| // | ||||||
|
|
||||||
| static ggml_type llama_ftype_get_default_type(llama_ftype ftype) { | ||||||
| ggml_type llama_ftype_get_default_type(llama_ftype ftype) { | ||||||
|
bartowski1182 marked this conversation as resolved.
|
||||||
| switch (ftype) { | ||||||
| case LLAMA_FTYPE_MOSTLY_Q4_0: return GGML_TYPE_Q4_0; | ||||||
| case LLAMA_FTYPE_MOSTLY_Q4_1: return GGML_TYPE_Q4_1; | ||||||
|
|
@@ -827,16 +828,32 @@ static ggml_type llama_ftype_get_default_type(llama_ftype ftype) { | |||||
| case LLAMA_FTYPE_MOSTLY_IQ3_S: | ||||||
| case LLAMA_FTYPE_MOSTLY_IQ3_M: return GGML_TYPE_IQ3_S; | ||||||
|
|
||||||
| default: throw std::runtime_error(format("invalid output file type %d\n", ftype)); | ||||||
|
bartowski1182 marked this conversation as resolved.
|
||||||
| default: return GGML_TYPE_COUNT; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| static void init_quantize_state_counters(quantize_state_impl & qs, std::vector<tensor_metadata> & metadata) { | ||||||
| for (auto & tm : metadata) { | ||||||
| tensor_category cat = tensor_get_category(tm.name); | ||||||
| tm.category = cat; | ||||||
|
|
||||||
| if (category_is_attn_v(cat)) { | ||||||
| ++qs.n_attention_wv; | ||||||
| } | ||||||
|
|
||||||
| if (cat == tensor_category::OUTPUT) { | ||||||
| qs.has_tied_embeddings = false; | ||||||
| } | ||||||
| } | ||||||
| qs.n_ffn_down = qs.n_ffn_gate = qs.n_ffn_up = (int)qs.model.hparams.n_layer; | ||||||
| } | ||||||
|
|
||||||
| // | ||||||
| // main quantization driver | ||||||
| // | ||||||
|
|
||||||
| static void llama_model_quantize_impl(const std::string & fname_inp, const std::string & fname_out, const llama_model_quantize_params * params) { | ||||||
| ggml_type default_type; | ||||||
| llama_ftype ftype = params->ftype; | ||||||
|
|
||||||
| int nthread = params->nthread; | ||||||
|
|
@@ -845,7 +862,10 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| nthread = std::thread::hardware_concurrency(); | ||||||
| } | ||||||
|
|
||||||
| default_type = llama_ftype_get_default_type(ftype); | ||||||
| ggml_type default_type = llama_ftype_get_default_type(ftype); | ||||||
| if (default_type == GGML_TYPE_COUNT) { | ||||||
|
bartowski1182 marked this conversation as resolved.
|
||||||
| throw std::runtime_error(format("invalid output file type %d\n", ftype)); | ||||||
| } | ||||||
|
|
||||||
| // mmap consistently increases speed on Linux, and also increases speed on Windows with | ||||||
| // hot cache. It may cause a slowdown on macOS, possibly related to free memory. | ||||||
|
|
@@ -964,6 +984,15 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| }); | ||||||
| } | ||||||
|
|
||||||
| // compute tensor metadata once and cache it | ||||||
| std::vector<tensor_metadata> metadata(tensors.size()); | ||||||
| for (size_t i = 0; i < tensors.size(); ++i) { | ||||||
| metadata[i].name = ggml_get_name(tensors[i]->tensor); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Nitpick, not sure if it matters, but calling
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, this raises the question of why does |
||||||
| } | ||||||
|
|
||||||
| // initialize quantization state counters and metadata categories | ||||||
| init_quantize_state_counters(qs, metadata); | ||||||
|
|
||||||
| int idx = 0; | ||||||
| uint16_t n_split = 1; | ||||||
|
|
||||||
|
|
@@ -976,25 +1005,6 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| std::vector<gguf_context_ptr> ctx_outs(n_split); | ||||||
| ctx_outs[0] = std::move(ctx_out); | ||||||
|
|
||||||
| // compute tensor metadata once and cache it | ||||||
| std::vector<tensor_metadata> metadata(tensors.size()); | ||||||
|
|
||||||
| // initialize quantization state before preliminary loop (counters for use_more_bits) | ||||||
| { | ||||||
| for (size_t i = 0; i < tensors.size(); ++i) { | ||||||
| const auto cat = tensor_get_category(tensors[i]->tensor->name); | ||||||
| if (category_is_attn_v(cat)) { | ||||||
| ++qs.n_attention_wv; | ||||||
| } | ||||||
| if (cat == tensor_category::OUTPUT) { | ||||||
| qs.has_tied_embeddings = false; | ||||||
| } | ||||||
| metadata[i].category = cat; // save and re-use the category while we're at it | ||||||
| } | ||||||
| // these also need to be set to n_layer by default | ||||||
| qs.n_ffn_down = qs.n_ffn_gate = qs.n_ffn_up = (int)qs.model.hparams.n_layer; | ||||||
| } | ||||||
|
|
||||||
| // flag for --dry-run | ||||||
| bool will_require_imatrix = false; | ||||||
|
|
||||||
|
|
@@ -1005,7 +1015,6 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| for (size_t i = 0; i < tensors.size(); ++i) { | ||||||
| const auto * it = tensors[i]; | ||||||
| const struct ggml_tensor * tensor = it->tensor; | ||||||
| const std::string name = ggml_get_name(tensor); | ||||||
|
|
||||||
| uint16_t i_split = params->keep_split ? it->idx : 0; | ||||||
| if (!ctx_outs[i_split]) { | ||||||
|
|
@@ -1034,7 +1043,7 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| " - offending tensor: %s\n" | ||||||
| " - target type: %s\n" | ||||||
| "============================================================================\n\n", | ||||||
| name.c_str(), ggml_type_name(metadata[i].target_type)); | ||||||
| metadata[i].name.c_str(), ggml_type_name(metadata[i].target_type)); | ||||||
| throw std::runtime_error("this quantization requires an imatrix!"); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -1107,7 +1116,6 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| new_ofstream(weight.idx); | ||||||
| } | ||||||
|
|
||||||
| const std::string name = ggml_get_name(tensor); | ||||||
| const size_t tensor_size = ggml_nbytes(tensor); | ||||||
|
|
||||||
| if (!params->dry_run) { | ||||||
|
|
@@ -1238,9 +1246,9 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: | |||||
| total_size_new += new_size; | ||||||
|
|
||||||
| // update the gguf meta data as we go | ||||||
| gguf_set_tensor_type(ctx_outs[cur_split].get(), name.c_str(), new_type); | ||||||
| GGML_ASSERT(gguf_get_tensor_size(ctx_outs[cur_split].get(), gguf_find_tensor(ctx_outs[cur_split].get(), name.c_str())) == new_size); | ||||||
| gguf_set_tensor_data(ctx_outs[cur_split].get(), name.c_str(), new_data); | ||||||
| gguf_set_tensor_type(ctx_outs[cur_split].get(), metadata[i].name.c_str(), new_type); | ||||||
| GGML_ASSERT(gguf_get_tensor_size(ctx_outs[cur_split].get(), gguf_find_tensor(ctx_outs[cur_split].get(), metadata[i].name.c_str())) == new_size); | ||||||
| gguf_set_tensor_data(ctx_outs[cur_split].get(), metadata[i].name.c_str(), new_data); | ||||||
|
|
||||||
| // write tensor data + padding | ||||||
| fout.write((const char *) new_data, new_size); | ||||||
|
|
@@ -1305,3 +1313,89 @@ uint32_t llama_model_quantize( | |||||
|
|
||||||
| return 0; | ||||||
| } | ||||||
|
|
||||||
| // | ||||||
| // Helper functions for external tools exposed in llama-ext.h | ||||||
| // | ||||||
|
|
||||||
| quantize_state_impl * llama_quant_init( | ||||||
| const llama_model * model, | ||||||
| const llama_model_quantize_params * params) { | ||||||
| return new quantize_state_impl(*model, params); | ||||||
| } | ||||||
|
|
||||||
| void llama_quant_free(quantize_state_impl * qs) { | ||||||
| delete qs; | ||||||
| } | ||||||
|
|
||||||
| llama_model * llama_quant_model_from_metadata(const llama_quant_model_desc * desc) { | ||||||
| struct llama_model_params mparams = llama_model_default_params(); | ||||||
| auto * model = new llama_model(mparams); | ||||||
|
|
||||||
| model->arch = llm_arch_from_string(desc->architecture); | ||||||
|
|
||||||
| // infer llm_type: only LLM_TYPE_70B matters for quantization logic | ||||||
| if (model->arch == LLM_ARCH_LLAMA && desc->n_layer == 80 && desc->n_head != desc->n_head_kv) { | ||||||
| model->type = LLM_TYPE_70B; | ||||||
| } | ||||||
|
|
||||||
| model->hparams.n_embd = desc->n_embd; | ||||||
| model->hparams.n_embd_head_k_full = desc->n_embd_head_k; | ||||||
| model->hparams.n_embd_head_v_full = desc->n_embd_head_v; | ||||||
| model->hparams.n_layer = desc->n_layer; | ||||||
| model->hparams.n_expert = desc->n_expert; | ||||||
|
|
||||||
| for (uint32_t i = 0; i < desc->n_layer; i++) { | ||||||
| model->hparams.n_head_arr[i] = desc->n_head; | ||||||
| model->hparams.n_head_kv_arr[i] = desc->n_head_kv; | ||||||
| model->hparams.n_ff_arr[i] = desc->n_ff; | ||||||
| } | ||||||
|
|
||||||
| return model; | ||||||
| } | ||||||
|
|
||||||
| bool llama_quant_tensor_allows_quantization( | ||||||
| const quantize_state_impl * qs, | ||||||
| const ggml_tensor * tensor) { | ||||||
| return tensor_allows_quantization(qs->params, qs->model.arch, tensor); | ||||||
| } | ||||||
|
|
||||||
| void llama_quant_compute_types( | ||||||
| quantize_state_impl * qs, | ||||||
| llama_ftype ftype, | ||||||
| ggml_tensor ** tensors, | ||||||
| ggml_type * result_types, | ||||||
| size_t n_tensors) { | ||||||
| // reset per-computation state | ||||||
| qs->n_attention_wv = 0; | ||||||
| qs->n_ffn_down = 0; | ||||||
| qs->n_ffn_gate = 0; | ||||||
| qs->n_ffn_up = 0; | ||||||
| qs->i_attention_wv = 0; | ||||||
| qs->i_ffn_down = 0; | ||||||
| qs->i_ffn_gate = 0; | ||||||
| qs->i_ffn_up = 0; | ||||||
| qs->n_fallback = 0; | ||||||
| qs->has_imatrix = false; | ||||||
| qs->has_tied_embeddings = true; | ||||||
|
|
||||||
| // build metadata from tensor names | ||||||
| std::vector<tensor_metadata> metadata(n_tensors); | ||||||
| for (size_t i = 0; i < n_tensors; i++) { | ||||||
| metadata[i].name = ggml_get_name(tensors[i]); | ||||||
| } | ||||||
|
|
||||||
| // initialize counters and categories | ||||||
| init_quantize_state_counters(*qs, metadata); | ||||||
|
|
||||||
| // use a local copy of params with the requested ftype | ||||||
| llama_model_quantize_params local_params = *qs->params; | ||||||
| local_params.ftype = ftype; | ||||||
|
|
||||||
| ggml_type default_type = llama_ftype_get_default_type(ftype); | ||||||
|
|
||||||
| // compute types | ||||||
| for (size_t i = 0; i < n_tensors; i++) { | ||||||
| result_types[i] = llama_tensor_get_type(*qs, &local_params, tensors[i], default_type, metadata[i]); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| * | ||
| !*.* | ||
| !snapshots/ | ||
| *.o | ||
| ggml-common.h | ||
| **/*.swp | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.