- 模型推理服务
- 人工智能
- 后端
- 大模型
- MLOps
- LLMOps
【免费下载链接】BentoML
The easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!
导读
本文是 BentoML 仓库中bentoml.diffusers模块的 API 参考指南,覆盖该模块对外暴露的四个核心函数:import_model、save_model、load_model与get。通过本文,你将掌握如何把 Hugging Face 上的 Diffusion 模型(如 Stable Diffusion 系列)导入 BentoML 模型库、如何将内存中的DiffusionPipeline持久化保存、如何按标签重新加载为可推理的 Pipeline,并理解调度器替换、LoRA/Textual Inversion 注入、CPU offload 与 torch.compile 等高级加载选项的底层行为。文中所有结论均以本仓库源码 diffusers.py 及其测试为事实依据。
bentoml.diffusers模块概览
bentoml.diffusers是 BentoML 对 Hugging Face Diffusers 框架的适配层,负责把 diffusers 的扩散模型 Pipeline 纳入 BentoML 的模型管理体系中:模型以标准 BentoML Model 的形式存入本地模型库(model store),并可通过统一的bentoml.modelsAPI 进行版本管理、打包进 Bento 并部署为推理服务。
在源码中,该模块位于 src/bentoml/_internal/frameworks/diffusers.py,模块名常量定义为MODULE_NAME = "bentoml.diffusers",内部使用一个固定目录diffusion_model/存放模型权重,并以model_index.json作为校验是否为合法 Diffusion 模型的标志文件(源码 L42-L44)。所有模型在库中都以ModelContext(framework_name="diffusers", framework_versions={"diffusers": diffusers.__version__})记录框架版本信息。
使用前提与依赖
该模块在导入时会强制检查diffusers、torch依赖,若缺失会抛出MissingDependencyException,并提示安装命令(源码 L28-L39):
pip install --upgrade diffusers transformers accelerate此外,bentoml.diffusers自 v1.4 起已被标记为弃用(见 src/bentoml/init.py 中的_LazyLoader加载警告),官方建议在新代码中改用bentoml.diffusers_simple.stable_diffusion/stable_diffusion_xl或直接在 Service 中使用HuggingFaceModel加载(后者可参考 sdxl-turbo 示例)。尽管如此,import_model/save_model/load_model/get仍是理解 BentoML 与 Diffusers 集成原理的最佳入口,且内部实现被diffusers_simple路径复用。
import_model:把 Diffusion 模型导入 BentoML 模型库
import_model是bentoml.diffusers中最常用的入口函数(源码 diffusers.py#L377-L557),用于把 Hugging Face 仓库中的预训练 Pipeline 或本地权重目录导入到 BentoML 模型库。
import bentoml bentoml.diffusers.import_model( 'my_sd15_model', "runwayml/stable-diffusion-v1-5", signatures={ "__call__": {"batchable": False}, } )参数详解
| 参数 | 类型 | 说明 |
|---|---|---|
name | Tag \| str | 模型在 BentoML 模型库中的名称,必须是合法的bentoml.Tag名称,可带:version后缀 |
model_name_or_path | str \| os.PathLike | Hugging Face 仓库 id(如CompVis/ldm-text2im-large-256)或包含save_pretrained产物(含model_index.json)的本地目录 |
proxies | dict[str, str] \| None | 按协议/端点指定的代理服务器字典,如{'http': 'foo.bar:3128'},用于下载请求 |
revision | str(默认"main") | 指定 Hugging Face 上模型的具体版本,可以是分支名、标签名或 commit id |
variant | str \| None | 模型变体,如fp16/fp32(例如DeepFloyd/IF-I-XL-v1.0提供这两种变体),可节省下载带宽与磁盘空间 |
pipeline_class | str \| type[DiffusionPipeline] \| None | 指定用于下载与解析模型的 Pipeline 类;传字符串时会被解析为类对象(见下文_str2cls) |
sync_with_hub_version | bool(默认False) | 为True时,模型版本将自动与 Hugging Face 仓库的 commit hash 同步 |
signatures | dict | 推理方法签名;默认{"__call__": {"batchable": False}} |
labels/custom_objects/external_modules/metadata | 杂项 | 管理标签、自定义对象(cloudpickle 序列化)、外部模块与元数据(须为str/int等原始类型) |
版本同步机制(sync_with_hub_version)
当sync_with_hub_version=True时,导入完成后会从下载目录中解析出 commit hash 作为模型版本号;如果同时指定了variant,版本号会追加-<variant>后缀(源码 L511-L534):
version = extract_commit_hash(src_dir, REGEX_COMMIT_HASH) if version is not None: if variant is not None: version = version + "-" + variant tag.version = version两个注意点(源码中均有实现逻辑):
- 若用户显式传入
name:version,日志会警告该版本可能被 Hub commit hash 覆盖; - 当
model_name_or_path指向本地目录时,sync_with_hub_version=True会直接抛出BentoMLException("Cannot sync version with huggingface hub when importing a local model")。
这一点由测试 test_diffusers_unit.py 明确验证:sync_with_hub_version=True时bento_model.tag.version等于传入的revisioncommit hash;不开启时保留用户显式指定的版本(如"asdf")。
三种导入路径
源码根据model_name_or_path的性质选择下载方式:
- 本地目录:直接使用该目录作为源目录(源码 L499-L504);
- 指定了
pipeline_class:调用pipeline_class.download(...)精确下载对应 Pipeline 组件(源码 L506-L509),适用于需要按 Pipeline 结构组织权重的场景; - 未指定 Pipeline 类:回退到
huggingface_hub.snapshot_download全量快照下载(源码 L520-L527)。
无论走哪条路径,最终都会校验源目录中是否存在model_index.json,不存在则抛出BentoMLException(f'artifact "{src_dir}" is not a Diffusion model')(源码 L551-L553),随后把整个目录(忽略.git)复制进模型库的diffusion_model/目录。
pipeline_class字符串解析:_str2cls
pipeline_class支持直接传类对象或类名字符串。字符串解析逻辑位于 diffusers.py#L154-L168:先按最后一个.切分模块名与类名,若未提供模块名则默认从diffusers导入,最终通过importlib.import_module+getattr得到类。因此你既可以写"diffusers.StableDiffusionPipeline",也可以直接写"StableDiffusionPipeline"。
save_model:保存内存中的 Pipeline
如果你已经在内存中构造好了一个diffusers.DiffusionPipeline(例如微调或组合过组件之后),可以调用save_model直接写入模型库(源码 diffusers.py#L560-L638):
import diffusers import bentoml pipeline = diffusers.StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5") bentoml.diffusers.save_model("my_sd15_model", pipeline)关键行为:
- 参数
pipeline必须是diffusers.DiffusionPipeline实例,否则抛出BentoMLException; - 未传
signatures时默认同样为{"__call__": {"batchable": False}}; - 底层调用
pipeline.save_pretrained(diffusion_model_dir),把完整 Pipeline(含model_index.json与各组件权重)序列化进模型库的diffusion_model/目录。
注意save_model与import_model的一个差异:save_model不记录options(源码 L629 传入options=None),因此通过save_model保存的模型不具备pipeline_class、variant等持久化选项,加载时的行为完全由load_model的参数决定。
load_model:从模型库加载为可推理 Pipeline
load_model是运行时最核心的函数(源码 diffusers.py#L197-L374),它把模型库中的 Diffusion 模型还原为 diffusers Pipeline:
import bentoml pipeline = bentoml.diffusers.load_model('my_diffusers_model:latest') images = pipeline(prompt)bento_model参数既可以是Tag/str(内部先经get校验模块归属),也可以是现成的bentoml.Model实例。若模型的info.module不是bentoml.diffusers,会抛出NotFound。
主要加载参数
| 参数 | 类型 / 默认 | 说明 |
|---|---|---|
device_id | str \| torch.device \| None | 把 Pipeline 放到指定设备(参考 PyTorch device 属性) |
pipeline_class | 默认diffusers.DiffusionPipeline | 用于加载保存模型的 Pipeline 类,支持字符串形式(经_str2cls解析) |
device_map | None \| str \| dict[str, int \| str \| torch.device] | 指定每个子模块放置的设备映射,透传给from_pretrained |
custom_pipeline | str \| None | 社区自定义 Pipeline 标识(托管于 GitHub 的 community pipelines) |
scheduler_class | type[SchedulerMixin] \| None | 加载后替换 Pipeline 使用的调度器 |
torch_dtype | str \| torch.dtype \| None | 覆盖默认 dtype 加载模型权重 |
low_cpu_mem_usage | bool \| None | 不初始化权重、只加载预训练权重以加速加载 |
enable_xformers | bool(默认False) | 启用 xformers 内存高效注意力 |
enable_attention_slicing | int \| str \| None | 启用注意力切片(可传 slice size) |
enable_model_cpu_offload/enable_sequential_cpu_offload | bool \| None | 两种 CPU offload 策略 |
enable_torch_compile | bool \| None | 对 UNet 执行torch.compile |
variant | str \| None | 加载指定变体权重文件,如pytorch_model.<variant>.bin |
lora_weights | LoraOptionType \| list[...] \| None | 加载 LoRA 权重(见下文) |
textual_inversions | TextualInversionOptionType \| list[...] \| None | 加载 Textual Inversion 权重 |
load_pretrained_extra_kwargs | dict[str, Any] \| None | 透传给 Pipelinefrom_pretrained的额外 kwargs |
加载流程的源码级细节
low_cpu_mem_usage的自动判定:为None时,若 torch ≥ 1.9.0 且accelerate可用,则自动置True,否则False(源码 L305-L309);- Pipeline 实例化:调用
pipeline_class.from_pretrained(diffusion_model_dir, torch_dtype=..., low_cpu_mem_usage=..., device_map=..., custom_pipeline=..., variant=..., **load_pretrained_extra_kwargs)(源码 L312-L320); - 调度器替换:若传入
scheduler_class,用scheduler_class.from_config(pipeline.scheduler.config)重建并替换pipeline.scheduler(源码 L322-L326); - 设备迁移的防冲突逻辑:当目标设备是
cuda且同时启用了device_map、sequential_cpu_offload或model_cpu_offload时,跳过pipeline.to(device_id),避免与 offload/分片机制冲突(源码 L328-L343,注释引用了 diffusers 的 issue #2782); - 优化开关顺序执行:
enable_xformers→sequential_cpu_offload→model_cpu_offload→attention_slicing→torch_compile(对pipeline.unet以mode="reduce-overhead", fullgraph=True编译,源码 L357-L361)。
LoRA 与 Textual Inversion 的加载
LoraOptionType可以是str或dict[str, str]:
- 字符串形式(
_prepare_lora_args,源码 L77-L119):先按“本地权重文件路径”解析——绝对路径存在则直接用;否则拼接lora_dir(默认当前工作目录,支持~展开)再判断相对路径。路径解析成功则返回(model_name, {"weight_name": 文件名})。若两者都不命中,则把字符串当作 Hugging Face 仓库 id 处理,格式须为org/repo/weightfile形式(至少两个/,否则抛出ValueError)。 - 字典形式:必须包含
model_name键(指向 Hub 仓库或本地目录),可含weight_name键及其他透传给pipeline.load_lora_weights的 kwargs。
加载时若传入多个 LoRA 权重,源码会记录警告“Currently diffusers only support single lora weight loading”,并只加载第一个(源码 L130-L137)。此外,load_model在加载 LoRA 前会校验pipeline_class是否是LoraLoaderMixin的子类,Textual Inversion 同理校验TextualInversionLoaderMixin,不满足直接抛NotImplementedError(源码 L291-L301)。
get:从模型库获取 Model 对象
get是最轻量的 API(源码 diffusers.py#L171-L194):
import bentoml model = bentoml.diffusers.get("my_stable_diffusion_model")它接收str | Tag,返回bentoml.Model。与通用bentoml.models.get的区别在于:它会校验模型的info.module是否为bentoml.diffusers,若不是则抛出NotFound,从而避免用 diffusers 加载器误读其他框架保存的模型。拿到 Model 实例后,可以继续调用model.with_options(...)或model.to_runnable()完成服务化装配。
服务化:Runnable 与运行时行为
bentoml.diffusers通过私有接口get_runnable(bento_model)(源码 diffusers.py#L641-L868)把模型转换为 BentoML 的Runnable(建议通过bentoml.Model.to_runnable使用)。该 Runnable 的行为可以从bentoml.models._create时持久化的ModelOptions推导,ModelOptions定义在 diffusers.py#L53-L74,覆盖pipeline_class、scheduler_class、torch_dtype、device_map、各类 offload/优化开关、variant、lora_dir、lora_weights、textual_inversions等。
Runnable 的运行时特性(均有源码依据):
- 资源声明:
SUPPORTED_RESOURCES = ("nvidia.com/gpu", "cpu"),SUPPORTS_CPU_MULTI_THREADING = True; - dtype 默认策略:CUDA 可用且未显式指定
torch_dtype时自动使用torch.float16;CUDA 可用且未显式指定enable_xformers时,若环境安装了 xformers 则自动启用; - 动态 LoRA:若 Pipeline 类支持 LoRA,Runnable 会注册
_load_lora_weights/_unload_lora_weights私有方法;调用推理方法时可通过 kwargs 传入lora_weights,在推理前后自动加载/卸载,并在finally中执行torch.cuda.empty_cache()释放显存(源码 L816-L828); - 调度器热替换:注册了
_replace_scheduler(scheduler_txt)方法,按类名字符串解析新调度器,若与当前调度器类型相同则直接返回{"success": True},若兼容则替换,否则返回失败原因(cannot import scheduler class/scheduler class is incompatible to this pipeline),见 tests/integration/frameworks/models/diffusers.py 中对_replace_scheduler的四组用例断言; - 输出归一化:推理结果若是
diffusers.utils.BaseOutput(diffusers 新版输出容器),统一to_tuple()转成可序列化元组(源码 L831-L833)。
简化入口:stable_diffusion / stable_diffusion_xl
对于 Stable Diffusion 与 SDXL 这类最常见的模型,仓库在 diffusers_simple.py 提供了开箱即用的 Runner 工厂:stable_diffusion.create_runner(...)与stable_diffusion_xl.create_runner(...),实现位于 stable_diffusion.py 与 stable_diffusion_xl.py。
它们内部复用了import_model+sync_with_hub_version=True的导入链路:get_model_or_download(utils.py)会先用bentoml.diffusers.get查本地模型库,存在且与 Hub 最新 commit 一致则直接复用,否则自动导入,并把 Hub commit hash 作为版本号;模型名由backend-model_id规范化生成(/转--、_转-)。两个工厂分别预设了默认模型与 Pipeline 映射:
stable_diffusion:默认stabilityai/stable-diffusion-2-1,支持text2img/img2img,默认输出尺寸768×768;stable_diffusion_xl:默认stabilityai/stable-diffusion-xl-base-1.0,支持text2img/img2img,默认输出尺寸1024×1024。
create_runner的参数与load_model高度对齐(pipeline_class、scheduler_class、torch_dtype、各类 offload 与优化开关、lora_weights、textual_inversions等),最终通过model.with_options(**options).to_runner()产出 Runner。
测试验证与事实来源
仓库的集成测试确认了上述行为:
- tests/integration/frameworks/models/diffusers.py:使用
hf-internal-testing/tiny-stable-diffusion-torch构造测试模型,验证__call__输出形状为(256, 256, 3),并覆盖_replace_scheduler的成功/导入失败/不兼容三种分支; - tests/integration/frameworks/test_diffusers_unit.py:验证
sync_with_hub_version对模型版本号的影响(Hub commit hash 覆盖用户版本、本地导入禁用同步等)。
小结
bentoml.diffusers的四个 API 构成了一条完整的模型生命周期链路:import_model(入库)→get(查询)→load_model(加载推理)→save_model(保存自定义 Pipeline),配合ModelOptions与 Runnable 机制即可将 Diffusion 模型无缝接入 BentoML 的 Bento 打包与部署流程。若你的目标只是快速服务 Stable Diffusion 系模型,可直接使用bentoml.diffusers_simple.stable_diffusion/stable_diffusion_xl工厂;而理解本文的底层 API,将帮助你更精细地控制调度器、dtype、LoRA 注入与显存优化策略。
- 模型推理服务
- 人工智能
- 后端
- 大模型
- MLOps
- LLMOps
【免费下载链接】BentoML
The easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!
相关推荐
BentoML Transformers 框架 API 详解:save_model、load_model 与 get 实战指南
BentoML Transformers 框架 API 详解:save_model、load_model 与 get 实战指南 本篇是 BentoML 官方 A
模型推理服务人工智能后端大模型MLOpsLLMOpsBentoML ONNX 框架 API 参考:save_model / load_model / get 完整指南
BentoML ONNX 框架 API 参考:save_model / load_model / get 完整指南 本篇以 BentoML 官方 API 参考文
模型推理服务人工智能后端大模型MLOpsLLMOpsHyperswitch 架构深度解析:Router、Scheduler、数据库与可观测性体系
Hyperswitch 架构深度解析:Router、Scheduler、数据库与可观测性体系 本篇技术指南以 Hyperswitch 官方 架构文档 https
模型推理服务人工智能后端大模型MLOpsLLMOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考