convert-*.py: move per model weight estimation away from util back to main script

plus some refactoring
This commit is contained in:
brian khuu 2024-06-02 17:44:53 +10:00
parent 684c604eca
commit b1927eed82
3 changed files with 90 additions and 109 deletions

View file

@ -47,7 +47,6 @@ AnyModel = TypeVar("AnyModel", bound="type[Model]")
class Model:
_model_classes: dict[str, type[Model]] = {}
model_name: str
dir_model: Path
ftype: gguf.LlamaFileType
is_big_endian: bool
@ -72,6 +71,10 @@ class Model:
model_name: str | None, split_max_tensors: int = 0, split_max_size: int = 0, dry_run: bool = False, small_first_shard: bool = False):
if type(self) is Model:
raise TypeError(f"{type(self).__name__!r} should not be directly instantiated")
if metadata is None:
raise TypeError("authorship metadata must be provided")
self.dir_model = dir_model
self.ftype = ftype
self.is_big_endian = is_big_endian
@ -121,16 +124,20 @@ class Model:
self.model_name = Model.get_model_name(self.metadata, self.hparams, self.dir_model, self.model_arch)
# Fallback to model architecture name if metadata name is still missing
if self.metadata.name is None:
self.metadata.name = gguf.MODEL_ARCH_NAMES[self.model_arch]
# Extracts and converts the encoding scheme from the given file type name. e.g. 'gguf.LlamaFileType.ALL_F32' --> 'F32'
output_type = self.ftype.name.partition("_")[2]
# Update authorship metadata class with parameter size class (useful for leader boards)
expert_count = self.hparams["num_local_experts"] if "num_local_experts" in self.hparams else None
weight_estimate = gguf.per_model_weight_count_estimation(self.get_tensors(), expert_count)
weight_estimate = self.per_model_weight_count_estimation(self.get_tensors(), expert_count)
self.metadata.parameter_size_class = gguf.parameter_size_class(expert_count, weight_estimate)
# Generate default filename based on model specification and available metadata
self.fname_default = gguf.naming_convention(self.model_name, self.metadata.basename, self.metadata.finetune, self.metadata.version, expert_count, weight_estimate, output_type)
self.fname_default = gguf.naming_convention(self.metadata.name, self.metadata.basename, self.metadata.finetune, self.metadata.version, expert_count, weight_estimate, output_type)
# Filename Output
if fname_out is not None:
@ -229,37 +236,36 @@ class Model:
return new_name
def set_gguf_meta_model(self):
self.gguf_writer.add_name(self.model_name)
self.gguf_writer.add_name(self.metadata.name)
if self.metadata is not None:
if self.metadata.basename is not None:
self.gguf_writer.add_basename(self.metadata.basename)
if self.metadata.finetune is not None:
self.gguf_writer.add_finetune(self.metadata.finetune)
if self.metadata.author is not None:
self.gguf_writer.add_author(self.metadata.author)
if self.metadata.version is not None:
self.gguf_writer.add_version(self.metadata.version)
if self.metadata.base_version is not None:
self.gguf_writer.add_base_version(self.metadata.base_version)
if self.metadata.url is not None:
self.gguf_writer.add_url(self.metadata.url)
if self.metadata.description is not None:
self.gguf_writer.add_description(self.metadata.description)
if self.metadata.license is not None:
self.gguf_writer.add_license(self.metadata.license)
if self.metadata.source_url is not None:
self.gguf_writer.add_source_url(self.metadata.source_url)
if self.metadata.source_hf_repo is not None:
self.gguf_writer.add_source_hf_repo(self.metadata.source_hf_repo)
if self.metadata.parameter_size_class is not None:
self.gguf_writer.add_parameter_size_class(self.metadata.parameter_size_class)
if self.metadata.tags is not None:
self.gguf_writer.add_tags(self.metadata.tags)
if self.metadata.languages is not None:
self.gguf_writer.add_languages(self.metadata.languages)
if self.metadata.datasets is not None:
self.gguf_writer.add_datasets(self.metadata.datasets)
if self.metadata.basename is not None:
self.gguf_writer.add_basename(self.metadata.basename)
if self.metadata.finetune is not None:
self.gguf_writer.add_finetune(self.metadata.finetune)
if self.metadata.author is not None:
self.gguf_writer.add_author(self.metadata.author)
if self.metadata.version is not None:
self.gguf_writer.add_version(self.metadata.version)
if self.metadata.base_version is not None:
self.gguf_writer.add_base_version(self.metadata.base_version)
if self.metadata.url is not None:
self.gguf_writer.add_url(self.metadata.url)
if self.metadata.description is not None:
self.gguf_writer.add_description(self.metadata.description)
if self.metadata.license is not None:
self.gguf_writer.add_license(self.metadata.license)
if self.metadata.source_url is not None:
self.gguf_writer.add_source_url(self.metadata.source_url)
if self.metadata.source_hf_repo is not None:
self.gguf_writer.add_source_hf_repo(self.metadata.source_hf_repo)
if self.metadata.parameter_size_class is not None:
self.gguf_writer.add_parameter_size_class(self.metadata.parameter_size_class)
if self.metadata.tags is not None:
self.gguf_writer.add_tags(self.metadata.tags)
if self.metadata.languages is not None:
self.gguf_writer.add_languages(self.metadata.languages)
if self.metadata.datasets is not None:
self.gguf_writer.add_datasets(self.metadata.datasets)
def set_gguf_parameters(self):
self.gguf_writer.add_block_count(self.block_count)
@ -415,23 +421,30 @@ class Model:
self.gguf_writer.write_kv_data_to_file()
self.gguf_writer.close()
# Set model name based on latest metadata either provided or calculated from environment
@staticmethod
def get_model_name(metadata, huggingface_parameters, dir_model, model_arch):
if metadata is not None and metadata.name is not None:
# Explicit Metadata Was Provided By User
return metadata.name
elif huggingface_parameters is not None and "_name_or_path" in huggingface_parameters:
# Hugging Face Parameters Model Name or Model Folder Name is Provided
return huggingface_parameters["_name_or_path"]
elif huggingface_parameters is not None and "model_type" in huggingface_parameters:
# Hugging Face Parameters Model Type is Provided
return huggingface_parameters["model_type"]
elif dir_model is not None and dir_model.name is not None:
# Use directory folder name
return dir_model.name
else:
return gguf.MODEL_ARCH_NAMES[model_arch]
def per_model_weight_count_estimation(tensors: Iterator[tuple[str, Tensor]], expert_count: int) -> int:
# TODO: Ensure parameter count is accurate throughout various model type
# May currently overestimate parameter count in Mamba model because
# output weights is tied with token embeddings.
sum_weight_estimate = 0
for name, data_torch in tensors:
# Got A Tensor
# We don't need these
if name.endswith((".attention.masked_bias", ".attention.bias", ".rotary_emb.inv_freq")):
continue
# Calculate Tensor Volume
sum_weights_in_tensor = 1
for dim in data_torch.shape:
sum_weights_in_tensor *= dim
# Add Tensor Volume To Running Count
sum_weight_estimate += sum_weights_in_tensor
# Calculate weight estimate per model
per_model_weight_estimate = (sum_weight_estimate / expert_count) if (expert_count > 0) else sum_weight_estimate
return per_model_weight_estimate
@staticmethod
def get_model_part_names(dir_model: Path, prefix: str, suffix: str) -> list[str]:

View file

@ -773,7 +773,7 @@ class OutputFile:
def add_meta_model(self, params: Params, metadata: gguf.Metadata | None) -> None:
# Metadata About The Model And Its Provenence
name = "LLaMA"
if metadata is not None and metadata.name is not None:
if metadata.name is not None:
name = metadata.name
elif params.path_model is not None:
name = params.path_model.name
@ -783,29 +783,28 @@ class OutputFile:
self.gguf.add_name(name)
if metadata is not None:
if metadata.basename is not None:
self.gguf.add_basename(metadata.basename)
if metadata.finetune is not None:
self.gguf.add_finetune(metadata.finetune)
if metadata.author is not None:
self.gguf.add_author(metadata.author)
if metadata.version is not None:
self.gguf.add_version(metadata.version)
if metadata.base_version is not None:
self.gguf.add_base_version(metadata.base_version)
if metadata.url is not None:
self.gguf.add_url(metadata.url)
if metadata.description is not None:
self.gguf.add_description(metadata.description)
if metadata.license is not None:
self.gguf.add_license(metadata.license)
if metadata.source_url is not None:
self.gguf.add_source_url(metadata.source_url)
if metadata.source_hf_repo is not None:
self.gguf.add_source_hf_repo(metadata.source_hf_repo)
if metadata.tags is not None:
self.gguf_writer.add_tags(metadata.tags)
if metadata.basename is not None:
self.gguf.add_basename(metadata.basename)
if metadata.finetune is not None:
self.gguf.add_finetune(metadata.finetune)
if metadata.author is not None:
self.gguf.add_author(metadata.author)
if metadata.version is not None:
self.gguf.add_version(metadata.version)
if metadata.base_version is not None:
self.gguf.add_base_version(metadata.base_version)
if metadata.url is not None:
self.gguf.add_url(metadata.url)
if metadata.description is not None:
self.gguf.add_description(metadata.description)
if metadata.license is not None:
self.gguf.add_license(metadata.license)
if metadata.source_url is not None:
self.gguf.add_source_url(metadata.source_url)
if metadata.source_hf_repo is not None:
self.gguf.add_source_hf_repo(metadata.source_hf_repo)
if metadata.tags is not None:
self.gguf_writer.add_tags(metadata.tags)
def add_meta_arch(self, params: Params) -> None:
# Metadata About The Neural Architecture Itself
@ -1197,10 +1196,10 @@ class VocabFactory:
def default_convention_outfile(file_type: GGMLFileType, model_name:str, expert_count:int, model_params_count: int, metadata: gguf.Metadata) -> str:
name = metadata.name if metadata is not None and metadata.name is not None else model_name
basename = metadata.basename if metadata is not None and metadata.basename is not None else None
finetune = metadata.finetune if metadata is not None and metadata.finetune is not None else None
version = metadata.version if metadata is not None and metadata.version is not None else None
name = metadata.name if metadata.name is not None else model_name
basename = metadata.basename if metadata.basename is not None else None
finetune = metadata.finetune if metadata.finetune is not None else None
version = metadata.version if metadata.version is not None else None
output_type = {
GGMLFileType.AllF32: "F32",

View file

@ -1,10 +1,5 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Iterator
if TYPE_CHECKING:
from torch import Tensor
def fill_templated_filename(filename: str, output_type: str):
# Given a file name fill in any type templates e.g. 'some-model-name.{ftype}.gguf'
@ -15,32 +10,6 @@ def fill_templated_filename(filename: str, output_type: str):
OUTTYPE=ftype_uppercase, FTYPE=ftype_uppercase)
def per_model_weight_count_estimation(tensors: Iterator[tuple[str, Tensor]], expert_count: int) -> int:
# TODO: Ensure parameter count is accurate throughout various model type
# May currently overestimate parameter count in Mamba model because
# output weights is tied with token embeddings.
sum_weight_estimate = 0
for name, data_torch in tensors:
# Got A Tensor
# We don't need these
if name.endswith((".attention.masked_bias", ".attention.bias", ".rotary_emb.inv_freq")):
continue
# Calculate Tensor Volume
sum_weights_in_tensor = 1
for dim in data_torch.shape:
sum_weights_in_tensor *= dim
# Add Tensor Volume To Running Count
sum_weight_estimate += sum_weights_in_tensor
# Calculate weight estimate per model
per_model_weight_estimate = (sum_weight_estimate / expert_count) if (expert_count > 0) else sum_weight_estimate
return per_model_weight_estimate
def model_weight_count_rounded_notation(model_params_count: int) -> str:
if model_params_count > 1e15 :
# Quadrillion Of Parameters