
DeepFloyd IF
用 DeepFloyd IF 分三阶段生成 1024×1024 图像
DeepFloyd IF 把文生图拆成三个阶段:64×64 基础模型、256×256 超分、1024×1024 超分。本文讲清显存门槛、Hugging Face 许可授权、Diffusers 与原生 deepfloyd_if 两套调用方式,并给出 Dream、风格迁移、超分辨率、局部重绘四种模式的完整代码。
DeepFloyd IF 是一个开源的文本生成图像模型,它的结构与常见的单模型文生图方案不同:文本编码器是冻结的 T5 transformer,负责把提示词转成文本嵌入;图像生成则被拆成三个级联的像素 diffusion 模块,先由基础模型生成 64×64 的低分辨率图像,再由两个超分辨率模型逐级放大到 256×256 和 1024×1024。每个阶段都通过交叉注意力和注意力池把文本嵌入注入 UNet。这种「先定构图、再补细节」的路线,让它在语言理解和画面逼真度上有不错的表现,在 COCO 数据集上的零样本 FID 得分为 6.66。
适合读这篇的人:手上有 16GB 以上显存的 NVIDIA 显卡、想在本机或 Notebook 环境里跑通完整三阶段流程的开发者;需要把文生图拆成可控中间步骤、以便检查每一步输出的研究者;以及想用同一套权重做风格迁移、超分辨率、局部重绘等多种任务的人。如果你只是想快速出一张图、不想折腾环境,这套流程的显存门槛和分阶段调用会显得偏重。站内 DeepFloyd IF 工具页可以作为入口参考,具体操作以下面的步骤为准。
需要提前说明:模型权重、依赖版本、许可条款都可能随时间调整,本文涉及的版本号与显存数字仅反映素材所述情形,实际使用请以 Hugging Face 模型卡与官方仓库的当前信息为准。
准备工作
硬件与显存门槛
三阶段全部跑起来对显存有明确要求,素材给出的最低配置如下:
- 运行 IF-I-XL(4.3B 参数,文本到 64×64 基础模块)与 IF-II-L(1.2B 参数,放大到 256×256 的超分模块),需要 16GB 显存。
- 再加上 Stable x4(放大到 1024×1024 的超分模块)跑完整链路,需要 24GB 显存。
- 如果启用 xformers,需要设置环境变量
FORCE_MEM_EFFICITE_ATTN=1。
另外,Diffusers 默认会对整个 IF 管道启用模型 CPU 卸载(model CPU offload),在这种模式下 14GB 显存也能跑,代价是部分计算被挪到内存,速度会慢一些。显存紧张时优先考虑这条路径。
Hugging Face 账号与模型许可
IF 的权重托管在 Hugging Face 上,使用前必须先接受模型的使用条件,否则下载会被拒绝。步骤是:
- 准备一个 Hugging Face 账号并登录。
- 打开
DeepFloyd/IF-I-XL-v1.0的模型卡页面,接受许可协议。 - 在本地登录 Hugging Face Hub。先升级客户端:
pip install huggingface_hub --upgrade
然后在 Python 交互环境里调用登录函数,按提示粘贴你的访问令牌(access token):
from huggingface_hub import login
login()
令牌在 Hugging Face 账号设置里生成,属于敏感凭据,不要写进代码仓库或公开的 Notebook。
安装依赖
有两条技术路线,依赖不一样,建议先想清楚走哪条。
路线一:原生 deepfloyd_if 包。素材给出的安装命令是:
pip install deepfloyd_if==1.0.2rc0
pip install xformers==0.0.16
pip install git+ --no-deps
注意第三条命令在素材中缺少仓库地址,无法直接执行。实际安装时请到项目仓库确认完整的 Git 地址后再运行,不要照抄这一行。版本号同样以仓库当前说明为准。
路线二:Hugging Face Diffusers。Diffusers 把三个阶段拆成独立的 pipeline,可以单独运行每一级、随时检查中间结果,适合调试和自定义。安装命令:
pip install diffusers accelerate transformers safetensors
如果你使用的 PyTorch 版本大于等于 2.0.0,需要删掉代码里所有 enable_xformers_memory_efficient_attention() 调用,否则会报错。这一点在下面每个阶段都会重复出现。
操作步骤
第一步:加载三个阶段模型
用 Diffusers 时,三个阶段分别从不同的仓库加载。第一阶段加载基础模型,并开启 CPU 卸载:
from diffusers import DiffusionPipeline
from diffusers.utils import pt_to_pil
import torch
stage_1 = DiffusionPipeline.from_pretrained("DeepFloyd/IF-I-XL-v1.0", variant="fp16", torch_dtype=torch.float16)
stage_1.enable_xformers_memory_efficient_attention() # torch >= 2.0.0 时删除此行
stage_1.enable_model_cpu_offload()
第二阶段加载 256×256 超分模型。注意这里显式传入 text_encoder=None,因为文本嵌入由第一阶段算好后直接复用,第二阶段不需要再加载 T5:
stage_2 = DiffusionPipeline.from_pretrained(
"DeepFloyd/IF-II-L-v1.0",
text_encoder=None,
variant="fp16",
torch_dtype=torch.float16
)
stage_2.enable_xformers_memory_efficient_attention() # torch >= 2.0.0 时删除此行
stage_2.enable_model_cpu_offload()
第三阶段加载 Stable Diffusion x4 超分模型。它需要安全模块,直接从第一阶段对象上取,避免重复加载:
safety_modules = {"feature_extractor": stage_1.feature_extractor, "safety_checker": stage_1.safety_checker, "watermarker": stage_1.watermarker}
stage_3 = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-x4-upscaler", **safety_modules, torch_dtype=torch.float16)
stage_3.enable_xformers_memory_efficient_attention() # torch >= 2.0.0 时删除此行
stage_3.enable_model_cpu_offload()
第二步:编码提示词
文本嵌入只算一次,三个阶段共用。同时生成正向和负向嵌入,负向嵌入用于无分类器引导:
prompt = 'a photo of a kangaroo wearing an orange hoodie and blue sunglasses standing in front of the eiffel tower holding a sign that says "very deep learning"'
prompt_embeds, negative_embeds = stage_1.encode_prompt(prompt)
generator = torch.manual_seed(0)
固定随机种子是为了让结果可复现。三个阶段传入同一个 generator,级联过程中的噪声序列才能保持一致。
第三步:逐阶段生成并保存中间结果
第一阶段输出 64×64 的潜变量结果,用 output_type="pt" 拿到张量,再转成 PIL 图像保存:
image = stage_1(prompt_embeds=prompt_embeds, negative_prompt_embeds=negative_embeds, generator=generator, output_type="pt").images
pt_to_pil(image)[0].save("./if_stage_I.png")
第二阶段接收上一阶段的张量作为 image 输入,继续放大到 256×256:
image = stage_2(
image=image,
prompt_embeds=prompt_embeds,
negative_prompt_embeds=negative_embeds,
generator=generator,
output_type="pt"
).images
pt_to_pil(image)[0].save("./if_stage_II.png")
第三阶段换成文本提示词输入,并需要指定 noise_level,素材示例取 100:
image = stage_3(prompt=prompt, image=image, generator=generator, noise_level=100).images
image[0].save("./if_stage_III.png")
三个阶段各存一张图,方便对比构图、细节和分辨率的变化。如果只想看最终结果,中间两张可以跳过保存。
第四步(可选):改用原生 deepfloyd_if 包
如果不走 Diffusers,而是用原生包,模型加载方式如下:
from deepfloyd_if.modules import IFStageI, IFStageII, StableStageIII
from deepfloyd_if.modules.t5 import T5Embedder
device = 'cuda:0'
if_I = IFStageI('IF-I-XL-v1.0', device=device)
if_II = IFStageII('IF-II-L-v1.0', device=device)
if_III = StableStageIII('stable-diffusion-x4-upscaler', device=device)
t5 = T5Embedder(device="cpu")
注意 T5 文本编码器被放在 CPU 上,这是为了省显存。原生包把四种能力封装成 deepfloyd_if.pipelines 下的四个函数:dream、style_transfer、super_resolution、inpainting。下面逐一说明。
一个完整示例
下面用原生包的 dream 函数跑一次完整的文生图,一次生成 4 张,这是最能体现三阶段级联效果的用法。
from deepfloyd_if.pipelines import dream
prompt = 'ultra close-up color photo portrait of rainbow owl with deer horns in the woods'
count = 4
result = dream(
t5=t5,
if_I=if_I,
if_II=if_II,
if_III=if_III,
prompt=[prompt]*count,
seed=42,
if_I_kwargs={
"guidance_scale": 7.0,
"sample_timestep_respacing": "smart100",
},
if_II_kwargs={
"guidance_scale": 4.0,
"sample_timestep_respacing": "smart50",
},
if_III_kwargs={
"guidance_scale": 9.0,
"noise_level": 20,
"sample_timestep_respacing": "75",
},
)
if_III.show(result['III'], size=14)
几个参数值得单独解释:
prompt传的是列表,长度等于count,所以一次出 4 张。想批量出不同提示词,就把列表换成不同的字符串。guidance_scale三个阶段取值不同:基础阶段 7.0,第二阶段 4.0,第三阶段 9.0。数值越高越贴合提示词,但过高容易过饱和或出现伪影。sample_timestep_respacing控制采样步数的重排策略。smart100、smart50是预设策略,"75"表示固定 75 步。步数越多越慢、细节通常越好。noise_level只在第三阶段出现,示例取 20,控制超分时注入的噪声强度。seed固定为 42,保证可复现。
返回的 result 是一个字典,键 I、II、III 分别对应三个阶段的输出,可以只取其中一级查看。
模式二:零样本图生图风格迁移
风格迁移把一张参考图(support_pil_img)的内容保留下来,按提示词描述的风格重新绘制。每个风格提示词对应一张输出:
from deepfloyd_if.pipelines import style_transfer
result = style_transfer(
t5=t5,
if_I=if_I,
if_II=if_II,
support_pil_img=raw_pil_image,
style_prompt=[
'in style of professional origami',
'in style of oil art, Tate modern',
'in style of plastic building bricks',
'in style of classic anime from 1990',
],
seed=42,
if_I_kwargs={
"guidance_scale": 10.0,
"sample_timestep_respacing": "10,10,10,10,10,10,10,10,0,0",
'support_noise_less_qsample_steps': 5,
},
if_II_kwargs={
"guidance_scale": 4.0,
"sample_timestep_respacing": 'smart50',
"support_noise_less_qsample_steps": 5,
},
)
if_I.show(result['II'], 1, 20)
这里有两个风格迁移专属参数:support_noise_less_qsample_steps 控制参考图在采样中保留多少原始信息;sample_timestep_respacing 用逗号分隔的步数序列,末尾的 0 表示该段不再采样。风格迁移通常只跑到第二阶段就足够,示例里展示的也是 result['II']。
模式三:超分辨率
超分辨率模式可以对不一定由 IF 生成的图像做放大,两级级联:先用 IF-II 放大到中间分辨率,再用 IF-III 或 Stable x4 放大到最终分辨率。
from deepfloyd_if.pipelines import super_resolution
middle_res = super_resolution(
t5,
if_III=if_II,
prompt=['woman with a blue headscarf and a blue sweaterp, detailed picture, 4k dslr, best quality'],
support_pil_img=raw_pil_image,
img_scale=4.,
img_size=64,
if_III_kwargs={
'sample_timestep_respacing': 'smart100',
'aug_level': 0.5,
'guidance_scale': 6.0,
},
)
high_res = super_resolution(
t5,
if_III=if_III,
prompt=[''],
support_pil_img=middle_res['III'][0],
img_scale=4.,
img_size=256,
if_III_kwargs={
"guidance_scale": 9.0,
"noise_level": 20,
"sample_timestep_respacing": "75",
},
)
show_superres(raw_pil_image, high_res['III'][0])
注意函数签名里统一用 if_III 这个参数名,第一级实际传入的是 if_II,第二级才传 if_III。这是原生包的接口约定,容易看错。img_scale 是放大倍数,img_size 是输入边长,aug_level 控制增强强度。第二级提示词传空字符串即可,因为细节主要由超分模型补。
模式四:零样本局部重绘
局部重绘需要一张原图和一张同尺寸的蒙版(inpainting_mask),蒙版标记的区域会被提示词内容替换:
from deepfloyd_if.pipelines import inpainting
result = inpainting(
t5=t5,
if_I=if_I,
if_II=if_II,
if_III=if_III,
support_pil_img=raw_pil_image,
inpainting_mask=inpainting_mask,
prompt=[
'oil art, a man in a hat',
],
seed=42,
if_I_kwargs={
"guidance_scale": 7.0,
"sample_timestep_respacing": "10,10,10,10,10,0,0,0,0,0",
'support_noise_less_qsample_steps': 0,
},
if_II_kwargs={
"guidance_scale": 4.0,
'aug_level': 0.0,
"sample_timestep_respacing": '100',
},
if_III_kwargs={
"guidance_scale": 9.0,
"noise_level": 20,
"sample_timestep_respacing": "75",
},
)
if_I.show(result['I'], 2, 3)
if_I.show(result['II'], 2, 6)
if_I.show(result['III'], 2, 14)
重绘模式里 support_noise_less_qsample_steps 设为 0,aug_level 也设为 0,意思是尽量不扰动蒙版外的原始像素。最后三行 show 调用分别展示三个阶段的输出,参数是行列布局。
模型规格与选型
IF 系列按阶段和规模分成多个权重,素材给出的参数与指标如下表。带星号的表示该阶段的最佳模型:
| 模型 | 所属阶段 | 参数量 | FID | Batch size | 训练步数 |
|---|---|---|---|---|---|
| IF-I-M | I | 400M | 8.86 | 3072 | 2.5M |
| IF-I-L | I | 900M | 8.06 | 3200 | 3.0M |
| IF-I-XL* | I | 4.3B | 6.66 | 3072 | 2.42M |
| IF-II-M | II | 450M | - | 1536 | 2.5M |
| IF-II-L* | II | 1.2B | - | 1536 | 2.5M |
| IF-III-L*(后续发布) | III | 700M | - | 3072 | 1.25M |
选型逻辑很直接:显存够就上 XL 和 L,追求 FID 指标就选带星号的组合;显存紧张时降级到 M 系列,参数量小很多,但 FID 会变差。第三阶段在素材写作时标注为「即将发布」,实际是否已提供、以何种形式提供,请以模型库当前状态为准。
注意事项
- 许可必须先接受。没有在模型卡上接受使用条件,
from_pretrained会直接失败。这一步不能靠代码绕过。 - PyTorch 2.0 及以上要删 xformers 调用。所有
enable_xformers_memory_efficient_attention()行都要去掉,否则报错。这是素材里反复强调的坑。 - 第二阶段不要重复加载文本编码器。构造
stage_2时传text_encoder=None,文本嵌入从第一阶段复用,否则白白多占显存。 - 第三阶段的安全模块从第一阶段取。
feature_extractor、safety_checker、watermarker三个对象直接引用stage_1上的实例,不要重新加载。 - CPU 卸载是显存与速度的权衡。默认开启后 14GB 显存可跑,但推理变慢;显存充足时可以关掉换取速度。
- 原生包的安装命令不完整。素材中
pip install git+ --no-deps缺少仓库地址,需自行到项目仓库确认完整地址。 - 参数名有陷阱。
super_resolution函数统一用if_III作为参数名,第一级实际传if_II,照抄示例时不要「纠正」成if_II。 - 版本与配额以官网为准。本文出现的包版本、显存门槛、模型可用状态都可能变化,部署前请核对 Hugging Face 模型卡与项目仓库的当前说明。