struct gguf_tensor_info { struct ggml_tensor t; // for holding the equivalent info
uint64_t offset; // offset from start of `data`, must be a multiple of `ALIGNMENT`
};
struct gguf_context {
uint32_t version = GGUF_VERSION;
template<typename Reader> bool gguf_read_tensor_shape(const Reader & gr, gguf_tensor_info & info, bool & ok) {
uint32_t n_dims = -1;
ok = ok && gr.read(n_dims); if (n_dims > GGML_MAX_DIMS) {
GGML_LOG_ERROR("%s: tensor '%s' has invalid number of dimensions: %" PRIu32 " > %" PRIu32 "\n",
__func__, info.t.name, n_dims, GGML_MAX_DIMS);
ok = false; returnfalse;
} for (uint32_t j = 0; ok && j < GGML_MAX_DIMS; ++j) {
info.t.ne[j] = 1; if (j < n_dims) {
ok = ok && gr.read(info.t.ne[j]);
}
// check that all ne are non-negative if (info.t.ne[j] < 0) {
GGML_LOG_ERROR("%s: tensor '%s' dimension %" PRIu32 " has invalid number of elements: %" PRIi64 " < 0\n",
__func__, info.t.name, j, info.t.ne[j]);
ok = false; returnfalse;
}
}
// check that the total number of elements is representable if (ok && ((INT64_MAX/info.t.ne[1] <= info.t.ne[0]) ||
(INT64_MAX/info.t.ne[2] <= info.t.ne[0]*info.t.ne[1]) ||
(INT64_MAX/info.t.ne[3] <= info.t.ne[0]*info.t.ne[1]*info.t.ne[2]))) {
GGML_LOG_ERROR("%s: total number of elements in tensor '%s' with shape " "(%" PRIi64 ", %" PRIi64 ", %" PRIi64 ", %" PRIi64 ") is >= %" PRIi64 "\n",
__func__, info.t.name, info.t.ne[0], info.t.ne[1], info.t.ne[2], info.t.ne[3], INT64_MAX);
ok = false; returnfalse;
} return true;
}
if (ok && gr.read(ctx->version)) { if (ok && ctx->version == 0) {
GGML_LOG_ERROR("%s: bad GGUF version: %" PRIu32 "\n", __func__, ctx->version);
ok = false;
}
/* *bitlayoutisdifferentwhenreadingnon-nativeendianmodels. *assumingthattheGGUFversionis3,thenon-nativeendianmodel *wouldreaditas0x30000000.wecanusetheANDoperationagainst *thelast4hexadecimaldigitstocheckifthemodelisthesame *endiannessasthehostsystem.
*/ if (ok && (ctx->version & 0x0000FFFF) == 0x00000000) {
GGML_LOG_ERROR("%s: failed to load model: this GGUF file version %" PRIu32 " is extremely large, is there a mismatch between the host and model endianness?\n", __func__, ctx->version);
ok = false;
}
if (ok && ctx->version == 1) {
GGML_LOG_ERROR("%s: GGUFv1 is no longer supported, please use a more up-to-date version\n", __func__);
ok = false;
} if (ok && ctx->version > GGUF_VERSION) {
GGML_LOG_ERROR("%s: this GGUF file is version %" PRIu32 " but this software only supports up to version %d\n",
__func__, ctx->version, GGUF_VERSION);
ok = false;
}
} else {
ok = false;
}
if (ok && gr.read(n_tensors)) {
static_assert(sizeof(size_t) <= 8 && sizeof(gguf_tensor_info) >= 2, "int64_t insufficient for indexing"); if (n_tensors < 0 || n_tensors > int64_t(SIZE_MAX/sizeof(gguf_tensor_info))) {
GGML_LOG_ERROR("%s: number of tensors is %" PRIi64 " but must be in [0, %zu]\n",
__func__, n_tensors, SIZE_MAX/sizeof(gguf_tensor_info));
ok = false;
}
} else {
ok = false;
}
if (ok && gr.read(n_kv)) {
static_assert(sizeof(size_t) <= 8 && sizeof(gguf_tensor_info) >= 2, "int64_t insufficient for indexing"); if (n_kv < 0 || n_kv > int64_t(SIZE_MAX/sizeof(gguf_kv))) {
GGML_LOG_ERROR("%s: number of key value pairs is %" PRIi64 " but must be in [0, %zu]\n",
__func__, n_kv, SIZE_MAX/sizeof(gguf_kv));
ok = false;
}
} else {
ok = false;
}
if (!ok) {
GGML_LOG_ERROR("%s: failed to read header\n", __func__);
gguf_free(ctx); return nullptr;
}
// KV pairs
{ for (int64_t i = 0; ok && i < n_kv; ++i) {
std::string key;
gguf_type type = gguf_type(-1); bool is_array = false;
uint64_t n = 1;
try {
ok = ok && gr.read(key);
} catch (std::length_error &) {
GGML_LOG_ERROR("%s: encountered length_error while reading key %" PRIi64 "\n", __func__, i);
ok = false;
} catch (std::bad_alloc &) {
GGML_LOG_ERROR("%s: encountered bad_alloc error while reading key %" PRIi64 "\n", __func__, i);
ok = false;
}
// Check for duplicate keys for (size_t j = 0; ok && j < ctx->kv.size(); ++j) { if (key == ctx->kv[j].key) {
GGML_LOG_ERROR("%s: duplicate key '%s' for tensors %zu and %" PRIi64 " \n", __func__, key.c_str(), j, i);
ok = false;
}
}
if (!ok) { break;
}
ok = ok && gr.read(type); if (type == GGUF_TYPE_ARRAY) {
is_array = true;
ok = ok && gr.read(type);
ok = ok && gr.read(n);
} if (!ok) { break;
}
switch (type) { case GGUF_TYPE_UINT8: ok = ok && gguf_read_emplace_helper<uint8_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_INT8: ok = ok && gguf_read_emplace_helper<int8_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_UINT16: ok = ok && gguf_read_emplace_helper<uint16_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_INT16: ok = ok && gguf_read_emplace_helper<int16_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_UINT32: ok = ok && gguf_read_emplace_helper<uint32_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_INT32: ok = ok && gguf_read_emplace_helper<int32_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_FLOAT32: ok = ok && gguf_read_emplace_helper<float> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_BOOL: ok = ok && gguf_read_emplace_helper<bool> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_STRING: ok = ok && gguf_read_emplace_helper<std::string>(gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_UINT64: ok = ok && gguf_read_emplace_helper<uint64_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_INT64: ok = ok && gguf_read_emplace_helper<int64_t> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_FLOAT64: ok = ok && gguf_read_emplace_helper<double> (gr, ctx->kv, key, is_array, n); break; case GGUF_TYPE_ARRAY: default:
{
GGML_LOG_ERROR("%s: key '%s' has invalid GGUF type %d\n", __func__, key.c_str(), type);
ok = false;
} break;
}
}
if (!ok) {
GGML_LOG_ERROR("%s: failed to read key-value pairs\n", __func__);
gguf_free(ctx); return nullptr;
}
GGML_ASSERT(int64_t(ctx->kv.size()) == n_kv);
if (ctx->alignment == 0 || (ctx->alignment & (ctx->alignment - 1)) != 0) {
GGML_LOG_ERROR("%s: alignment %zu is not a power of 2\n", __func__, ctx->alignment);
gguf_free(ctx); return nullptr;
}
}
// read the tensor info if (n_tensors > 0) {
ctx->info.resize(n_tensors);
for (int64_t i = 0; ok && i < n_tensors; ++i) {
gguf_tensor_info & info = ctx->info[i];
// tensor name
{
std::string name;
try {
ok = ok && gr.read(name);
} catch (std::length_error &) {
GGML_LOG_ERROR("%s: encountered length_error while reading tensor name %" PRIi64 "\n", __func__, i);
ok = false;
} catch (std::bad_alloc &) {
GGML_LOG_ERROR("%s: encountered bad_alloc error while reading tensor name %" PRIi64 "\n", __func__, i);
ok = false;
} if (name.length() >= GGML_MAX_NAME) {
GGML_LOG_ERROR("%s: tensor name %" PRIi64 " is too long: %zu >= %d\n", __func__, i, name.length(), GGML_MAX_NAME);
ok = false; break;
}
ggml_set_name(&info.t, name.c_str());
// make sure there are no duplicate tensor names for (int64_t j = 0; ok && j < i; ++j) { if (strcmp(info.t.name, ctx->info[j].t.name) == 0) {
GGML_LOG_ERROR("%s: duplicate tensor name '%s' for tensors %" PRIi64 " and %" PRIi64 "\n", __func__, info.t.name, j, i);
ok = false; break;
}
}
} if (!ok) { break;
}
// tensor shape if (!gguf_read_tensor_shape(gr, info, ok)) { break;
} if (!ok) { break;
}
// tensor type
{
ok = ok && gr.read(info.t.type);
// check that tensor type is within defined range if (info.t.type < 0 || info.t.type >= GGML_TYPE_COUNT) {
GGML_LOG_ERROR("%s: tensor '%s' has invalid ggml type %d (%s)\n",
__func__, info.t.name, info.t.type, ggml_type_name(info.t.type));
ok = false; break;
}
// Validation logic for both file and buffer readers const size_t type_size = ggml_type_size(info.t.type); const int64_t blck_size = ggml_blck_size(info.t.type);
// check that row size is divisible by block size if (blck_size == 0 || info.t.ne[0] % blck_size != 0) {
GGML_LOG_ERROR("%s: tensor '%s' of type %d (%s) has %" PRId64 " elements per row, " "not a multiple of block size (%" PRId64 ")\n",
__func__, info.t.name, (int) info.t.type, ggml_type_name(info.t.type), info.t.ne[0], blck_size);
ok = false; break;
}
// calculate byte offsets given the tensor shape and type
info.t.nb[0] = type_size;
info.t.nb[1] = info.t.nb[0]*(info.t.ne[0]/blck_size); for (int j = 2; j < GGML_MAX_DIMS; ++j) {
info.t.nb[j] = info.t.nb[j - 1]*info.t.ne[j - 1];
}
} if (!ok) { break;
}
// tensor data offset within buffer
ok = ok && gr.read(info.offset);
}
}
if (!ok) {
GGML_LOG_ERROR("%s: failed to read tensor info\n", __func__);
gguf_free(ctx); return nullptr;
}
GGML_ASSERT(int64_t(ctx->info.size()) == n_tensors);
// Handle alignment and data section positioning if constexpr (std::is_same_v<Reader, gguf_reader>) { // File reader: use fseek and ftell
FILE* file = gr.file; if (fseek(file, GGML_PAD(ftell(file), ctx->alignment), SEEK_SET) != 0) {
GGML_LOG_ERROR("%s: failed to seek to beginning of data section\n", __func__);
gguf_free(ctx); return nullptr;
}
ctx->offset = ftell(file);
} else { // Buffer reader: use seek and tell const size_t current_offset = gr.tell(); const size_t aligned_offset = GGML_PAD(current_offset, ctx->alignment);
// For vocab-only files or when there's no tensor data, the aligned offset might be beyond buffer size if (n_tensors == 0 || aligned_offset >= gr.buffer_size) { // No tensor data section - use current offset as the data offset
ctx->offset = current_offset;
} else { if (!gr.seek(aligned_offset)) {
GGML_LOG_ERROR("%s: failed to seek to beginning of data section\n", __func__);
gguf_free(ctx); return nullptr;
}
ctx->offset = gr.tell();
}
}
// compute the total size of the data section, taking into account the alignment
{
ctx->size = 0; for (size_t i = 0; i < ctx->info.size(); ++i) { const gguf_tensor_info & ti = ctx->info[i]; if (ti.offset != ctx->size) {
GGML_LOG_ERROR("%s: tensor '%s' has offset %" PRIu64 ", expected %zu\n",
__func__, ti.t.name, ti.offset, ctx->size);
GGML_LOG_ERROR("%s: failed to read tensor data\n", __func__);
gguf_free(ctx); return nullptr;
}
size_t padded_size = GGML_PAD(ggml_nbytes(&ti.t), ctx->alignment); if (SIZE_MAX - ctx->size < padded_size) {
GGML_LOG_ERROR("%s: tensor '%s' size overflow, cannot accumulate size %zu + %zu\n",
__func__, ti.t.name, ctx->size, padded_size);
gguf_free(ctx); return nullptr;
}
ctx->size += padded_size;
}
}
// load the tensor data only if requested if (params.ctx != nullptr) { // if the provided gguf_context is no_alloc, then we create "empty" tensors and do not read the binary blob // otherwise, we load the binary blob into the created ggml_context as well, and point the "data" members of // the ggml_tensor structs to the appropriate locations in the binary blob
// compute the exact size needed for the new ggml_context const size_t mem_size =
params.no_alloc ?
(n_tensors )*ggml_tensor_overhead() :
(n_tensors + 1)*ggml_tensor_overhead() + ctx->size;
*params.ctx = ggml_init(pdata); if (*params.ctx == nullptr) {
GGML_LOG_ERROR("%s: failed to initialize ggml context for storing tensors\n", __func__);
gguf_free(ctx); return nullptr;
}
struct ggml_context * ctx_data = *params.ctx;
struct ggml_tensor * data = nullptr;
if (!params.no_alloc) {
data = ggml_new_tensor_1d(ctx_data, GGML_TYPE_I8, ctx->size);
ok = ok && data != nullptr;
if (ok) {
ggml_set_name(data, "GGUF tensor data binary blob");
}
// read the binary blob with the tensor data
ok = ok && gr.read(data->data, ctx->size);
if (!ok) {
GGML_LOG_ERROR("%s: failed to read tensor data binary blob\n", __func__);
ggml_free(ctx_data);
*params.ctx = nullptr;
gguf_free(ctx); return nullptr;
}
ctx->data = data->data;
}
ggml_set_no_alloc(ctx_data, true);
// create the tensors for (size_t i = 0; i < ctx->info.size(); ++i) { conststruct gguf_tensor_info & info = ctx->info[i];
struct ggml_tensor * cur = ggml_new_tensor(ctx_data, info.t.type, GGML_MAX_DIMS, info.t.ne);
ok = ok && cur != nullptr;
if (!ok) { break;
}
ggml_set_name(cur, info.t.name);
// point the data member to the appropriate location in the binary blob using the tensor info if (!params.no_alloc) {
cur->data = (char *) data->data + info.offset;
}
}
if (!ok) {
GGML_LOG_ERROR("%s: failed to create tensors\n", __func__);
ggml_free(ctx_data);
*params.ctx = nullptr;
gguf_free(ctx); return nullptr;
}
std::vector<std::string> tmp(n); for (size_t i = 0; i < n; ++i) {
tmp[i] = data[i];
}
ctx->kv.emplace_back(key, tmp);
}
// set or add KV pairs from another context void gguf_set_kv(struct gguf_context * ctx, conststruct gguf_context * src) { const int64_t n_kv = gguf_get_n_kv(src); for (int64_t i = 0; i < n_kv; ++i) { conststruct gguf_kv & kv = src->kv[i];
if (!kv.is_array) { switch (kv.get_type()) { case GGUF_TYPE_UINT8: gguf_set_val_u8 (ctx, kv.get_key().c_str(), kv.get_val<uint8_t>()); break; case GGUF_TYPE_INT8: gguf_set_val_i8 (ctx, kv.get_key().c_str(), kv.get_val<int8_t>()); break; case GGUF_TYPE_UINT16: gguf_set_val_u16 (ctx, kv.get_key().c_str(), kv.get_val<uint16_t>()); break; case GGUF_TYPE_INT16: gguf_set_val_i16 (ctx, kv.get_key().c_str(), kv.get_val<int16_t>()); break; case GGUF_TYPE_UINT32: gguf_set_val_u32 (ctx, kv.get_key().c_str(), kv.get_val<uint32_t>()); break; case GGUF_TYPE_INT32: gguf_set_val_i32 (ctx, kv.get_key().c_str(), kv.get_val<int32_t>()); break; case GGUF_TYPE_FLOAT32: gguf_set_val_f32 (ctx, kv.get_key().c_str(), kv.get_val<float>()); break; case GGUF_TYPE_UINT64: gguf_set_val_u64 (ctx, kv.get_key().c_str(), kv.get_val<uint64_t>()); break; case GGUF_TYPE_INT64: gguf_set_val_i64 (ctx, kv.get_key().c_str(), kv.get_val<int64_t>()); break; case GGUF_TYPE_FLOAT64: gguf_set_val_f64 (ctx, kv.get_key().c_str(), kv.get_val<double>()); break; case GGUF_TYPE_BOOL: gguf_set_val_bool(ctx, kv.get_key().c_str(), kv.get_val<bool>()); break; case GGUF_TYPE_STRING: gguf_set_val_str (ctx, kv.get_key().c_str(), kv.get_val<std::string>().c_str()); break; case GGUF_TYPE_ARRAY: default: GGML_ABORT("invalid type");
} continue;
}
const size_t ne = kv.get_ne();
switch (kv.get_type()) { case GGUF_TYPE_UINT8: case GGUF_TYPE_INT8: case GGUF_TYPE_UINT16: case GGUF_TYPE_INT16: case GGUF_TYPE_UINT32: case GGUF_TYPE_INT32: case GGUF_TYPE_FLOAT32: case GGUF_TYPE_UINT64: case GGUF_TYPE_INT64: case GGUF_TYPE_FLOAT64: case GGUF_TYPE_BOOL: {
gguf_set_arr_data(ctx, kv.get_key().c_str(), kv.get_type(), kv.data.data(), ne);
} break; case GGUF_TYPE_STRING: {
std::vector<constchar *> tmp(ne); for (size_t j = 0; j < ne; ++j) {
tmp[j] = kv.data_string[j].c_str();
}
gguf_set_arr_str(ctx, kv.get_key().c_str(), tmp.data(), ne);
} break; case GGUF_TYPE_ARRAY: default: GGML_ABORT("invalid type");
}
}
}
switch (kv.get_type()) { case GGUF_TYPE_UINT8: case GGUF_TYPE_INT8: case GGUF_TYPE_UINT16: case GGUF_TYPE_INT16: case GGUF_TYPE_UINT32: case GGUF_TYPE_INT32: case GGUF_TYPE_FLOAT32: case GGUF_TYPE_UINT64: case GGUF_TYPE_INT64: case GGUF_TYPE_FLOAT64: {
write(kv.data);
} break; case GGUF_TYPE_BOOL: { for (size_t i = 0; i < ne; ++i) {
write(kv.get_val<bool>(i));
}
} break; case GGUF_TYPE_STRING: { for (size_t i = 0; i < ne; ++i) {
write(kv.get_val<std::string>(i));
}
} break; case GGUF_TYPE_ARRAY: default: GGML_ABORT("invalid type");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.