Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
99119ce
Add unit test coverage for llama_tensor_get_type
bartowski1182 Mar 4, 2026
a3ff194
Fix merge conflicts, add more schemas
bartowski1182 Mar 4, 2026
363e6d3
clang formatter changes
bartowski1182 Mar 4, 2026
0a89cda
Trailing whitespace
bartowski1182 Mar 4, 2026
86103e7
Update name
bartowski1182 Mar 9, 2026
8627302
Start rebase
bartowski1182 Mar 9, 2026
6e414fc
Updating files with upstream changes prior to rebase
bartowski1182 Mar 10, 2026
2015dea
Changes needed from rebase
bartowski1182 Mar 10, 2026
544745c
Update attn_qkv schema, change throw behaviour
bartowski1182 Mar 10, 2026
182cbe5
Fix merge conflicts
bartowski1182 Mar 10, 2026
506a490
White space
bartowski1182 Mar 10, 2026
3948227
Update with latest changes to state counters
bartowski1182 Mar 11, 2026
aa8d567
Revert accidental personal CLAUDE.md changes
bartowski1182 Mar 11, 2026
d2586d5
Change quotation mark
bartowski1182 Mar 11, 2026
3fe55f1
Reuse metadata.name since we have it
bartowski1182 Mar 11, 2026
8ebfe03
Move test-only stuff out of llama-quant.cpp
bartowski1182 Mar 12, 2026
4a2f648
Hide the regex functionality back in llama-quant.cpp, use a unique po…
bartowski1182 Mar 12, 2026
64d6c88
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Mar 15, 2026
d576ae3
cont : inital deslop guidelines
ggerganov Mar 15, 2026
3adf377
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Mar 16, 2026
0b3cc32
Cleanup based on review comments
bartowski1182 Mar 16, 2026
b85a7c8
Continue cleanup
bartowski1182 Mar 17, 2026
c7aa761
Small cleanup
bartowski1182 Mar 17, 2026
87be6a3
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Mar 17, 2026
9c00aab
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Mar 24, 2026
04c8299
Manually set proper ordering of tensors, mostly applies to gemma
bartowski1182 Mar 27, 2026
2cf3eaf
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Mar 31, 2026
79a8863
Merge branch 'ggml-org:master' into llama-quant-refactor
bartowski1182 Apr 2, 2026
d0cb870
Formatting
bartowski1182 Apr 2, 2026
dd7e363
Update tests/test-quant-type-selection.cpp
bartowski1182 Apr 2, 2026
3bcbae3
Merge branch 'master' into llama-quant-refactor
bartowski1182 Apr 2, 2026
93cb0fe
Fix merge conflicts
bartowski1182 Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions src/llama-ext.h
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);
156 changes: 125 additions & 31 deletions src/llama-quant.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "llama.h"
Comment thread
bartowski1182 marked this conversation as resolved.
#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>
Comment thread
bartowski1182 marked this conversation as resolved.
#include <cinttypes>
#include <fstream>
#include <mutex>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Comment thread
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;
Expand Down Expand Up @@ -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));
Comment thread
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;
Expand All @@ -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) {
Comment thread
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.
Expand Down Expand Up @@ -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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
metadata[i].name = ggml_get_name(tensors[i]->tensor);
metadata[i].name = tensors[i]->tensor->name;

Nitpick, not sure if it matters, but calling ggml_get_name is generally unnecessary where we can just do tensor->name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, this raises the question of why does ggml_get_name even exist if it just returns tensor->name ... but yeah I can make that change

}

// initialize quantization state counters and metadata categories
init_quantize_state_counters(qs, metadata);

int idx = 0;
uint16_t n_split = 1;

Expand All @@ -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;

Expand All @@ -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]) {
Expand Down Expand Up @@ -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!");
}
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]);
}
}
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*
!*.*
!snapshots/
*.o
ggml-common.h
**/*.swp
Expand Down
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ if (TARGET cpp-httplib)
add_executable(test-gguf-model-data test-gguf-model-data.cpp)
target_link_libraries(test-gguf-model-data PRIVATE gguf-model-data common)
llama_test(test-gguf-model-data LABEL "model")

# test-quant-type-selection requires gguf-model-data for remote model metadata
llama_build_and_test(test-quant-type-selection.cpp LABEL "model")
target_link_libraries(test-quant-type-selection PRIVATE gguf-model-data)
target_compile_definitions(test-quant-type-selection PRIVATE
SNAPSHOT_DIR="${CMAKE_CURRENT_SOURCE_DIR}/snapshots")
endif()
endif()

Expand Down
Loading