特定transfomer架构的模型的压缩量化处理

文章目录

〇、前言

最近在做大模型压缩这一块,我感觉从拿到一个模型,到选取一个对象选取一种压缩方法,最后查看压缩的效果,这应该算是一次完整的流程了。

一、模型的选择

Transformer、LLaMA、BERT、GPT 之间既有紧密联系,也有显著区别。它们都是基于 Transformer 的架构,但在设计、任务、预训练方式和应用场景上有所不同。

1. Transformer

特点:

  • 架构: Transformer 是谷歌在 2017 年提出的一种全新的神经网络架构,摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),采用了 自注意力机制(self-attention) 进行序列数据的处理。
  • 编码器-解码器结构: Transformer 的原始架构包含一个编码器和一个解码器,最初用于机器翻译任务。编码器将输入序列转换为一组表示,解码器基于这些表示生成输出序列。
  • 自注意力机制: 自注意力机制使 Transformer 能够并行处理数据,解决了 RNN 中序列依赖问题,且能更好地捕捉长距离的依赖关系。

应用:

Transformer 是后续众多模型的基础架构,包括 BERT、GPT、T5 等。它的自注意力机制使得模型能够更有效地处理长文本序列,并在多个 NLP 任务中表现出色。

2. BERT(Bidirectional Encoder Representations from Transformers)

特点:

  • 双向编码器: BERT 是基于 Transformer 的编码器部分 构建的,但与原始 Transformer 的自回归生成不同,BERT 通过双向的方式进行文本建模。它会同时考虑一个词前后的上下文,这种 双向注意力 的机制使得 BERT 在文本理解任务中非常强大。
  • 预训练任务: BERT 使用了两种主要的预训练任务:
    1. Masked Language Model (MLM):在训练时随机屏蔽部分词汇,让模型根据上下文预测这些词汇。这种方式让 BERT 能够理解上下文信息。
    2. Next Sentence Prediction (NSP):让模型预测两句话是否在语料库中紧密相连,帮助模型学习句子间的关系。
  • 下游任务微调: BERT 是通过大量无监督预训练后,再在特定任务上进行有监督的微调,适应各种下游任务,如情感分析、问答、文本分类等。

应用:

BERT 被广泛用于各种 文本理解 任务,如分类、问答、命名实体识别(NER)等。它并不擅长生成任务,因为它只使用了 Transformer 的编码器部分,无法生成新的文本。

联系:

  • BERT 和 Transformer 紧密相连,BERT 直接基于 Transformer 的编码器架构构建,主要用于理解任务。

3. GPT(Generative Pretrained Transformer)

特点:

  • 自回归生成模型: GPT 是基于 Transformer 的解码器部分 构建的。与 BERT 不同,GPT 是一个 自回归模型 ,它通过生成下一个词来逐步生成整个序列。在生成下一个词时,GPT 仅利用前面的上下文,而不依赖于将来的词,因此是 单向 的。
  • 预训练任务: GPT 通过 语言模型预训练(Language Model Pretraining) 进行预训练,即给定一个序列,预测下一个词。这种自回归方式使 GPT 在生成任务上具有很强的能力。
  • 模型版本:
    • GPT-2:通过大规模训练,GPT-2 展现了强大的生成能力,能生成连贯的长文本。
    • GPT-3 :GPT-3 扩展了模型的规模,拥有 1750 亿参数,不仅在文本生成任务中表现卓越,还能通过提示完成多种任务,几乎无需微调。

应用:

GPT 系列模型尤其擅长 文本生成任务,如对话生成、机器翻译、文本补全、编写文章等。GPT 也可以应用于部分文本理解任务,但其设计初衷主要是为了生成任务。

联系:

  • GPT 也是基于 Transformer 架构,但它只使用了 解码器部分,并通过自回归方式生成文本。与 BERT 的双向编码器不同,GPT 是单向解码器。

4. LLaMA(Large Language Model Meta AI)

特点:

  • 轻量化大模型: LLaMA 是由 Meta(Facebook) 提出的 大语言模型,目的是提供一种参数量相对较小但能与更大型模型(如 GPT-3)相媲美的语言模型。它的设计强调在较小的规模下提供高效的性能表现,因此其训练成本较低,但在任务上表现优异。
  • 多个参数规模: LLaMA 提供了从 7B 到 65B 不等的参数规模版本,便于研究人员和开发者在资源受限的环境下进行实验。
  • 架构: LLaMA 基于 Transformer 架构,使用类似于 GPT 的自回归生成方式,主要用于生成任务。

应用:

LLaMA 主要用于 文本生成任务,类似于 GPT 系列的应用场景,但其目标是在较小的参数规模下提供与更大模型相似的性能。由于其较小的模型规模,LLaMA 更适合研究人员进行探索性研究。

联系:

  • LLaMA 和 GPT 一样,也是基于 Transformer 架构的生成模型,但 Meta 针对其规模进行了优化,使其在较小的模型下也能展现强大的性能。

5. 总结:各个transfomer架构模型区别与联系表格整理

模型 架构 任务类型 预训练方式 主要应用
Transformer 编码器-解码器 通用架构 N/A NLP 和 CV 任务的基础架构
BERT 编码器 文本理解(分类、问答等) Masked Language Model (MLM) 和 Next Sentence Prediction (NSP) 文本理解任务,特别是分类和问答
GPT 解码器 文本生成 语言模型(LM)预训练 文本生成任务,如对话生成、文章生成
LLaMA 解码器 文本生成 自回归语言模型 文本生成,强调轻量化大模型

a.主要联系:架构基础相同+注意力机制

  • 架构基础相同 :所有这些模型都基于 Transformer 的架构,不同之处在于它们是否使用了 Transformer 的编码器、解码器部分,以及如何进行预训练。
  • 注意力机制的广泛应用:自注意力机制是它们共同的核心,使得它们能够有效处理序列数据,尤其是长距离的依赖关系。

b.主要区别:仅编码、仅解码、编码和解码

  • BERT 使用编码器进行 双向文本理解,适合分类和理解任务。
  • GPT 和 LLaMA 使用解码器进行 单向文本生成,适合生成任务,如对话和文章生成。
  • Transformer 是所有这些模型的基础,但其原始设计包含编码器和解码器结构,而 BERT 和 GPT 分别只使用了编码器和解码器部分。

二、压缩的对象

在深度学习模型的训练和推理阶段需要保存或使用的不同类型的对象。

1. 训练阶段:梯度、优化器

在训练时,模型通过计算梯度和调整模型参数来学习和优化。

  • 梯度(Gradients)

    • 训练过程中,模型会计算损失函数(Loss),然后通过 反向传播算法(Backpropagation) 计算损失函数相对于每个参数的梯度。梯度是一个向量,指示了如何改变模型参数以最小化损失。
    • 梯度表示了每个参数需要调整的方向和幅度,因此在每次参数更新时都需要存储和使用梯度。
    • 这些梯度随着模型的更新而变化,只有在训练期间存在。
  • 优化器(Optimizer)

    • 优化器根据梯度信息来调整模型的权重,以最小化损失函数。常见的优化器有 SGD(随机梯度下降)Adam 等。
    • 优化器的状态(如动量、学习率等)也会被保存,它们是辅助参数更新的关键。
    • 优化器在每一轮训练时都会根据当前的梯度来更新权重,因此在训练过程中需要保存优化器的状态。

2.推理阶段:权重、激活、KV Cache

在推理时,模型的目标是基于给定输入生成输出,不再进行梯度计算,而是使用预训练好的权重和缓存。

  • 权重(Weights)

    • 推理过程中,模型只需使用已经训练好的参数(也就是权重)来生成预测结果。权重是模型在训练期间学到的用于表示输入数据特征的数值。
    • 在推理时,权重不会更新,它们是模型进行计算的基础。
  • 激活(Activations)

    • 激活值是模型每一层的输出,是中间计算结果。它们是输入数据通过神经网络各层的加权和非线性变换后产生的。
    • 在推理阶段,激活值会用于每一层的计算,特别是深度模型,激活值的缓存对于保持前后层的连贯性非常重要。
    • 对于一些特定任务,如生成任务或序列生成,激活值可能会被缓存,以加速后续的推理。
  • KV Cache(Key-Value Cache)

    • KV Cache 主要用于 Transformer 解码器 模型(如 GPT 等)的推理过程中。
    • 在自回归生成任务中(如对话生成),模型需要逐步生成每个词。为了避免在每一步生成时重复计算之前的结果,模型会缓存前几步的键和值(Key 和 Value)。这样,后续生成时可以直接复用之前的计算结果,极大提高推理效率。
    • Key 和 Value 是在注意力机制中计算出的值,它们帮助模型保持上下文信息,从而生成连贯的输出。

三、压缩的方法

PTQ(Post-Training Quantization)QAT(Quantization-Aware Training) 是两种常见的量化(Quantization)方法,它们的目的是通过减少模型的数值精度来压缩模型大小、加快推理速度,并减少计算资源的消耗,尤其在移动设备或嵌入式设备上。它们的主要区别在于 量化发生的时机如何处理量化误差

1. PTQ(Post-Training Quantization)

后训练量化 是指在模型训练完成之后对模型进行量化。它不需要在训练期间考虑量化问题,只在训练后进行处理。

特点:

  • 量化时机:在模型训练完成后,直接对预训练的浮点模型进行量化。
  • 简单且快速:因为不需要重新训练模型,只需要对已经训练好的模型参数进行量化,PTQ 的实现相对简单,所需计算量小。
  • 量化误差较大:由于没有在训练过程中考虑量化带来的误差,因此模型可能在量化后精度损失较大,尤其是对浮点模型非常敏感的任务。
  • 典型用法:通常将 32 位浮点数(FP32)模型转换为 8 位整数(INT8)模型,以降低存储和计算成本。

工作流程:

  1. 训练浮点模型:首先,在高精度(如 FP32)下完成模型的正常训练。
  2. 模型量化:在训练完成后,将模型参数(如权重、激活值等)直接从浮点精度转换为低精度格式(通常是 INT8)。
  3. 校准数据(可选):有时会用一个较小的数据集进行量化校准,以减少量化误差并提高模型性能。

优势:

  • 不需要重新训练:只需对现有模型进行量化,节省了计算资源和时间。
  • 实现简单:只需额外的量化步骤,不需要改变训练过程。

劣势:

  • 精度损失较大:由于模型在训练时没有考虑到量化,因此在量化过程中引入的误差会导致性能下降,尤其是对于对精度要求高的任务。

2. QAT(Quantization-Aware Training)

量化感知训练 是指在模型训练的过程中模拟量化过程,使得模型能够感知量化的影响,并调整参数以适应量化后的推理。

特点:

  • 量化时机:量化过程是在训练期间进行的,模型在训练时就已经意识到量化的存在,并通过梯度更新来适应量化误差。
  • 精度损失小:由于在训练期间已经考虑到了量化,模型会调整自身参数以最小化量化带来的误差,从而在推理时保持更高的精度。
  • 训练复杂度增加:需要在训练过程中模拟量化操作,这会增加训练的复杂性和计算成本。

工作流程:

  1. 量化模拟:在训练过程中,模型的权重和激活会定期被模拟量化(通常是从 FP32 到 INT8),以使模型学习到量化误差并调整参数。
  2. 梯度更新:训练过程中,模型会通过梯度下降法更新参数,适应低精度的计算,减少量化误差。
  3. 量化模型:训练完成后,模型已经适应了量化操作,推理时直接使用低精度模型(如 INT8)进行推理。

优势:

  • 精度损失小:由于模型在训练时已经考虑到量化的影响,因此量化后的精度保持得较好,尤其适合对精度要求较高的任务。
  • 量化误差可控:通过模拟量化过程,模型可以在训练中适应量化带来的误差,并进行自我调整。

劣势:

  • 训练成本高:与传统的浮点模型训练相比,QAT 的训练复杂度更高,训练时间更长,因为需要模拟低精度计算。
  • 实现复杂:需要修改训练流程来引入量化模拟。

3.PTQ 和 QAT 的对比表格整理

特性 PTQ(Post-Training Quantization) QAT(Quantization-Aware Training)
量化时机 在模型训练完成后进行量化 在训练过程中模拟量化
实现难度 简单,训练后直接量化 较复杂,需在训练中进行量化模拟
训练成本 无需重新训练,训练成本低 需要重新训练,训练成本高
精度损失 可能较大,尤其是复杂任务 精度损失较小,模型适应量化误差
适用场景 对精度要求不高的场景 对精度要求较高的场景
模型类型 预训练的浮点模型 量化感知模型

4.选择哪种量化方法?

  • PTQ 适用于以下场景:

    • 资源有限的设备中需要快速部署模型。
    • 对精度要求不是特别高的任务(如简单的分类任务或边缘设备的推理)。
    • 训练后不希望再花费大量时间进行重新训练。
  • QAT 适用于以下场景:

    • 对精度要求很高的任务(如复杂的自然语言处理、图像识别等任务)。
    • 可以接受较长的训练时间和更高的训练成本,来确保量化后的精度。

四、压缩的效果

大模型压缩的效果评估涉及多个维度,不仅需要考虑模型压缩后在存储和计算资源上的节省,还要衡量模型在推理性能、速度和准确性上的表现。常见的大模型压缩效果评估指标可以分为以下几类:

1. 模型性能指标

模型压缩后最重要的是确保其性能不会大幅下降,因此常用的模型性能评估指标包括:

  • 准确率(Accuracy)
    • 对于分类任务,模型压缩后仍然需要评估其分类准确率。
    • 例如,图像分类任务的 Top-1Top-5 准确率。
  • F1 值(F1 Score)
  • 对于不均衡的数据集,F1 值 是一种更好的评估标准,结合了模型的精准率(Precision)和召回率(Recall)。
  • F1 值用于评估分类型任务的模型压缩效果
  • BLEU、ROUGE 分数
  • 在机器翻译、文本摘要等任务中,常用 BLEUROUGE 分数来评估压缩后的生成质量。
  • 均方误差(MSE)
  • 对于回归任务或者一些特定的预测任务,可以通过 均方误差 来衡量模型在数值预测上的偏差。

  • 感知损失(Perceptual Loss)

    • 在图像或语音生成任务中,可能需要用感知损失来衡量生成数据的质量是否接近原始数据。

2. 模型尺寸和存储效率

压缩模型的一个主要目标是减少其存储空间。以下指标可以用于评估模型压缩带来的存储优化效果:

  • 模型大小(Model Size)

    • 压缩后的模型权重文件的大小,通常以 MBGB 为单位。这个指标可以直接反映出模型压缩效果。
    • 例如,将模型从原来的 1 GB 压缩到 100 MB,表示模型的存储需求减少了 90%。
  • 参数量(Number of Parameters)

    • 模型中可训练参数的数量。压缩后参数量通常会大幅减少,如从数十亿个参数减少到几亿甚至几百万个参数。
    • 例如,模型压缩后从 175B 参数减少到 7B。
  • 浮点数运算量(FLOPs)

    • FLOPs 表示模型在推理时需要进行的浮点运算次数。FLOPs 越少,意味着计算复杂度越低,推理速度也越快。
    • 压缩后可以通过比较压缩前后模型的 FLOPs 来衡量压缩效果。

3. 推理速度

压缩后的模型是否能显著加速推理过程,是评估其效果的一个重要指标,特别是在资源受限的设备上。

  • 延迟(Latency)

    • 模型从接收到输入到输出结果所需的时间。延迟通常以 毫秒(ms) 为单位,尤其是在实时推理系统中(如自动驾驶、语音助手),延迟是至关重要的指标。
    • 延迟可以分为 单样本延迟批处理延迟
  • 吞吐量(Throughput)

    • 吞吐量指的是模型在固定时间内处理的样本数量,通常以 样本/秒 为单位(如 1000 样本/秒)。在压缩后,模型的吞吐量应该显著提高。
    • 对于需要高效处理大量数据的系统,如推荐系统、搜索引擎等,吞吐量是关键指标。

4. 能耗和资源使用效率

在实际部署中,特别是移动设备或嵌入式设备中,评估压缩后的模型资源使用效率至关重要。

  • 功耗(Power Consumption)

    • 运行压缩模型所消耗的能量,尤其是对电池供电设备(如智能手机或 IoT 设备)非常重要。功耗越低,意味着压缩后的模型更节能。
  • 内存占用(Memory Usage)

    • 模型在推理时所占用的 RAM 大小。压缩后的模型应该显著减少推理过程中对内存的需求,特别是在设备资源有限的场景中。
  • 硬件利用率(Hardware Utilization)

    • 压缩后的模型能否更好地利用硬件资源,比如 GPU 或 TPU 的利用率。通过更有效的硬件利用,模型推理的效率和速度都能得到提升。

5. 压缩比例

这个指标用来直接量化压缩的效果,通常包括以下几类:

  • 参数压缩率(Parameter Compression Ratio)

    • 表示压缩后模型的参数数量相对于原始模型的减少程度。可以表示为:
      [
      \text{参数压缩率} = \frac{\text{压缩后模型的参数数量}}{\text{压缩前模型的参数数量}}
      ]
    • 例如,如果原模型有 1 亿个参数,压缩后变为 1000 万个参数,压缩率为 10%。
  • 模型大小压缩率(Model Size Compression Ratio)

    • 表示压缩后模型的存储大小相对于原始模型的减少程度。可以表示为:
      [
      \text{模型大小压缩率} = \frac{\text{压缩后模型大小}}{\text{压缩前模型大小}}
      ]
    • 例如,将模型从 500MB 压缩到 50MB,压缩率为 1/10。

6. 压缩对比实验

为了评估压缩效果,通常需要进行对比实验,包括以下方式:

  • 压缩前后性能对比

    • 比较压缩前后的模型性能(如准确率、推理速度等),用量化数据来直接反映压缩的效果。
  • 与其他压缩方法的对比

    • 在同样的压缩场景下,与其他压缩技术(如剪枝、知识蒸馏、权重量化等)进行对比,评估哪种方法效果更好。

7.感知质量(Perceptual Quality)

对于涉及图像、视频、语音等生成任务的模型,感知质量是重要的评估指标,主要通过人类的主观感知或基于模型的感知损失函数来衡量。

  • 人类评估(Human Evaluation)

    • 在图像生成或文本生成任务中,经过压缩的模型输出质量往往需要通过人类进行主观评分(如图像的清晰度、文本的流畅度等)。
  • 自动评估

    • 使用感知损失、SSIM(结构相似性指数)等指标来衡量生成结果与原始数据的相似度。

五、示例:以Llama-7B的中文版本为例

1.原理:

LLM.int8(): Int8 矩阵乘法来处理 Transformer 模型中的前馈层(Feed Forward)和注意力投影层(Multi-HeadAttention),从而将推理所需的内存减半,同时保持完整精度的性能。

2.使用源码

python 复制代码
import torch
import torch.nn as nn
import os
import time
from modelscope import AutoTokenizer
from transformers import LlamaForCausalLM
import bitsandbytes as bnb
import random
import numpy as np

random.seed(42)
np.random.seed(42)
torch.manual_seed(42)


def redirect_output_to_file(file_path):
    import sys
    sys.stdout = open(file_path, 'w')

output_file = os.path.join(os.getcwd(), 'LLMint8_try_output.txt')
redirect_output_to_file(output_file)

model_dir = '/home/mshw/model/Llama2-Chinese-7b-Chat-ms'
print(model_dir)

if not torch.cuda.is_available():
    raise RuntimeError("CUDA 不可用,请检查 GPU 配置")

n_gpus = torch.cuda.device_count()
print(f"Number of GPUs detected: {n_gpus}")

if n_gpus == 0:
    raise RuntimeError("没有检测到可用的 GPU")

max_memory = {}
for i in range(n_gpus):
    free_mem, total_mem = torch.cuda.mem_get_info(i)
    max_mem_gb = max(0, int(free_mem / 1024**3) - 1)
    max_memory[i] = f"{max_mem_gb}GB"
    print(f"GPU {i}: {max_mem_gb}GB free memory allocated for usage.")

cache_dir = os.getcwd()
offload_folder = os.path.join(cache_dir, 'offload')
os.makedirs(offload_folder, exist_ok=True)

# 加载模型
model = LlamaForCausalLM.from_pretrained(model_dir, torch_dtype=torch.float16, device_map='auto')

# 确保模型权重绑定
model.tie_weights()



tokenizer = AutoTokenizer.from_pretrained(model_dir, cache_dir=cache_dir)

def get_sparsity(tensor: torch.Tensor) -> float:
    tensor_cpu = tensor.to('cpu')
    return 1 - float(tensor_cpu.count_nonzero()) / tensor_cpu.numel()



def get_num_parameters(model: nn.Module, count_nonzero_only=False) -> int:
    num_counted_elements = 0
    for param in model.parameters():
        if count_nonzero_only:
            param_cpu = param.detach().to('cpu')
            num_counted_elements += param_cpu.count_nonzero()
        else:
            num_counted_elements += param.numel()
    return num_counted_elements

def get_model_size_in_gb(model: nn.Module, data_width=8, count_nonzero_only=False) -> float:
    data_width_bytes = data_width // 8
    model_size_bytes = get_num_parameters(model, count_nonzero_only) * data_width_bytes
    model_size_gb = model_size_bytes / (1024**3)
    return model_size_gb

def calculate_memory_access(tensor: torch.Tensor) -> int:
    return tensor.numel() * tensor.element_size()

def get_model_memory_access(model: nn.Module) -> int:
    total_access = 0
    for param in model.parameters():
        total_access += calculate_memory_access(param)
    return total_access

# 使用8位宽度进行模型大小计算
model_size_gb = get_model_size_in_gb(model, data_width=8) 


inputs = "咖啡的作用是什么?"
MiB = 1024 * 1024

torch.cuda.reset_peak_memory_stats()
start_time = time.time()

# 使用适当的方法进行推理
inputs_encoded = tokenizer(inputs, return_tensors='pt').to('cuda')
inputs_encoded.pop("token_type_ids", None)  # 移除不需要的键

outputs = model.generate(**inputs_encoded)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)

end_time = time.time()

for i in range(n_gpus):
    peak_mem = torch.cuda.max_memory_reserved(device=i) / MiB
    print(f"GPU {i} 峰值内存: {peak_mem:.2f} MiB")

print(result)
print(f"推理时间: {end_time - start_time:.2f} 秒")

# 恢复标准输出
import sys
sys.stdout.close()
sys.stdout = sys.__stdout__

3.思考

怎么区分权重的异常特征和正常特征?

均值和标准差:计算每层权重的均值和标准差,识别那些偏离较大的权重

设定合理阈值:定义上下限,找出超出范围的权重。

相关推荐
工业甲酰苯胺2 小时前
分布式系统架构:服务容错
数据库·架构
Java程序之猿4 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构
小蜗牛慢慢爬行7 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
思忖小下8 小时前
梳理你的思路(从OOP到架构设计)_简介设计模式
设计模式·架构·eit
一个儒雅随和的男子15 小时前
微服务详细教程之nacos和sentinel实战
微服务·架构·sentinel
腾讯云开发者15 小时前
AI时代,需要怎样的架构师?腾讯云架构师峰会来了!
架构
Hello Dam18 小时前
面向微服务的Spring Cloud Gateway的集成解决方案:用户登录认证与访问控制
spring cloud·微服务·云原生·架构·gateway·登录验证·单点登录
AI人H哥会Java1 天前
【Spring】Spring的模块架构与生态圈—Spring MVC与Spring WebFlux
java·开发语言·后端·spring·架构
小屁不止是运维1 天前
麒麟操作系统服务架构保姆级教程(二)ssh远程连接
linux·运维·服务器·学习·架构·ssh