ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

unilm (edgelm/fairseq) 中的 Quant-Noise 量化噪声训练与极端模型压缩实战指南

unilm (edgelm/fairseq) 中的 Quant-Noise 量化噪声训练与极端模型压缩实战指南 unilm (edgelm/fairseq) 中的 Quant-Noise 量化噪声训练与极端模型压缩实战指南【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm本篇指南围绕 unilm 仓库中 Quant-Noise 示例文档 展开完整讲解“在训练中注入量化噪声Quantization Noise以提升推理期量化鲁棒性”的两条技术路线面向 int8 的标量 Fake Quantization 与面向极低比特率的迭代乘积量化iPQ。你将掌握--quant-noise-scalar、--quant-noise-pq、--quant-noise-pq-block-size等命令行参数的正确用法与推荐取值学会使用仓库内置的quantize_model_API 把该技术集成到自定义模型并能直接复制文档中给出的 RoBERTa 预训练/微调与 Wikitext-103 语言模型的完整训练、量化与评测命令。一、Quant-Noise 核心思想Quant-Noise 出自 Angela Fan 与 Pierre Stock 等人 2020 年的论文《Training with Quantization Noise for Extreme Model Compression》。其核心结论是在训练阶段让模型随机“体验”量化过程可以显著提高模型在推理期被真正量化后的精度保持率。该技巧对标量量化如 int8和乘积量化PQ均有效也适用于 NLP 与视觉等多个领域。仓库中为此提供了两套完整的工程实现标量量化Scalar Quantization位于 edgelm/fairseq/modules/quantization/scalar/采用 GPU 上的 Fake Quantization 模拟 int8迭代乘积量化iPQ位于 edgelm/fairseq/modules/quantization/pq/实现的是 Stock 等人提出的改进版乘积量化 iPQ支持把模型压缩到极低比特训练期噪声注入函数edgelm/fairseq/modules/quant_noise.py。论文引用信息BibTeXarticle{fan2020training, title{Training with Quantization Noise for Extreme Model Compression}, author{Angela Fan* and Pierre Stock* and and Benjamin Graham and Edouard Grave and Remi Gribonval and Herve Jegou and Armand Joulin}, year{2020}, eprint{2004.07320}, archivePrefix{arXiv}, primaryClass{cs.ML} }二、标量量化Scalar Quantization / int8 Fake Quantization与 iPQ 追求极致压缩不同标量量化展示的是 Quant-Noise 在简单量化基线如 int8上的价值。仓库通过Fake Quantization在 GPU 上模拟 int8对权重和激活同时做“量化-反量化”底层复用 PyTorch 的 quantization 原语实现位于 edgelm/fairseq/modules/quantization/scalar/。2.1 训练注入量化噪声标量量化的 Quant-Noise 做法是训练时随机地对比例为p的权重进行量化。只需在训练命令中追加一个开关--quant-noise-scalar 0.5需要注意噪声值越大模型越容易量化但未量化状态下的 test/valid 困惑度可能更高两者需要权衡。从源码结构看fairseq 的模型配置中把该参数声明为quant_noise_scalar例如 edgelm/fairseq/config/model/transformer_lm/transformer_lm_gbw.yaml 中同时给出quant_noise_pq: 0、quant_noise_pq_block_size: 8、quant_noise_scalar: 0三个字段默认均为“关闭噪声”而 edgelm/fairseq/models/roberta/model.py 与 edgelm/fairseq/models/transformer/transformer_legacy.py 在构造模型时都会通过getattr/safe_getattr兜底读取这三个参数因此任何 legacy 架构都能通过命令行直接开启。2.2 评测自动切换为全量化在评测eval阶段所有量化模块与激活钩子会自动切换到p1即对全部权重与激活做量化。因此 Fairseq 汇报的验证指标本身就是量化后的精度无需额外操作。2.3 集成到自己的代码如果你想在自己的模型中使用 Quant-Noise 标量量化调用 edgelm/fairseq/modules/quantization/scalar/utils.py 中的quantize_model_函数它会1把模型中所有模块替换为量化对应物2在这些模块上注册钩子以量化激活之后按常规流程训练即可。注意在eval()模式下网络默认始终处于完全量化状态权重与激活p1。从源码看该函数的签名是quantize_model_(model, p0.2, bits8, update_step3000, methodhistogram, ...)内部维护一张nn.Linear → IntLinear、nn.Embedding → IntEmbedding、nn.Conv2d → IntConv2d的模块映射表MAPPING逐个替换模块并注入p、bits、update_step等量化参数同时用ActivationQuantizer处理激活量化methodhistogram表示用直方图方法标定量化参数每update_step步更新一次。这解释了为什么 README 建议“替换模块后按常规训练即可”——量化状态机完全封装在替换后的模块内部。三、迭代乘积量化iPQ路线iPQ Quant-Noise 是论文中取得 SOTA 压缩效果的主线流程分两步第一步用 Quant-Noise 无压缩训练模型第二步对训好的模型做 iPQ 量化。文档特别指出此处实现的是论文中最简单的噪声形式——以概率p随机丢弃权重矩阵中的 block效果与“把 block 赋值到其当前质心”相当。3.1 训练参数与推荐取值--quant-noise-pq 0.1 --quant-noise-pq-block-size 8quant-noise-pq控制对权重矩阵 block 施加的 drop 比例推荐0.05 ~ 0.2quant-noise-pq-block-size控制权重矩阵 block 的大小推荐8block size 必须是input_features的约数尺寸检查逻辑就在 edgelm/fairseq/modules/quant_noise.py 中更大的 block size 意味着更高的压缩率但可能损失精度。目前支持基于 Transformer 的模型seq2seq、语言模型、BERT 类架构。quant_noise函数会包裹一个模块把其权重矩阵切分为 block 并随机 drop。在 Transformer 中quant-noise 会应用到输入/输出 Embedding、Attention 与 FFN上。3.2 quant_noise 源码剖析edgelm/fairseq/modules/quant_noise.py 是整条噪声链路的核心实现非常紧凑值得逐行理解入口校验若p 0直接原样返回模块只支持nn.Linear、nn.Embedding、nn.Conv2d并按 2D矩阵或 4D卷积核分别断言input_features % block_size 0卷积则检查in_channels或 kernel 尺寸。前向预钩子通过register_forward_pre_hook注册_forward_pre_hook且仅在mod.training为真时生效评测不加噪。mask 生成对 2D 权重先构造形状为(in_features // block_size * out_features,)的 mask执行mask.bernoulli_(p)随机采样再repeat_interleave(block_size, -1)把每个 block 内共享同一保留决策最后view(-1, in_features)还原成权重形状。卷积情形对 1x1 conv 与常规卷积分别处理。缩放与置零s 1 / (1 - p)做无偏缩放后mod.weight.data s * weight.masked_fill(mask, 0)——这正是“以概率 p 整块丢弃”的最简噪声实现。从源码结构看fairseq 的 Transformer 通过 edgelm/fairseq/models/transformer/transformer_legacy.py 读取quant_noise_pq / quant_noise_pq_block_size / quant_noise_scalar默认 0、8、0并在 transformer_encoder.py 与 transformer_decoder.py 中于 forward 里执行x self.quant_noise(x)这与 README 所说“噪声作用于 Embedding、Attention 和 FFN”相吻合同时transformer_config.py中的QuantNoiseConfig表明新版 dataclass 配置体系下同样以quant_noise.pq、quant_noise.pq_block_size字段驱动。3.3 与 LayerDrop 组合使用Quant-Noise 还可以与LayerDrop组合见 edgelm/examples/layerdrop/把剪枝效果叠加到量化模型上使模型更小。推荐 LayerDrop 取0.1 或 0.2。3.4 量化两步走量化基于 Stock 等人提出的iPQ改进版乘积量化。对 PQ 这一特殊情形量化是顺序进行的推荐顺序为先 FFN再 Embedding最后 Attention。每个阶段的量化又分两个子步骤先做n步乘积量化通常n20足够再对得到的质心centroids做微调finetune。3.5 集成到自己的代码含示例代码若要在自定义模型上用 Quant-Noise iPQ先用模块无关的quant_noise包裹模块并训练再用 edgelm/fairseq/modules/quantization/pq/ 下的代码量化训好的模型——训练循环无需任何改动。官方示例如下from fairseq.modules.quantization.pq import quantize_model_, SizeTracker # get configuration parameters n_centroids_config config[n_centroids] block_sizes_config config[block_sizes] layers_to_quantize config[layers_to_quantize] # size tracker for keeping track of assignments, centroids and non-compressed sizes size_tracker SizeTracker(model) # Quantize model by stages for step in range(len(layers_to_quantize)): # quantize model in-place quantized_layers quantize_model_( model, size_tracker, layers_to_quantize, block_sizes_config, n_centroids_config, stepstep, ) logger.info(fFinetuning stage {step}, quantized layers: {quantized_layers}) logger.info(f{size_tracker}) # Dont forget to re-create/update trainer/optimizer since model parameters have changed optimizer ... # Finetune the centroids with your usual training loop for a few epochs trainer.train_epoch()注意文档说明该方法目前只在 Transformer 及 EfficientNets 等若干卷积模型上验证过。四、量化后的模块长什么样PQLinear 与 SizeTracker理解量化产物的存储结构有助于把握压缩率来源。以 edgelm/fairseq/modules/quantization/pq/modules/qlinear.py 中的PQLinear为例权重不再整体保存而是拆成两部分可训练的centroidsn_centroids × block_size的质心表与冻结的assignments每个子向量所属质心的索引weight是一个property每次前向时通过self.centroids[self.assignments]查表、reshape、permute、flatten重建完整权重因此质心可以随 finetune 继续更新这正是“第二步微调质心”能够成立的原因bias 不做量化仍按原样保存。压缩大小统计则由 edgelm/fairseq/modules/quantization/pq/utils.py 中的SizeTracker完成压缩后体积 索引int8 计前提是使用 256 个质心 质心fp16 计 未压缩部分bias、LayerNorm 等并按bits_per_weight log2(n_centroids) / block_size记账最终打印compression ratio。例如 256 质心、block size 8 时每个权重仅占 1 bit这就是“极端压缩”的由来。同一文件中的quantize_model_展示了分阶段量化入口的完整行为按正则表达式过滤待量化层自动排除 bias按block_sizes_config/n_centroids_config逐层取参数支持kernel_size、in_features乃至fuzzy_name按层名模糊匹配用PQ量化器encode()得到 centroids 与 assignments在多卡下广播保证各进程一致最后把nn.Linear/nn.Embedding/nn.Conv2d原地替换为PQLinear/PQEmbedding/PQConv2d。五、复现论文 NLP 结果完整命令以下命令继承自 edgelm/examples/quant_noise/README.md与仓库中 fairseq 的fairseq-train/fairseq-eval-lm入口配套使用。5.1 训练 RoBERTa QuantNoise预训练遵循 edgelm/examples/roberta/ 的设置训练 RoBERTa Base QuantNoiseTOTAL_UPDATES125000 WARMUP_UPDATES10000 PEAK_LR0.0005 TOKENS_PER_SAMPLE512 MAX_POSITIONS512 MAX_SENTENCES16 UPDATE_FREQ2 DATA_DIR/path/to/data/here fairseq-train $DATA_DIR \ --task masked_lm --criterion masked_lm --arch roberta_base \ --sample-break-mode complete \ --tokens-per-sample $TOKENS_PER_SAMPLE --max-positions $MAX_POSITIONS \ --optimizer adam --adam-betas (0.9, 0.98) --adam-eps 1e-6 \ --clip-norm 0.0 \ --lr-scheduler polynomial_decay --lr $PEAK_LR \ --warmup-updates $WARMUP_UPDATES --total-num-update $TOTAL_UPDATES \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.01 \ --batch-size $MAX_SENTENCES \ --update-freq $UPDATE_FREQ --max-update $TOTAL_UPDATES \ --save-dir checkpoint/roberta \ --ddp-backend legacy_ddp --encoder-layerdrop 0.2 \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8 --untie-weights-roberta注意末尾三个关键项--encoder-layerdrop 0.2对应“Quant-Noise LayerDrop”组合--quant-noise-pq 0.2处于文档推荐区间 0.05~0.2 的上沿--untie-weights-roberta保证输入/输出 Embedding 不共享便于分别量化。5.2 微调 RoBERTa QuantNoiseGLUE/RTE遵循 edgelm/examples/roberta/ 的 GLUE 微调设置在 RTE 数据集上微调 RoBERTa Base QuantNoiseTOTAL_NUM_UPDATES2036 WARMUP_UPDATES122 LR2e-05 NUM_CLASSES2 MAX_SENTENCES16 ROBERTA_PATH/path/to/roberta_quantnoise/model.pt fairseq-train /path/to/rte/data/ \ --restore-file $ROBERTA_PATH \ --max-positions 512 \ --batch-size $MAX_SENTENCES \ --max-tokens 4400 \ --task sentence_prediction \ --reset-optimizer --reset-dataloader --reset-meters \ --required-batch-size-multiple 1 \ --init-token 0 --separator-token 2 \ --arch roberta_large \ --criterion sentence_prediction \ --num-classes $NUM_CLASSES \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.1 --optimizer adam --adam-betas (0.9, 0.98) --adam-eps 1e-06 \ --clip-norm 0.0 \ --lr-scheduler polynomial_decay --lr $LR --total-num-update $TOTAL_NUM_UPDATES --warmup-updates $WARMUP_UPDATES \ --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ --max-epoch 10 \ --find-unused-parameters \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ --ddp-backend legacy_ddp \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8关键点--restore-file指向带量化噪声预训练出的 checkpoint且微调阶段保留同样的--quant-noise-pq 0.2 --quant-noise-pq-block-size 8使微调过程继续处于噪声训练状态。5.3 在 Wikitext-103 上训练语言模型 QuantNoise遵循 edgelm/examples/language_model/ 的设置训练 Transformer QuantNoise LMfairseq-train --task language_modeling /path/to/wikitext-103/data \ --save-dir checkpoints/transformer_wikitext-103 \ --adaptive-input --adaptive-input-cutoff 20000,60000 --adaptive-input-factor 4 \ --adaptive-softmax-cutoff 20000,60000 --adaptive-softmax-dropout 0.2 --adaptive-softmax-factor 4.0 \ --tie-adaptive-proj --tie-adaptive-weights \ --arch transformer_lm_gbw \ --attention-dropout 0.1 --dropout 0.2 --relu-dropout 0.1 \ --clip-norm 0.1 --criterion adaptive_loss \ --ddp-backend legacy_ddp \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 \ --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 1.0 --t-mult 2.0 \ --max-tokens 3072 --tokens-per-sample 3072 --momentum 0.99 --optimizer nag \ --sample-break-mode none --update-freq 3 \ --warmup-init-lr 1e-07 --warmup-updates 16000 \ --weight-decay 0 --seed 1 --stop-min-lr 1e-09 \ --quant-noise-pq 0.05 --quant-noise-pq-block-size 8这里噪声取推荐区间的下沿0.05。评测该模型时使用fairseq-eval-lmfairseq-eval-lm /path/to/wikitext-103/data --path /path/to/model/checkpoint \ --sample-break-mode complete \ --max-tokens 3072 \ --context-window 2560 \ --softmax-batch 1024 \ --gen-subset valid在 test 集上评测时把--gen-subset改为test即可。5.4 对微调后的 RoBERTa 做 iPQ 量化对微调好的 RoBERTa 模型做 iPQ 量化在 1 张 GPU 上执行预计一天内完成TOTAL_NUM_UPDATES6108 # 2036 updates for each iteration WARMUP_UPDATES122 LR2e-05 NUM_CLASSES2 MAX_SENTENCES16 fairseq-train --task sentence_prediction /path/to/data/ \ --restore-file $ROBERTA_PATH \ --save-dir checkpoints/roberta_finetuned \ --max-positions 512 \ --batch-size $MAX_SENTENCES \ --max-tokens 4400 \ --init-token 0 --separator-token 2 \ --arch roberta_large \ --criterion sentence_prediction \ --num-classes $NUM_CLASSES \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.1 --optimizer adam --adam-betas (0.9, 0.98) --adam-eps 1e-06 \ --clip-norm 0.0 --lr-scheduler polynomial_decay \ --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ --no-progress-bar --skip-invalid-size-inputs-valid-test --ddp-backend legacy_ddp \ --quantization-config-path /path/to/config/yaml5.5 对训练好的语言模型做 iPQ 量化在 8 张 V100 23GB GPU 上执行预计数小时内完成fairseq-train --task language_modeling /path/to/wikitext-103/data \ --save-dir checkpoints/transformer_wikitext-103 \ --adaptive-input --adaptive-input-cutoff 20000,60000 --adaptive-input-factor 4 \ --adaptive-softmax-cutoff 20000,60000 --adaptive-softmax-dropout 0.2 --adaptive-softmax-factor 4.0 \ --arch transformer_lm_gbw \ --attention-dropout 0.1 --dropout 0.2 --relu-dropout 0.1 \ --bucket-cap-mb 25 --char-embedder-highway-layers 2 --character-embedding-dim 4 \ --clip-norm 0.1 --criterion adaptive_loss \ --ddp-backend legacy_ddp \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --fp16 --keep-last-epochs -1 \ --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 0.05 --stop-min-lr 1e-09 \ --max-tokens 2944 --tokens-per-sample 2944\ --momentum 0.99 --no-epoch-checkpoints --no-progress-bar --optimizer nag --required-batch-size-multiple 8 \ --sample-break-mode none --t-mult 2.0 --skip-invalid-size-inputs-valid-test \ --tie-adaptive-proj --tie-adaptive-weights --update-freq 3 --weight-decay 0 --seed 1 \ --log-interval 100 --no-progress-bar --skip-invalid-size-inputs-valid-test \ --restore-file path/to/trained/lm/with/quant/noise \ --max-update 13500 --quantization-config-path /path/to/config/yaml如果显存不足或分布式训练卡死可以尝试调小--max-tokens与--tokens-per-sample代价是量化精度可能略有下降。5.6 适用性与未验证组合Remarks为保证开源代码可读、易集成作者声明未验证以下组合RoBERTa 标量量化iPQ 与int8同时叠加。遇到适配困难时建议在仓库中提 issue 获取帮助。六、视觉结果的复现状态论文中的 Vision 部分代码当时计划以 ClassyVision 项目形式开源README 注明“请持续关注”。不过文档同时指出nn.Conv2d的标量量化与 iPQ 量化对应物IntConv2d、PQConv2d已包含在当前发布中可直接参考 edgelm/fairseq/modules/quantization/pq/modules/qconv.py 与 edgelm/fairseq/modules/quantization/scalar/modules/qconv.py 自行集成。七、小结参数速查与关键源码索引目标参数 / API推荐取值源码位置int8 标量量化噪声训练--quant-noise-scalar视任务权衡示例 0.5scalar/utils.pyiPQ 噪声训练--quant-noise-pq0.05 ~ 0.2quant_noise.pyiPQ block 大小--quant-noise-pq-block-size8须整除 input_featuresquant_noise.py组合剪枝LayerDrop0.1 / 0.2edgelm/examples/layerdrop/分阶段量化无需改训练循环quantize_model_SizeTracker按 FFN → EMB → ATTN 顺序pq/utils.py量化后模块PQLinear/PQEmbedding/PQConv2d256 质心时索引可用 int8pq/modules/qlinear.py掌握本文内容后你可以在任意 fairseq 支持的 Transformer 任务masked LM、seq2seq、LM中通过两个命令行开关开启 Quant-Noise 训练用quantize_model_SizeTracker把训好的模型分阶段压缩到极低比特并持续 finetune 质心通过SizeTracker的输出量化地评估压缩率与精度代价。所有命令与实现均以当前仓库 edgelm/examples/quant_noise/README.md 及上述源码文件为准建议结合本地代码版本核对参数默认值后再上生产实验。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表