HuggingFace镜像/granite-3.0-3b-a800m-instruct-GGUF
模型介绍文件和版本分析
下载使用量0

granite-3.0-3b-a800m-instruct 的 Llamacpp imatrix 量化版本

使用 llama.cpp 版本 b3930 进行量化。

原始模型:https://huggingface.co/ibm-granite/granite-3.0-3b-a800m-instruct

所有量化版本均使用 imatrix 选项,并基于 此处 的数据集制作。

可在 LM Studio 中运行。

提示词格式

<|start_of_role|>system<|end_of_role|>{system_prompt}<|end_of_text|>
<|start_of_role|>user<|end_of_role|>{prompt}<|end_of_text|>
<|start_of_role|>assistant<|end_of_role|>

在 openmind 中的使用

注意:目前 trans 不支持加载 granitemoe 相关模型,手动编写可以加载,但分词器可能存在问题。

import os
import time
import argparse
import torch
from torch import nn
import numpy as np
import logging

from transformers.integrations import GGUF_TENSOR_MAPPING, GGUF_CONFIG_MAPPING
from transformers.modeling_gguf_pytorch_utils import GGUF_TO_TRANSFORMERS_MAPPING, GGUF_SUPPORTED_ARCHITECTURES
from transformers.integrations.ggml import GGUF_TO_FAST_CONVERTERS, GGUFGPTConverter

model_type = "granitemoe"

GGUF_TENSOR_MAPPING.update(
    {
        model_type: {
            "token_embd": "model.embed_tokens",
            "blk": "model.layers",
            "ffn_gate_exps": "block_sparse_moe.gate_linear",
            "ffn_up_exps": "block_sparse_moe.input_linear",
            "ffn_down_exps": "block_sparse_moe.output_linear",
            "ffn_gate_inp": "block_sparse_moe.router.layer",
            "ffn_norm": "post_attention_layernorm",
            "attn_norm": "input_layernorm",
            "attn_q": "self_attn.q_proj",
            "attn_v": "self_attn.v_proj",
            "attn_k": "self_attn.k_proj",
            "attn_output": "self_attn.o_proj",
            "output.weight": "lm_head.weight",
            "output_norm": "model.norm",
        }
    }
)

GGUF_CONFIG_MAPPING.update(
    {
        model_type: {
            "block_count": "num_hidden_layers",
            "context_length": "max_position_embeddings",
            "embedding_length": "hidden_size",
            "feed_forward_length": "intermediate_size",
            "attention.head_count": "num_attention_heads",
            "attention.head_count_kv": "num_key_value_heads",
            "rope.freq_base": "rope_theta",
            "attention.layer_norm_rms_epsilon": "rms_norm_eps",
            "expert_count": "num_local_experts",
            "expert_used_count": "num_experts_per_tok",
            "vocab_size": "vocab_size",
            "rope.dimension_count": None,
        },
    }
)

GGUF_TO_TRANSFORMERS_MAPPING.update(
    {
        "config": GGUF_CONFIG_MAPPING,
        "tensors": GGUF_TENSOR_MAPPING,
    }
)

GGUF_SUPPORTED_ARCHITECTURES.append(model_type)

GGUF_TO_FAST_CONVERTERS.update(
    {
        model_type: GGUFGPTConverter,
    }
)

# 修改 transformers 包中的 GraniteMoeMoE 类
def modify_granitemoe():
    import transformers.models.granitemoe.modeling_granitemoe as granitemoe

    class ModifiedGraniteMoeMoE(nn.Module):
        def __init__(self, config: granitemoe.GraniteMoeConfig):
            super(ModifiedGraniteMoeMoE, self).__init__()

            self.input_size = config.hidden_size
            self.hidden_size = config.intermediate_size
            self.activation = granitemoe.ACT2FN[config.hidden_act]
            
            self.gate_linear = granitemoe.GraniteMoeParallelExperts(config.num_local_experts, self.input_size, self.hidden_size)
            self.input_linear = granitemoe.GraniteMoeParallelExperts(config.num_local_experts, self.input_size, self.hidden_size)
            self.output_linear = granitemoe.GraniteMoeParallelExperts(config.num_local_experts, self.hidden_size, self.input_size)
            self.router = granitemoe.GraniteMoeTopKGating(
                input_size=self.input_size,
                num_experts=config.num_local_experts,
                top_k=config.num_experts_per_tok,
            )

        def forward(self, layer_input):
            bsz, length, emb_size = layer_input.size()
            layer_input = layer_input.reshape(-1, emb_size)
            _, batch_index, batch_gates, expert_size, router_logits = self.router(layer_input)

            expert_inputs = layer_input[batch_index]
            hidden_states = self.activation(self.gate_linear(expert_inputs, expert_size)) * self.input_linear(expert_inputs, expert_size)
            expert_outputs = self.output_linear(hidden_states, expert_size)

            expert_outputs = expert_outputs * batch_gates[:, None]

            zeros = torch.zeros((bsz * length, self.input_size), dtype=expert_outputs.dtype, device=expert_outputs.device)
            layer_output = zeros.index_add(0, batch_index, expert_outputs)
            layer_output = layer_output.view(bsz, length, self.input_size)
            return layer_output, router_logits

    granitemoe.GraniteMoeMoE = ModifiedGraniteMoeMoE

# 在导入 transformers 之前调用修改函数
modify_granitemoe()
# ------------------------------------------------

def parse_args():
    parser = argparse.ArgumentParser(description="NPU Inference for Text Generation Model")
    parser.add_argument(
        "--model_name_or_path",
        "-m",
        type=str,
        help="Path to model",
        default=".",
    )
    parser.add_argument(
        "--inference_mode",
        "-i",
        type=str,
        help="Inference mode",
        default="gguf",
    )
    parser.add_argument(
        "--gguf_file",
        "-g",
        type=str,
        help="Path to GGUF file",
        default="granite-3.0-3b-a800m-instruct-Q4_0.gguf",
    )
    parser.add_argument(
        "--debug",
        action="store_true",
        help="Debug mode",
    )
    return parser.parse_args()

def set_logging(model_name):
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        handlers=[
            logging.FileHandler(f"{model_name}_inference.log"),
            logging.StreamHandler(),
        ],
    )

args = parse_args()
set_logging(os.path.basename(args.model_name_or_path))

if args.debug:
    logging.info("Debug mode enabled, using transformers package from source.")
    from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, is_torch_npu_available
else:
    logging.info("Debug mode disabled, using openmind package.")
    from openmind import AutoTokenizer, AutoModelForCausalLM, pipeline, is_torch_npu_available

def load_model_from_gguf(model_path: str, device_map="auto"):
    gguf_filename = args.gguf_file
    tokenizer = AutoTokenizer.from_pretrained(model_path, gguf_file=gguf_filename, tokenizer_type="gpt2")
    tokenizer.pad_token = tokenizer.eos_token
    model = AutoModelForCausalLM.from_pretrained(model_path, gguf_file=gguf_filename, device_map=device_map)
    return tokenizer, model

def load_model_from_local(model_path: str, device_map="auto"):
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    model = AutoModelForCausalLM.from_pretrained(model_path, device_map=device_map)
    return tokenizer, model

def load_model_from_pipeline(model_path: str, device_map="auto", task="text-generation"):
    pipeline_pt = pipeline(
        task=task,
        model=model_path,
        device_map=device_map,
        framework="pt",
        truncation=True,
    )
    return pipeline_pt.tokenizer, pipeline_pt

def load_model(mode: str, *args, **kwargs):
    if mode == "gguf":
        return load_model_from_gguf(*args, **kwargs)
    elif mode == "model":
        return load_model_from_local(*args, **kwargs)
    elif mode == "pipeline":
        return load_model_from_pipeline(*args, **kwargs)
    else:
        raise ValueError(f"load_model Unknown mode: {mode}")
    

def generate_text_form_model(tokenizer, model, prompt, max_new_tokens=50):
    inputs = tokenizer(prompt, return_tensors="pt", padding=True).to(model.device)
    output = model.generate(
        input_ids=inputs['input_ids'], 
        attention_mask=inputs['attention_mask'],
        max_new_tokens=max_new_tokens,
    )
    return tokenizer.decode(output[0], skip_special_tokens=True)

def generate_text_from_pipeline(tokenizer, pipeline, prompt, max_new_tokens=50):
    results = pipeline(
        prompt,
        max_new_tokens=max_new_tokens,
    )
    return results[0]["generated_text"]

def generate_text(mode: str, *args, **kwargs):
    if mode == "model" or mode == "gguf":
        return generate_text_form_model(*args, **kwargs)
    elif mode == "pipeline":
        return generate_text_from_pipeline(*args, **kwargs)
    else:
        raise ValueError(f"generate_text Unknown mode: {mode}")

def apply_chat_template(tokenizer, tokenize=False):
    if tokenizer.chat_template is None:
        print("Chat template is not defined, use default template.")
        tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"
    chat = [
        {
            "role": "system",
            "content": "You are a helpful assistant who always responds in a friendly manner",
        },
        {
            "role": "user",
            "content": "Why does the ocean appear blue?",
        },
    ]
    chat_input = tokenizer.apply_chat_template(chat, tokenize=tokenize)
    return chat_input

def main():
    model_path = args.model_name_or_path
    abs_model_path = os.path.abspath(model_path)
    model_name = os.path.basename(abs_model_path)
    logging.info(f"测试模型: {model_name}")
    logging.info(f"模型路径: {model_path}")
    logging.info(f"绝对路径: {abs_model_path}")
    inference_mode = args.inference_mode
    logging.info(f"推理模式: {inference_mode}")
    
    # 确保使用 NPU 设备
    device_map = "auto" if is_torch_npu_available() else "cpu"
    logging.info(f"NPU {'available' if device_map == 'auto' else 'not available'}, use device_map='{device_map}'.")

    # 加载模型
    tokenizer, task_pipeline = load_model(mode=inference_mode, model_path=model_path, device_map=device_map)
    prompt = apply_chat_template(tokenizer, tokenize=False)

    # 推理性能测试
    inference_times = []
    num_runs = 10

    logging.info(f"\n=== NPU {model_name} 性能测试 ===")

    for i in range(num_runs):
        input_text = prompt

        start_time = time.time()
        
        results = generate_text(inference_mode, tokenizer, task_pipeline, input_text)
        # torch.npu.synchronize()

        inference_time = time.time() - start_time
        inference_times.append(inference_time)

        if i == 0:
            logging.info(f"输入文本: {input_text}")
            logging.info("生成结果:")
            logging.info(f"  {results}")

    avg_time = np.mean(inference_times)
    std_time = np.std(inference_times)

    logging.info("\n性能分析:")
    logging.info(f"NPU平均推理时间: {avg_time:.4f} 秒")
    logging.info(f"NPU推理时间标准差: {std_time:.4f} 秒")
    logging.info(f"推理时间列表: {inference_times}")


if __name__ == "__main__":
    main()

从下方下载文件(非整个分支):

文件名量化类型文件大小拆分描述
granite-3.0-3b-a800m-instruct-f16.gguff166.75GBfalse完整的 F16 权重。
granite-3.0-3b-a800m-instruct-Q8_0.ggufQ8_03.59GBfalse极高质量,通常无需使用,但为最大可用量化版本。
granite-3.0-3b-a800m-instruct-Q6_K_L.ggufQ6_K_L2.81GBfalse嵌入和输出权重使用 Q8_0。质量非常高,接近完美,推荐。
granite-3.0-3b-a800m-instruct-Q6_K.ggufQ6_K2.78GBfalse质量非常高,接近完美,推荐。
granite-3.0-3b-a800m-instruct-Q5_K_L.ggufQ5_K_L2.45GBfalse嵌入和输出权重使用 Q8_0。高质量,推荐。
granite-3.0-3b-a800m-instruct-Q5_K_M.ggufQ5_K_M2.41GBfalse高质量,推荐。
granite-3.0-3b-a800m-instruct-Q5_K_S.ggufQ5_K_S2.34GBfalse高质量,推荐。
granite-3.0-3b-a800m-instruct-Q4_K_L.ggufQ4_K_L2.12GBfalse嵌入和输出权重使用 Q8_0。良好质量,推荐。
granite-3.0-3b-a800m-instruct-Q4_K_M.ggufQ4_K_M2.06GBfalse良好质量,在必须使用场景下的默认大小,推荐。
granite-3.0-3b-a800m-instruct-Q4_K_S.ggufQ4_K_S1.94GBfalse质量略低,但节省更多空间,推荐。
granite-3.0-3b-a800m-instruct-Q4_0_8_8.ggufQ4_0_8_81.93GBfalse针对 ARM 推理优化。需要“sve”支持(见下方链接)。不要在 Mac 或 Windows 上使用。
granite-3.0-3b-a800m-instruct-Q4_0_4_8.ggufQ4_0_4_81.93GBfalse针对 ARM 推理优化。需要“i8mm”支持(见下方链接)。不要在 Mac 或 Windows 上使用。
granite-3.0-3b-a800m-instruct-Q4_0_4_4.ggufQ4_0_4_41.93GBfalse针对 ARM 推理优化。在所有 ARM 芯片上应能良好运行,如不确定请选择此版本。不要在 Mac 或 Windows 上使用。
granite-3.0-3b-a800m-instruct-Q4_0.ggufQ4_01.93GBfalse旧版格式,总体而言不值得优先于相似大小的其他格式使用
granite-3.0-3b-a800m-instruct-Q3_K_XL.ggufQ3_K_XL1.84GBfalse嵌入和输出权重使用 Q8_0。质量较低但仍可使用,适合 RAM 可用空间有限的情况。
granite-3.0-3b-a800m-instruct-IQ4_XS.ggufIQ4_XS1.82GBfalse质量尚可,比 Q4_K_S 更小且性能相近,推荐。
granite-3.0-3b-a800m-instruct-Q3_K_L.ggufQ3_K_L1.77GBfalse质量较低但仍可使用,适合 RAM 可用空间有限的情况。
granite-3.0-3b-a800m-instruct-Q3_K_M.ggufQ3_K_M1.64GBfalse低质量。
granite-3.0-3b-a800m-instruct-IQ3_M.ggufIQ3_M1.52GBfalse中低质量,新方法,性能尚可,与 Q3_K_M 相当。
granite-3.0-3b-a800m-instruct-Q3_K_S.ggufQ3_K_S1.49GBfalse低质量,不推荐。
granite-3.0-3b-a800m-instruct-IQ3_XS.ggufIQ3_XS1.41GBfalse较低质量,新方法,性能尚可,略优于 Q3_K_S。
granite-3.0-3b-a800m-instruct-Q2_K_L.ggufQ2_K_L1.34GBfalse嵌入和输出权重使用 Q8_0。质量极低,但出乎意料地仍可使用。
granite-3.0-3b-a800m-instruct-Q2_K.ggufQ2_K1.27GBfalse质量极低,但出乎意料地仍可使用。

嵌入/输出权重

部分量化版本(如Q3_K_XL、Q4_K_L等)采用标准量化方法,其中嵌入权重和输出权重被量化为Q8_0,而非默认的量化方式。

有人认为这种方式能提升模型质量,也有人未察觉任何差异。如果您使用这些模型,请留言分享您的使用体验。我希望收到反馈,了解这些模型是否真的被使用且有用,这样我就不会继续上传无人使用的量化版本了。

谢谢!

使用huggingface-cli下载

首先,请确保已安装huggingface-cli:

pip install -U "huggingface_hub[cli]"

然后,你可以定位到你想要的特定文件:

huggingface-cli download bartowski/granite-3.0-3b-a800m-instruct-GGUF --include "granite-3.0-3b-a800m-instruct-Q4_K_M.gguf" --local-dir ./

如果模型大于50GB,它会被拆分为多个文件。要将所有文件下载到本地文件夹,请运行:

huggingface-cli download bartowski/granite-3.0-3b-a800m-instruct-GGUF --include "granite-3.0-3b-a800m-instruct-Q8_0/*" --local-dir ./

你可以指定一个新的本地目录(granite-3.0-3b-a800m-instruct-Q8_0),也可以将它们全部下载到当前位置(./)。

Q4_0_X_X

这些不适用于 Metal(Apple)卸载,仅适用于 ARM 芯片。

如果你使用的是 ARM 芯片,Q4_0_X_X 量化版本将带来显著的速度提升。可以查看原始拉取请求中的 Q4_0_4_4 速度对比原始拉取请求。

要确定哪种版本最适合你的 ARM 芯片,可以查看AArch64 SoC 特性(感谢 EloyOn!)。

应该选择哪个文件?

Artefact2 提供了一篇很棒的文章,其中包含显示各种性能的图表,详见此处。

首先要弄清楚你能运行多大的模型。为此,你需要知道自己有多少 RAM 和/或 VRAM。

如果你希望模型运行得尽可能快,那么最好将整个模型放入 GPU 的 VRAM 中。目标是选择文件大小比 GPU 总 VRAM 小 1-2GB 的量化版本。

如果你追求绝对的最高质量,可以将系统 RAM 和 GPU 的 VRAM 加起来,然后同样选择文件大小比这个总和小 1-2GB 的量化版本。

接下来,你需要决定是使用“I-quant”还是“K-quant”。

如果你不想过多思考,选择 K-quant 版本之一即可。这些版本的格式为“QX_K_X”,例如 Q5_K_M。

如果你想深入了解,可以查看这个非常有用的特性图表:

llama.cpp 特性矩阵

但基本上,如果你目标是 Q4 及以下,并且正在运行 cuBLAS(Nvidia)或 rocBLAS(AMD),那么你应该考虑 I-quant 版本。这些版本的格式为 IQX_X,例如 IQ3_M。它们是较新的版本,在相同大小下提供更好的性能。

这些 I-quant 版本也可以在 CPU 和 Apple Metal 上使用,但会比相应的 K-quant 版本慢,因此你需要在速度和性能之间做出权衡。

I-quant 版本不与 Vulkan(同样适用于 AMD)兼容,因此如果你有 AMD 显卡,请仔细检查你使用的是 rocBLAS 构建版本还是 Vulkan 构建版本。在撰写本文时,LM Studio 已有支持 ROCm 的预览版,其他推理引擎也有针对 ROCm 的特定构建版本。

致谢

感谢 kalomaze 和 Dampf 在创建 imatrix 校准数据集过程中提供的帮助。

感谢 ZeroWw 为嵌入/输出实验带来的启发。

想要支持我的工作?请访问我的 ko-fi 页面:https://ko-fi.com/bartowski