在消费级 gpu 上运行大规模模型是机器学习社区正面临的挑战。
语言模型的规模一直在变大,palm 有 540b 参数,opt、gpt-3 和 bloom 有大约 176b 参数,模型还在朝着更大的方向发展。
这些模型很难在易于访问的设备上运行。例如,bloom-176b 需要在 8 个 80gb a100 gpu(每个约 15000 美元)上运行才能完成推理任务,而微调 bloom-176b 则需要 72 个这样的 gpu。palm 等更大的模型将需要更多的资源。
我们需要找到方法来降低这些模型的资源需求,同时保持模型的性能。领域内已经开发了各种试图缩小模型大小的技术,例如量化和蒸馏。
bloom 是去年由 1000 多名志愿研究人员在一个名为「bigscience」的项目中创建的,该项目由人工智能初创公司 hugging face 利用法国政府的资金运作,今年 7 月 12 日 bloom 模型正式发布。
使用 int8 推理会大幅减少模型的内存占用,却不会降低模型的预测性能。基于此,来自华盛顿大学、meta ai 研究院等(原 facebook ai research )机构的研究员联合 huggingface 开展了一项研究,试图让经过训练的 bloom-176b 在更少的 gpu 上运行,并将所提方法完全集成到 huggingface transformers 中。
论文地址:https://arxiv.org/pdf/2208.07339.pdfgithub 地址:https://github.com/timdettmers/bitsandbytes
该研究为 transformer 提出了首个数十亿规模的 int8 量化过程,该过程不会影响模型的推理性能。它可以加载一个具有 16-bit 或 32-bit 权重的 175b 参数的 transformer,并将前馈和注意力投影层转换为 8-bit。其将推理所需的内存减少了一半,同时保持了全精度性能。
该研究将向量量化和混合精度分解的组合命名为 llm.int8()。实验表明,通过使用 llm.int8(),可以在消费级 gpu 上使用多达 175b 参数的 llm 执行推理,而不会降低性能。该方法不仅为异常值对模型性能的影响提供了新思路,还首次使在消费级 gpu 的单个服务器上使用非常大的模型成为可能,例如 opt-175b/bloom。
方法简介机器学习模型的大小取决于参数的数量及其精度,通常是 float32、float16 或 bfloat16 之一。float32 (fp32) 代表标准化的 ieee 32 位浮点表示,使用这种数据类型可以表示范围广泛的浮点数。fp32 为「指数」保留 8 位,为「尾数」保留 23 位,为数字的符号保留 1 位。并且,大多数硬件都支持 fp32 操作和指令。
而 float16 (fp16) 为指数保留 5 位,为尾数保留 10 位。这使得 fp16 数字的可表示范围远低于 fp32,面临溢出(试图表示一个非常大的数字)和下溢(表示一个非常小的数字)的风险。
出现溢出时会得到 nan(非数字)的结果,如果像在神经网络中那样进行顺序计算,那么很多工作都会崩溃。bfloat16 (bf16) 则能够避免这种问题。bf16 为指数保留 8 位,为小数保留 7 位,意味着 bf16 可以保留与 fp32 相同的动态范围。
理想情况下,训练和推理应该在 fp32 中完成,但它的速度比 fp16/bf16 慢,因此要使用混合精度来提高训练速度。但在实践中,半精度权重在推理过程中也能提供与 fp32 相似的质量。这意味着我们可以使用一半精度的权重并使用一半的 gpu 来完成相同的结果。
但是,如果我们可以使用不同的数据类型以更少的内存存储这些权重呢?一种称为量化的方法已广泛用于深度学习。
该研究首先在实验中用 2-byte bf16/fp16 半精度代替 4-byte fp32 精度,实现了几乎相同的推理结果。这样一来,模型减小了一半。但是如果进一步降低这个数字,精度会随之降低,那推理质量就会急剧下降。
为了弥补这一点,该研究引入 8bit 量化。这种方法使用四分之一的精度,因此只需要四分之一模型大小,但这不是通过去除另一半 bit 来实现的。
两种最常见的 8-bit 量化技术为 zero-point 量化和 absmax(absolute maximum)量化。这两种方法将浮点值映射为更紧凑的 int8(1 字节)值。
例如,在 zero-point 量化中,如果数据范围是 -1.0——1.0,量化到 -127——127,其扩展因子为 127。在这个扩展因子下,例如值 0.3 将被扩展为 0.3*127 = 38.1。量化通常会采用四舍五入(rounding),得到了 38。如果反过来,将得到 38/127=0.2992——在这个例子中有 0.008 的量化误差。这些看似微小的错误在通过模型层传播时往往会累积和增长,并导致性能下降。
虽然这些技术能够量化深度学习模型,但它们通常会导致模型准确率下降。但是集成到 hugging face transformers 和 accelerate 库中的 llm.int8(),是第一种即使对于带有 176b 参数的大型模型 (如 bloom) 也不会降低性能的技术。
llm.int8()算法可以这样解释,本质上,llm.int8()试图通过三个步骤来完成矩阵乘法计算:
从输入隐藏状态中,按列提取异常值(即大于某个阈值的值)。将 fp16 中的异常值与 int8 中的非异常值进行矩阵乘法。在 fp16 中对非异常值进行去量化,将异常值和非异常值相加,得到完整的结果。
这些步骤可以在下面的动画中总结:
最后,该研究还关注了一个问题:速度比原生模型更快吗?
llm.int8() 方法的主要目的是使大型模型更易于访问而不会降低性能。但是,如果它非常慢,那么用处也不大了。研究团队对多个模型的生成速度进行了基准测试,发现带有 llm.int8() 的 bloom-176b 比 fp16 版本慢了大约 15% 到 23%——这是完全可以接受的。而较小的模型(如 t5-3b 和 t5-11b)的减速幅度更大。研究团队正在努力提升这些小型模型的运行速度。
以上就是消费级gpu成功运行1760亿参数大模型的详细内容。