大语言模型 从主流大模型到llama权重文件解析和参数计算

一、大语言模型

目前我们关注的GPT、Llama都属于大语言模型。

  • Llama:已在大量数据集上完成训练,具备文本分类、生成、摘要等能力;通过“迁移学习”,可在特定任务上快速微调。
  • 大语言模型的核心特点:
  1. 更大规模的训练数据:覆盖各类知识、文本类型,提升泛化能力;
  2. 更复杂的模型结构:通常采用更深的神经网络结构;
  3. 更强的生成能力:能生成连贯、有意义的文本;
  4. 更强的泛化能力:少量数据即可适配不同任务;
  5. 零样本学习能力:无需小样本,仅通过指令即可完成任务。

二、GPT简介

GPT是OpenAI基于Transformer架构的语言模型,核心特点是自回归预训练,可用于文本生成、翻译、问答等任务。

  • ChatGPT:基于GPT系列模型的对话微调版本,通过大规模对话数据优化,提升了上下文理解与对话流畅度;
  • GPT-4:在多模态能力(文本+图像)、逻辑推理等方面升级,2023年3月发布,性能优于此前的GPT-3系列。

三、Llama简介

Llama是Meta推出的开源大语言模型(含Llama 1、Llama 2),特点是仅使用公开数据训练,性能接近GPT-3.5。

  • Llama 2:在Llama 1基础上升级,支持更长上下文、更强数据清洗;其对话版本Llama 2-Chat通过人类反馈优化(RLHF),提升了安全性与实用性。
  • Llama 2开源模型名称:
模型 Llama 2-Chat
7B Llama-2-7b-chat-hf
13B Llama-2-13b-chat-hf
70B Llama-2-70b-chat-hf

四、Llama的训练

1. 训练数据

Llama仅使用公开可得数据训练,Llama 1预训练数据约含1.4T tokens

Llama 2训练数据扩展至2万亿标记,同时剔除了含私人信息的数据源。

2. 预训练

Llama 2基于Llama 1的架构,优化点包括:更强数据清洗、更长上下文长度、分组查询注意力机制。

训练损失:在2T标记的预训练后,各参数模型(7B/13B/70B)均未出现损失饱和。

五、Llama 2 Chat

Llama 2 Chat是Llama 2基础上针对对话微调的模型,通过监督微调+人类反馈强化学习(RLHF) 优化。

1. 监督微调

  • 基于预训练的Llama 2,在人工编写的指令数据集(27540条prompt+answer)上微调;
  • 合并prompt与answer,保证序列长度为4096,训练时仅对回答部分反向传播。

2. 基于人类反馈的强化学习(RLHF)

目标是对齐人类偏好与指令遵循,核心步骤:

  1. 收集人类偏好数据:通过二元比较标注模型回应的“有用性”“安全性”,构建百万级数据集;
  2. 奖励模型:训练两个独立的奖励模型(有用性RM/安全性RM),避免两者相互抵消;
  • 数据配比:有用性RM采用“Meta Helpfulness: (Meta Safety+开源)=1:1”,安全性RM采用“Meta Safety: (Meta Helpfulness+开源)=9:1”;
  1. 迭代微调:使用近端策略优化(PPO)、拒绝采样微调两种算法,提升模型的对话效果。

六、Llama 2权重文件夹内容整理

1、权重文件格式分类

Llama 2发布时提供两种权重文件格式:

  1. pth格式(原始格式):如 Llama-2-7b ,目录包含 checklist.chk 、 unconsolidated.00.pth 、 params.json 等文件;
  2. hf格式(HuggingFace格式):如 Llama-2-7b-hf ,是主流使用格式。

2、Llama-2-7b-hf权重文件夹目录

plaintext

├── config.json # 模型配置(架构、超参数、特殊标记)
├── generation_config.json # 生成器配置(文本生成方式)
├── pytorch_model-00001-of-00002.bin # 权重文件1(约9.9GB)
├── pytorch_model-00002-of-00002.bin # 权重文件2(约3.5GB)
├── pytorch_model.bin.index.json # 权重文件索引(快速加载)
├── README.md # 说明文档
├── special_tokens_map.json # 特殊标记定义(起始/结束/未知标记)
├── tokenizer.model # 分词器二进制文件
├── tokenizer.json # 分词器配置(JSON格式)
└── tokenizer_config.json # 分词器初始化配置

3、核心文件说明

  1. .bin权重文件
  • 模型训练后的参数文件,因体积(13G)超过10GB被拆分;
  • 包含神经网络的权重、偏置等可学习参数。
  1. 配置类文件
  • config.json :定义模型架构(如 LlamaForCausalLM )、嵌入维度( hidden_size )、注意力头数( num_attention_heads )等;
  • generation_config.json :控制文本生成的参数(如 bos_token_id 、 eos_token_id );
  • special_tokens_map.json :定义特殊标记(如 bos_token: 、 eos_token: )。
  1. 分词器相关文件
  • tokenizer.model / tokenizer.json :存储词表与分词规则;
  • tokenizer_config.json :分词器初始化参数。

七、Llama 2模型参数计算与权重文件解析(含代码实战)

1、Llama 2模型超参数

Llama 2不同尺寸模型的核心超参数如下:

参数数量 模型大小 嵌入维度 d_model 层数 L 中间维度 d_ff
6.7B 13476839424 4096 32 11008
13.0B 26031738880 5120 40 13824
32.5B 65057902592 6656 60 17920
70B 137953316864 8192 80 28672

2、标准Transformer解码器参数计算

以GPT-3(125M参数)为例,参数来自词嵌入层、Transformer层、输出层:

  1. 词嵌入层: V × d_model ( V 为词汇表大小)
  2. Transformer层:每层包含自注意力机制、前馈网络、层归一化,公式为:

4×dmodel2+2×df×dmodel+df+5×dmodel4×d_model² + 2×d_f×d_model + d_f + 5×d_model4×dmodel2+2×df×dmodel+df+5×dmodel

  1. 输出层:与词嵌入层参数共享,数量为 V × d_model

3、Llama 2权重文件解析(HF格式)

HF格式的Llama 2权重以 .bin 文件存储(拆分多个文件),每个文件是zip压缩包,包含 data.pkl (序列化的参数数据)。

代码示例:解析Llama 2权重文件,用于读取HF格式的Llama 2权重文件,解析参数形状、类型并统计数量:

import pickle
import zipfile
from pathlib import Path
from typing import IO, Any, Callable, Optional, List, Dict
from dataclasses import dataclass
import torch  # 需提前安装PyTorch

# 定义数据类型枚举(对应权重存储的类型)
DT_F16 = 'F16'    # 半精度浮点
DT_F32 = 'F32'    # 单精度浮点
DT_BF16 = 'DT_BF16'# 脑浮点数
DT_I32 = 'I32'    # 32位整数


# -------------------------- 数据类定义:描述权重存储信息 --------------------------
@dataclass
class LazyStorageKind:
    """描述权重的存储数据类型"""
    data_type: str  # 对应DT_F16/DT_F32等


@dataclass
class LazyStorage:
    """描述权重的存储位置与类型"""
    kind: LazyStorageKind  # 数据类型
    description: str       # 存储路径等描述信息


@dataclass
class LazyTensor:
    """描述权重张量的形状、类型"""
    shape: List[int]   # 张量形状(如[32000, 4096])
    data_type: str     # 数据类型
    description: str   # 附加描述


# -------------------------- 自定义反序列化类 --------------------------
class LazyUnpickler(pickle.Unpickler):
    """
    继承pickle.Unpickler,重写persistent_load和find_class方法,
    用于解析HF格式权重文件中的序列化数据
    """
    # 映射Torch存储类型到自定义的LazyStorageKind
    CLASSES = {
        ('torch.util', '_rebuild_tensor_v2'): lambda *args: args,
        ('torch', 'BFloat16Storage'): LazyStorageKind(DT_BF16),
        ('torch', 'HalfStorage'): LazyStorageKind(DT_F16),    # Half对应F16
        ('torch', 'FloatStorage'): LazyStorageKind(DT_F32),
        ('torch', 'IntStorage'): LazyStorageKind(DT_I32)
    }

    def __init__(self, fp: IO[bytes], data_base_path: str, zip_file: zipfile.ZipFile):
        super().__init__(fp)
        self.data_base_path = data_base_path  # 权重数据在zip包中的基础路径
        self.zip_file = zip_file              # zip文件对象

    def persistent_load(self, pid: Any) -> Any:
        """
        处理持久化对象(HF权重文件中用pid标记权重存储位置)
        """
        # 从pid中解析数据类型、文件名、偏移量等信息
        data_type = pid[1]
        filename = f"{self.data_base_path}/{pid[2]}"
        # 构造LazyStorage对象,描述权重的存储信息
        description = f"persistent data_type={data_type} path-in-zip={filename}"
        return LazyStorage(kind=self.CLASSES[('torch', data_type)], description=description)

    def find_class(self, module: str, name: str) -> Any:
        """
        重写类查找逻辑,映射Torch的存储类到自定义的LazyStorageKind
        """
        if not module.startswith('torch'):
            # 非Torch类,使用默认查找逻辑
            return super().find_class(module, name)
        # Torch类,使用CLASSES映射
        return self.CLASSES.get((module, name), super().find_class(module, name))


# -------------------------- 主函数:解析权重文件 --------------------------
if __name__ == '__main__':
    # 1. 指定要解析的权重文件路径(替换为你的Llama 2权重文件路径)
    weight_path = Path(r"")#此处填你的模型根目录

    # 2. 以二进制模式打开权重文件(HF的.bin是zip压缩包)
    with open(weight_path, 'rb') as fp:
        # 3. 打开zip压缩包
        with zipfile.ZipFile(fp) as zip_file:
            # 4. 找到zip包中的data.pkl文件(序列化的权重数据)
            pickle_paths = [name for name in zip_file.namelist() if name.endswith('.pkl')]
            assert len(pickle_paths) == 1, "权重文件中应只有一个data.pkl"  # 校验

            # 5. 打开data.pkl文件
            with zip_file.open(pickle_paths[0], 'r') as pickle_fp:
                # 6. 使用自定义的LazyUnpickler反序列化数据
                unpickler = LazyUnpickler(
                    fp=pickle_fp,
                    data_base_path=pickle_paths[0][:-4],  # 去掉.pkl后缀,得到基础路径
                    zip_file=zip_file
                )
                model_data = unpickler.load()  # 反序列化得到模型权重字典

    # 7. 统计并打印权重参数信息
    total_params = 0   # 总参数数量
    total_bytes = 0    # 总字节数

    # 遍历权重字典中的每个参数
    for param_name, lazy_tensor in model_data.items():
        # 打印参数名、形状、类型
        print(f"{param_name}: shape={lazy_tensor.shape} type={lazy_tensor.data_type}")
        
        # 计算当前参数的数量
        param_count = 1
        for dim in lazy_tensor.shape:
            param_count *= dim
        
        # 计算当前参数的字节数(F16占2字节,F32占4字节)
        if lazy_tensor.data_type == DT_F16:
            param_bytes = param_count * 2
        elif lazy_tensor.data_type == DT_F32:
            param_bytes = param_count * 4
        else:
            param_bytes = 0  # 其他类型暂不统计
        
        # 累加总数
        total_params += param_count
        total_bytes += param_bytes

    # 打印统计结果
    print(f"\n总参数数量: {total_params}")
    print(f"总字节数: {total_bytes} (约{total_bytes/1024/1024/1024:.2f}GB)")

第82行填写你自己的模型根目录喵

输出大概是这样

model.embed_tokens.weight: shape=[32000, 4096] type=F16
model.layers.0.self_attn.q_proj.weight: shape=[4096, 4096] type=F16
model.layers.0.self_attn.k_proj.weight: shape=[4096, 4096] type=F16
model.layers.0.self_attn.v_proj.weight: shape=[4096, 4096] type=F16
model.layers.0.self_attn.o_proj.weight: shape=[4096, 4096] type=F16
model.layers.0.self_attn.rotary_emb.inv_freq: shape=[64] type=F32
model.layers.0.mlp.gate_proj.weight: shape=[11008, 4096] type=F16
model.layers.0.mlp.up_proj.weight: shape=[11008, 4096] type=F16
model.layers.0.mlp.down_proj.weight: shape=[4096, 11008] type=F16
model.layers.0.input_layernorm.weight: shape=[4096] type=F16
model.layers.0.post_attention_layernorm.weight: shape=[4096]
......
model.layers.23.self_attn.q_proj.weight: shape=[4096, 4096] type=F16
model.layers.23.self_attn.k_proj.weight: shape=[4096, 4096] type=F16
model.layers.23.self_attn.v_proj.weight: shape=[4096, 4096] type=F16
model.layers.23.self_attn.o_proj.weight: shape=[4096, 4096] type=F16
model.layers.23.self_attn.rotary_emb.inv_freq: shape=[64] type=F32
model.layers.23.mlp.gate_proj.weight: shape=[11008, 4096] type=F16
model.layers.23.mlp.up_proj.weight: shape=[11008, 4096] type=F16
model.layers.23.mlp.down_proj.weight: shape=[4096, 11008] type=F16
model.layers.23.input_layernorm.weight: shape=[4096] type=F16
model.layers.23.post_attention_layernorm.weight: shape=[4096] type=F16

参数数量=4988274176,字节数=9976551424

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐