权重是一个浮点数。仅此而已。网络中两个神经元之间的每条连接都携带这样一个数字,而现代大型语言模型拥有数十亿个这样的数字——按层排列成巨大的矩阵。在训练开始之前,这些矩阵会被填充看似随机的值(稍后会详细说明初始化)。然后网络看到数据,通过损失函数计算预测的错误程度,并通过反向传播将该误差的梯度反向传递到每一层,使每个权重朝着减少预测错误的方向微小地调整。在数万亿字节的文本上重复这个过程数十亿次,你将得到一个能够写诗、解释量子力学或调试你代码的模型。所有这些学习到的能力都储存在权重中。没有单独的知识库,没有事实数据库——只有通过纯粹的统计压力,将数字矩阵组织成看起来像理解的东西。
你存储这些数字的格式可能比你想象的更重要。全精度权重使用 fp32——32位浮点数——这提供了大约7位小数的精度和巨大的动态范围。研究人员多年来一直使用它,它仍然是数值稳定性的黄金标准。但 fp32 很昂贵:一个70亿参数的模型在 fp32 下仅权重就需要28GB,还不包括优化器状态或激活值。半精度 fp16 可以将这个数字减半,但其有限的指数范围在训练过程中容易溢出或下溢。于是出现了 bf16——bfloat16——它保留了 fp32 的指数范围,但将尾数截断为16位。Google专门为深度学习开发了它,因为它在使用一半内存的情况下很少出现数值爆炸,因此已成为训练的默认标准。对于推理,你可以进一步压缩:int8 量化将权重打包成8位整数(仅为 fp32 的四分之一大小),而质量损失却很小;int4——由GPTQ和AWQ方法率先提出——再次减半。一个需要140GB fp16存储的700亿参数模型,在4位精度下仅需约35GB,这就是为什么量化是你能在消费级GPU上运行大型模型的原因。
当你下载模型时,文件格式决定了这些权重矩阵如何序列化到磁盘。多年来,默认使用的是PyTorch的.bin格式,它只是将张量用Python的pickle序列化。这虽然可行,但pickle有一个众所周知的安全问题:恶意.bin文件在加载时可以执行任意代码。Hugging Face专门创建了safetensors来解决这个问题——它是一个简单的内存映射格式,仅包含张量数据和元数据,无法执行代码。safetensors加载速度也更快,因为它支持懒加载和零拷贝读取。它已成为在Hugging Face及更广泛领域分发模型的标准。还有GGUF,这是llama.cpp和更广泛的本地推理生态系统使用的格式。GGUF将权重、分词器配置和模型元数据打包成一个自包含文件,通常内置量化。如果你在笔记本电脑或消费级GPU上本地运行模型,你几乎肯定在使用GGUF文件。简而言之:safetensors用于分发和微调,GGUF用于本地推理,而只有在遇到旧版检查点时才使用.bin。
即使在训练开始之前,你放入这些权重矩阵的值就决定了后续的一切。如果全部初始化为零,网络无法学习——每一层中的每个神经元都计算相同的内容,梯度相同,对称性永远不会打破。如果初始化值太大,激活值会爆炸;如果太小,梯度在到达早期层之前就会消失到零。Xavier初始化(2010年)通过根据输入和输出连接数(即扇入和扇出)缩放初始权重,解决了sigmoid和tanh网络的这一问题。Kaiming初始化(2015年,来自He等人论文)将这一想法调整为适用于ReLU激活函数,因为它们的行为不同,会将一半输入置零。现代Transformer通常使用这些方法的变体,有时还会为注意力层调整额外的缩放因子。还有彩票假设(Frankle & Carlin,2019年),它表明在随机初始化的网络中,存在一些小的子网络——“中奖票”——可以独立训练以匹配完整网络的性能。这一发现令人印象深刻:这些数十亿初始权重中的大部分可能都是不必要的,理论上正确的稀疏初始化可以以极小的规模实现相同模型。在实践中,可靠地找到这些中奖票仍然昂贵,但这一想法已经塑造了研究人员对剪枝和高效架构的思考方式。
人们几乎可以互换使用“权重”和“参数”,对于大多数目的来说这没有问题——但技术上,参数包括偏置(每个神经元加权和后添加的小常数)以及任何其他学习到的值,如层归一化缩放因子。在典型的Transformer中,偏置仅占总参数的一小部分,所以当有人说一个模型有700亿参数时,实际上指的是700亿权重。更深层次的要点是,当你下载模型的权重文件时,你下载的是模型所学到的一切。架构——层数、宽度、激活函数——只是蓝图。权重是建筑本身。两个架构相同但权重不同的模型,如果在不同数据或不同训练时长下训练,行为会完全不同。这就是为什么“发布权重”如此重要:你不是在分享一个设计,而是在分享数百万美元计算和数月训练积累的结果。知识存在于数字之中。