当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > Transformers 量化加载时如何选择 device_map

Transformers 量化加载时如何选择 device_map

来源:17golang原创 2026-11-14 20:54:04 0浏览 收藏

Transformers 量化加载时如何选择 device_map

用 Transformers 和 bitsandbytes 加载量化模型时,device_map 决定的是模型模块放在哪里,BitsAndBytesConfig 决定的是权重怎样量化;两者不是同一个开关。推理任务通常从 device_map="auto" 开始,显存大小不对称时再加 max_memory,只有明确知道模块边界时才维护自定义字典。

官方文档:https://huggingface.co/docs/transformers/quantization/bitsandbytes

简单判断:单卡推理可以指定单个 CUDA 设备;多卡推理优先使用 auto,并用 max_memory 描述预算;需要把某个模块放到 CPU 时才写自定义 device_map。训练量化模型时不要把推理阶段的 auto 配置照搬过去。

先把量化配置和设备映射分开

以 bitsandbytes 为例,load_in_4bit=True 或 load_in_8bit=True 负责降低权重存储占用,bnb_4bit_compute_dtype 负责计算时使用的类型,device_map 才负责把模块放到可用设备。即使权重变小,激活、KV cache 和未量化模块仍然会占用显存,所以不能只按“参数量除以位宽”判断是否一定能加载。

BitsAndBytesConfig、from_pretrained 和 device_map auto 连接 GPU 与 CPU 的静态关系说明图
图1:结构说明图,展示量化配置、加载入口与自动设备映射的关系;这是静态说明图,不是运行截图。

一个适合推理的最小写法如下。示例把计算类型写出来,避免读者误以为 4-bit 权重意味着所有模块都以 4-bit 运行:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

model_id = "your-org/your-model"

# 4-bit 只描述量化存储;计算类型单独指定为 bfloat16。
quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)

# auto 面向推理分配模块;它不是训练阶段的通用设备策略。
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=quant_config,
    device_map="auto",
    dtype="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)

# 让输入与模型的首个计算设备保持一致,避免设备不匹配。
inputs = tokenizer("用一句话解释量化", return_tensors="pt")
first_device = next(model.parameters()).device
inputs = {key: value.to(first_device) for key, value in inputs.items()}
outputs = model.generate(**inputs, max_new_tokens=32)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

如果仓库已经保存了量化配置,加载时通常可以让 Transformers 从模型配置中读取量化方法,不必再次传入同一份量化开关。本文只讨论推理加载,不把预量化检查点、量化训练和模型评测混在一起。

大多数推理场景先选 device_map="auto"

多块 GPU 或显存不足以容纳完整模型时,auto 是最省维护成本的起点。它会结合可见设备尝试分配模型;如果机器的 GPU 显存不同,或者还要给服务进程、输入和 KV cache 留空间,就不要只依赖“所有显存都可用”的默认判断,而是给出保守预算。

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

# 显存预算不是整块卡的标称容量,要给运行时开销留余量。
max_memory = {
    0: "18GiB",       # GPU 0 预留一部分空间给服务进程和 KV cache
    1: "10GiB",       # GPU 1 显存较小,避免自动分配过满
    "cpu": "48GiB",   # 允许部分模块落到 CPU,但会牺牲速度
}

# auto 在给定预算内分配;预算过小仍可能无法完成加载。
model = AutoModelForCausalLM.from_pretrained(
    "your-org/your-model",
    quantization_config=BitsAndBytesConfig(load_in_8bit=True),
    device_map="auto",
    max_memory=max_memory,
    dtype="auto",
)

# 这是分配结果的运行时记录,不要把它当作新的配置输入。
print(model.hf_device_map)

max_memory 的作用是收紧分配边界,不是把显存凭空增加。若模型仍然放不下,应先降低量化精度、减少上下文或换更大设备,而不是不断把预算字符串调到标称上限。

什么时候使用明确设备或自定义 device_map

单卡推理、需要稳定部署拓扑时,可以使用明确设备,例如 device_map="cuda:0" 或对应的设备编号。这样更容易预估输入和缓存都落在哪块卡上,但前提是模型连同非量化模块确实能放下。

自定义字典适合少数明确的边界,例如 8-bit 推理时把 lm_head 放到 CPU。官方文档说明,CPU offload 的权重以 float32 保存,因此它更像容量兜底,而不是免费扩容;跨 PCIe 传输也会让延迟变得不可忽略。

max_memory、自定义 device_map、lm_head CPU offload 与 hf_device_map 复查关系说明图
图2:边界说明图,展示显存预算、自定义模块映射与复查接口的关系;这是静态说明图,不是运行结果截图。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

# 只有已经确认模型模块名称时,才维护这种精细映射。
device_map = {
    "transformer.word_embeddings": 0,
    "transformer.h": 0,
    "transformer.ln_f": 0,
    "lm_head": "cpu",  # 把输出头放到 CPU,换取 GPU 显存空间
}

# CPU offload 需要显式打开对应配置;不要把任意模块名照抄到别的模型。
quant_config = BitsAndBytesConfig(
    load_in_8bit=True,
    llm_int8_enable_fp32_cpu_offload=True,
)

model = AutoModelForCausalLM.from_pretrained(
    "your-org/your-model",
    quantization_config=quant_config,
    device_map=device_map,
    dtype="auto",
)

# 读取最终映射,确认模型实际接受的模块分布。
print(model.hf_device_map)
print(model.get_memory_footprint())

自定义映射最大的风险是模块前缀依赖具体模型架构:把某个模型的 transformer.h 直接换到另一个模型,可能导致键不存在或分配不完整。因此先读取模型结构和已生成的 hf_device_map,再决定是否需要维护字典。

用这张速查表确定最终选择

场景优先选择需要注意
单卡推理且模型能放下明确 CUDA 设备为输入、激活和 KV cache 留余量
多卡推理或显存不均device_map="auto" + max_memory预算写保守值,读取 hf_device_map
只想把特定模块放 CPU自定义 device_map先确认模块前缀,并接受 CPU offload 延迟
量化训练按训练器和参数高效微调文档配置不要把推理用的 auto 当训练通用方案

最后记住三个判断顺序:先确认是推理还是训练,再确认量化配置和计算类型,最后根据显存拓扑选择 auto、明确设备或自定义映射。出现显存溢出时,优先减少预算、上下文或缓存压力,并用模型提供的内存统计和分配映射定位问题。

常见问题

device_map="auto" 能直接用于训练吗?

不要这样假设。官方量化文档把这类设备分配示例放在推理加载场景;训练还涉及梯度、优化器状态和参数更新,应按训练框架的设备策略配置。

用了 4-bit 为什么仍然显存不足?

量化主要降低权重占用,激活、KV cache、未量化模块和输入仍会消耗显存。先看上下文长度与并发,再用 max_memory 给自动分配留下运行余量。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Transformers streamer 怎样处理生成停止信号Transformers streamer 怎样处理生成停止信号
上一篇
Transformers streamer 怎样处理生成停止信号
Datasets shard 怎样切分数据集做并行处理
下一篇
Datasets shard 怎样切分数据集做并行处理
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1029次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1030次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1173次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1133次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    973次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码