news 2026/9/17 7:07:50

mlx-vlm 中的 ERNIE-Image 本地推理:从权重转换、量化到文生图与 SDEdit 编辑的 MLX 实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mlx-vlm 中的 ERNIE-Image 本地推理:从权重转换、量化到文生图与 SDEdit 编辑的 MLX 实践指南

mlx-vlm 中的 ERNIE-Image 本地推理:从权重转换、量化到文生图与 SDEdit 编辑的 MLX 实践指南

【免费下载链接】mlx-vlmMLX-VLM is a package for inference and fine-tuning of Vision Language Models (VLMs) on your Mac using MLX.项目地址: https://gitcode.com/GitHub_Trending/ml/mlx-vlm

本文基于 mlx-vlm 仓库中 ERNIE-Image 模型模块文档 及其配套源码撰写。读完你可以掌握:如何把百度的 ERNIE-Image(Turbo / Base)检查点转换为 MLX 格式并量化、如何用mlx_vlm.generate命令行一键文生图、如何用 Python API 调用generate_image完成生成与图生图(img2img)编辑,以及底层 flow-matching 调度器、单流 DiT Transformer 和 SDEdit 潜空间变换的实际实现原理。

一、ERNIE-Image 是什么:mlx-vlm 中的模型构成

ERNIE-Image 是百度的文生图模型家族。mlx-vlm 在 Apple 芯片(MLX 框架)上用以下四个组件完整复现了它的推理链路:

  • Ministral-3 文本编码器:生成文本条件嵌入(对应 text_encoder.py);
  • ERNIE-Image 扩散 Transformer(单流 DiT):图像主干网络(对应 transformer.py);
  • FLUX.2 VAE:潜空间编解码器,复用 flux2 VAE 实现,通过 weights.py 中的load_vae加载;
  • flow-matching 调度器:即 scheduler.py 中的ErnieImageFlowMatchScheduler,对应官方FlowMatchEulerDiscreteScheduler(shift=4.0)。

此外模型还支持可选的提示词增强(prompt enhancer),将短提示词扩写为完整场景描述。

两个变体与推荐参数

仓库在 config.py 中用VARIANTS字典固化了两个变体的元数据,与官方文档一致:

Hugging Face 模型变体文生图图生图推荐设置
baidu/ERNIE-Image-TurboTurbo8 步,guidance 1
baidu/ERNIE-ImageBase50 步,guidance 4

关键区别在于 classifier-free guidance(CFG):Base 使用 CFG(guidance 4.0),Turbo 在其推荐值 guidance 1.0 下关闭 CFG。源码中这一逻辑非常直接——pipeline 用do_cfg = guidance > 1.0判断是否拼接负向提示词并做条件/无条件预测插值(见 pipeline.py 与_denoise中的unconditional + guidance * (conditional - unconditional))。

另外,宽度/高度必须是16 的正倍数,由 config.py 的validate_dimensions强制校验:小于 16 或不是 16 的倍数会直接抛出ValueError

二、转换检查点到 MLX 格式(convert)

转换入口是 convert.py,可通过python -m mlx_vlm.models.ernie_image.convert调用。

2.1 转换为 BF16

python -m mlx_vlm.models.ernie_image.convert \ --hf-path baidu/ERNIE-Image-Turbo \ --mlx-path ./ERNIE-Image-Turbo-MLX

默认以 BF16(mx.bfloat16)保存全部组件。

2.2 转换并量化

python -m mlx_vlm.models.ernie_image.convert \ --hf-path baidu/ERNIE-Image-Turbo \ --mlx-path ./ERNIE-Image-Turbo-MLX-MXFP8 \ --quantize \ --q-mode mxfp8

支持的量化模式为affinemxfp4nvfp4mxfp8。当省略--q-bits--q-group-size时,会使用各模式的默认值——这些默认值定义在 convert.py 的_MODE_DEFAULTS中:

模式默认 group_size默认 bits
affine644
mxfp4324
nvfp4164
mxfp8328

从源码看有两点值得注意:

  1. 非 affine 模式锁定默认值_quantization_parameters会校验,若mxfp4/nvfp4/mxfp8的 group_size/bits 与默认值不一致则报错,因为这些 block 格式对缩放布局有硬性要求;
  2. 分组件选择性量化:转换按计划依次处理text_encodertransformer(仅layers.*前缀的模块)、vae,若源检查点存在pe/*.safetensors还会处理pe(提示词增强器)。每组件都要求有权重形状可被 group_size 整除才量化(见_quantize_componentcompatible谓词)。

2.3 转换产物的结构

convert_ernie_image会把每个组件分片保存为 safetensors(多分片时生成model-xxxxx-of-yyyyy.safetensors与索引文件),并写入统一的元数据文件mlx_ernie_image.json(记录 variant、组件量化配置、supports_img2img等),同时用_write_missing_configs补写model_index.json、各组件config.json。这些配置缺省值本身也揭示了架构参数,例如 scheduler 默认num_train_timesteps=1000, shift=4.0,VAE 为AutoencoderKLFlux2latent_channels=32, patch_size=[2,2])。

一个细节:如果源 VAE 缺少 encoder 权重,转换时只告警并产出仅支持文生图的检查点(supports_img2img=False);加载 img2img 时 weights.py 的_require_vae_encoder_weights会明确报错提示“缺少 VAE encoder 权重,请从完整官方检查点重新转换”。

三、CLI:文生图与图像编辑

3.1 Turbo 文生图

mlx_vlm.generate \ --output-modality image \ --model baidu/ERNIE-Image-Turbo \ --prompt "A red panda serving tea in a moonlit bamboo forest" \ --size 1024x1024 \ --steps 8 \ --guidance 1 \ --seed 42 \ --output outputs/ernie-image-turbo.png

3.2 Base 文生图(带负向提示词)

mlx_vlm.generate \ --output-modality image \ --model baidu/ERNIE-Image \ --prompt "A cinematic photograph of a fox walking through fresh snow" \ --size 1024x1024 \ --steps 50 \ --guidance 4 \ --seed 42 \ --output outputs/ernie-image.png \ --gen-kwargs '{"negative_prompt":"blurry, low quality"}'

Base 使用 CFG,因此可以通过negative_prompt进一步约束生成质量;而 Turbo 在 guidance=1 时不启用 CFG,负向提示词不会参与条件组合。

3.3 图像编辑(SDEdit 风格 img2img)

mlx_vlm.generate \ --output-modality image \ --task edit \ --model baidu/ERNIE-Image-Turbo \ --image input/fox.png \ --prompt "Give the fox a red Santa hat" \ --size 1024x1024 \ --steps 8 \ --guidance 3 \ --seed 42 \ --output outputs/ernie-image-edit.png \ --gen-kwargs '{"image_strength":0.7}'

编辑功能的几个关键约定(均有源码佐证):

  • 只接受恰好一张源图:model.py 中edit()len(request.image_paths) != 1直接抛错;
  • 它是通用 SDEdit 式重扩散,而非原生指令编辑native_instruction_edit: False),因此需要 guidance > 1(例如 3)才能让请求的改动强有力地施加。Turbo 的编辑默认 guidance 在 config.py 中被单独设为edit_guidance=3.0(生成推荐值保持 1.0 不变),Base 的编辑默认值沿用其生成 guidance;
  • image_strength(别名strength)必须在 (0, 1] 区间,值越大对源图重扩散越多;默认 0.6(见 model.py 的取值与 pipeline.py 的区间校验);
  • 提示词增强在编辑任务默认关闭:因为增强器把提示词改写成独立场景描述,从未看过源图,会稀释编辑意图。如需重新启用,加载模型时传use_prompt_enhancer=True

从 SDEdit 的实现看(pipeline.py 的edit_array):源图先经 VAE encoder 编码并按 VAE 的running_mean/running_var归一化,然后按sigma与噪声线性混合得到起点潜变量,实际去噪步数取round(steps * image_strength),即 strength 越高、跳过的“保留源图”步数越少、重扩散程度越大。

四、Python API 用法

4.1 文生图

from mlx_vlm.generate.image import generate_image, load_image_generation_model model = load_image_generation_model("./ERNIE-Image-Turbo-MLX") result = generate_image( model, "A red panda serving tea in a moonlit bamboo forest", seed=42, steps=8, width=1024, height=1024, guidance=1.0, output_path="outputs/ernie-image-turbo.png", ) print(result.array.shape, result.path)

4.2 图像编辑

from mlx_vlm.generate.image import generate_image, load_image_model model = load_image_model("./ERNIE-Image-Turbo-MLX", task="edit") result = generate_image( model, "Give the fox a red Santa hat", task="edit", image_paths=("input/fox.png",), seed=42, steps=8, guidance=3.0, image_strength=0.7, output_path="outputs/ernie-image-edit.png", ) print(result.array.shape, result.path)

4.3 结果对象

Python 端的主要输出是一个已求值的mx.array(H×W×3 的 uint8 图像),对应ImageGenerationResult(定义于 generate/image.py)。除落盘外,还可以稍后用result.save(path)保存,或调用result.to_b64_json()编码为 base64 PNG。结果对象还携带 seed、width/height、steps、variant、guidance、prompt_tokens、peak_memory(GB)等元数据,便于脚本化验证。

五、源码级实现剖析

5.1 Pipeline 与内存管理

ErnieImagePipeline 按“文本编码 → 去噪 → VAE 解码”三阶段组织,并对内存做了显式治理(ErnieImageRuntimeConfig):

  • evict_text_encoder=True(默认):提示词编码完成后立即释放文本编码器并mx.clear_cache()
  • prompt_cache_size=2:用 LRU 缓存已编码的提示词 hidden states,相同提示词重复生成时跳过编码;
  • evict_transformer:解码完成后可选释放 Transformer 与 VAE。

生成主流程generate_array的要点:

  1. 校验尺寸(16 倍数)、steps >= 1guidance >= 0
  2. 若启用提示词增强,先扩写提示词并记录last_revised_prompt
  3. 潜变量形状为(1, 128, H//16, W//16)(128 通道、16 倍下采样),以seed初始化的mx.random.key采样,dtype 为 bfloat16;
  4. 调度器ErnieImageFlowMatchScheduler(num_inference_steps=steps)逐步step更新潜变量,最后vae.decode_packed_latents解码并映射回 [0, 255] uint8。

5.2 flow-matching 调度器

scheduler.py 是一个紧凑的 Euler flow-matching 实现:sigma 从linspace(1, 0, steps+1)出发,套用官方 shift 变换shift * s / (1 + (shift-1) * s)(默认 shift=4.0),再乘以训练步数 1000 得到 timestep;step用相邻 sigma 差值乘以模型输出做欧拉推进。仓库测试 test_ernie_image.py 中有test_ernie_scheduler_matches_official_static_shift,用于验证该调度与官方实现一致。

5.3 单流 DiT Transformer

ErnieImageTransformer 把图像 token 与文本 token拼接在一条序列中做自注意力(single-stream 设计),默认配置(config.py)为:hidden 4096、FFN 12288、36 层、32 头、输入/输出 128 通道、文本输入维 3072。位置编码采用三轴 RoPE:rope_axes_dim=(32, 48, 48)rope_theta=256——图像 token 的三轴分别是“文本序列长度偏移、y 网格、x 网格”,文本 token 则只用一维索引(见__call__中 position_ids 的构造)。条件注入通过 AdaLN 调制(adaln_modulation线性层输出 6 组 shift/scale/gate)与 final norm 实现,注意力使用mx.core.fast.scaled_dot_product_attention与 QK-RMSNorm。

5.4 文本编码器

text_encoder.py 中的ErnieImageTextEncoder是一个 Ministral-3 架构:hidden 3072、26 层、32 Q 头 / 8 KV 头(GQA)、head_dim 128、YaRN 长上下文 RoPE 参数(factor 16.0)。注意其__call__默认取self.layers[:-1](丢弃最后一层)而不做最终 norm——这是该模型对扩散条件嵌入的实际取法。分词器从本地tokenizer/目录加载(local_files_only=True),默认截断到max_sequence_length=2048

5.5 变体识别与加载入口

model.py 提供ErnieImageGenerationModel/ErnieImageEditModelload/load_edit两个入口。from_model_id接受downloadtokenrevisionevict_text_encoderevict_transformermax_sequence_lengthprompt_cache_sizeuse_prompt_enhancer等 kwargs,默认evict_text_encoder=Truemax_sequence_length=2048prompt_cache_size=2use_prompt_enhancerNone时为自动模式:仅当本地模型快照同时具备pe/*.safetensorspe_tokenizer/tokenizer.json且任务为文生图时启用(见_should_enhance_prompt)。本地目录的变体识别优先读mlx_ernie_image.json元数据,其次按目录名中的turbo关键字判断(config.py 的variant_from_local_path)。

六、验证与测试

仓库为 ERNIE-Image 提供了专门的测试文件 mlx_vlm/tests/test_ernie_image.py,覆盖:

  • 变体元数据(("baidu/ERNIE-Image", 50, 4.0)("baidu/ERNIE-Image-Turbo", 8, 1.0))与本地元数据优先的识别逻辑;
  • 尺寸必须为 16 正倍数的边界校验(test_ernie_dimensions_must_be_positive_multiples_of_16);
  • 调度器与官方 shift 行为一致性、RoPE 混合约定一致性;
  • 微型 Transformer 前向、权重清洗/布局转换(PyTorch NCHW 与 MLX NHWC 卷积权重)、严格量化加载(test_ernie_strict_quantized_loading_modes);
  • 编辑任务对 img2img strength 的前向传递(test_ernie_edit_model_forwards_img2img_strength)。

这些测试表明:上述 CLI 与 Python 用法对应的默认参数(8/50 步、1/4 guidance、strength 0.6 默认值等)均有回归保障。

七、适用前提与限制小结

  • 本模块面向MLX 运行时(Apple 芯片);转换脚本同样在 MLX 环境中执行;
  • 尺寸必须是 16 的正倍数;编辑任务的分辨率在省略 width/height 时由_load_edit_dimension自动对齐到 16 的倍数(区间 [16, 2048]);
  • 图生图是通用 SDEdit,不是原生指令编辑条件,效果强度依赖 guidance 与 image_strength 的组合;
  • 量化仅支持文中四种模式,且对 group_size/bits 有严格默认约束;已量化的组件不能直接再量化(需先反量化);
  • 若源检查点 VAE 不含 encoder,转换产物只能文生图,img2img 会在加载时报错提示重新转换。

以上均可以在 mlx_vlm/models/ernie_image/ 目录下的 README.md、config.py、pipeline.py、convert.py、weights.py 及测试 test_ernie_image.py 中逐一对照验证。

【免费下载链接】mlx-vlmMLX-VLM is a package for inference and fine-tuning of Vision Language Models (VLMs) on your Mac using MLX.项目地址: https://gitcode.com/GitHub_Trending/ml/mlx-vlm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 7:07:43

企业级远程运维工具选型:为什么SSH/SFTP/RDP需要去中心化架构

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 7:06:26

OpenMV+STM32视觉循迹小车实战:图像处理与PID控制详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 7:05:41

基于.NET与微信小程序的市容监察管理系统设计与实现

又是一年毕设季,后台私信里问得最多的还是那句话:“老师/学长,系统类的题目到底怎么选才不踩坑?”其实系统类选题只要业务线清晰、技术栈主流、有完整的闭环,就是最稳妥的方向。今天我就拿一个非常有代表性的题目来拆—…

作者头像 李华
网站建设 2026/9/17 7:05:25

Qt for MCUs 2.11 LTS:MCU级矢量地图渲染实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 7:05:10

Flutter文本处理库copywriter的鸿蒙适配指南

1. Flutter 三方库 copywriter 的鸿蒙化适配指南在移动应用开发领域,文本展示质量直接影响用户体验。作为开发者,我们经常面临中英文混排不美观、标点符号不规范等问题。copywriter 库的出现,为 Flutter 开发者提供了一套优雅的解决方案。本文…

作者头像 李华
网站建设 2026/9/17 7:04:24

SVN从零到实战:安装配置、分支合并与团队权限管理

不论你现在用的是单兵作战还是几十人的研发团队,代码版本管理这件事迟早要面对。Git这几年确实风头很盛,但SVN(Subversion)从来没有退出过主流视野。我见过不少传统企业、外包项目、甚至银行和制造业的研发部门,到现在…

作者头像 李华