乐趣区

关于人工智能:在英特尔-CPU-上加速-Stable-Diffusion-推理

前一段时间,咱们向大家介绍了最新一代的 英特尔至强 CPU (代号 Sapphire Rapids),包含其用于减速深度学习的新硬件个性,以及如何应用它们来减速自然语言 transformer 模型的 分布式微调 和 推理。

本文将向你展现在 Sapphire Rapids CPU 上减速 Stable Diffusion 模型推理的各种技术。后续咱们还打算公布对 Stable Diffusion 进行分布式微调的文章。

在撰写本文时,取得 Sapphire Rapids 服务器的最简略办法是应用 Amazon EC2 R7iz 系列实例。因为它仍处于预览阶段,你须要 注册 能力取得拜访权限。与之前的文章一样,我应用的是 r7iz.metal-16xl 实例 (64 个 vCPU,512GB RAM),操作系统镜像为 Ubuntu 20.04 AMI (ami-07cd3e6c4915b2d18)。

本文的代码可从 Gitlab 上获取。咱们开始吧!

Diffusers 库

Diffusers 库使得用 Stable Diffusion 模型生成图像变得极其简略。如果你不相熟 Stable Diffusion 模型,这里有一个很棒的 图文介绍。

首先,咱们创立一个蕴含以下库的虚拟环境: Transformers、Diffusers、Accelerate 以及 PyTorch。

virtualenv sd_inference
source sd_inference/bin/activate
pip install pip --upgrade
pip install transformers diffusers accelerate torch==1.13.1

而后,咱们写一个简略的基准测试函数,反复推理屡次,最初返回单张图像生成的均匀提早。

import time

def elapsed_time(pipeline, prompt, nb_pass=10, num_inference_steps=20):
    # warmup
    images = pipeline(prompt, num_inference_steps=10).images
    start = time.time()
    for _ in range(nb_pass):
        _ = pipeline(prompt, num_inference_steps=num_inference_steps, output_type="np")
    end = time.time()
    return (end - start) / nb_pass

当初,咱们用默认的 float32 数据类型构建一个 StableDiffusionPipeline,并测量其推理提早。

from diffusers import StableDiffusionPipeline

model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(model_id)
prompt = "sailing ship in storm by Rembrandt"
latency = elapsed_time(pipe, prompt)
print(latency)

均匀提早为 32.3 秒 。正如这个英特尔开发的 Hugging Face Space 所展现的,雷同的代码在上一代英特尔至强 (代号 Ice Lake) 上运行须要大概 45 秒。

开箱即用,咱们能够看到 Sapphire Rapids CPU 在没有任何代码更改的状况下速度相当快!

当初,让咱们持续减速它吧!

Optimum Intel 与 OpenVINO

Optimum Intel 用于在英特尔平台上减速 Hugging Face 的端到端流水线。它的 API 和 Diffusers 原始 API 极其类似,因而所需代码改变很小。

Optimum Intel 反对 OpenVINO,这是一个用于高性能推理的英特尔开源工具包。

Optimum Intel 和 OpenVINO 装置如下:

pip install optimum[openvino]

相比于上文的代码,咱们只须要将 StableDiffusionPipeline 替换为 OVStableDiffusionPipeline 即可。如需加载 PyTorch 模型并将其实时转换为 OpenVINO 格局,你只需在加载模型时设置 export=True

from optimum.intel.openvino import OVStableDiffusionPipeline
...
ov_pipe = OVStableDiffusionPipeline.from_pretrained(model_id, export=True)
latency = elapsed_time(ov_pipe, prompt)
print(latency)

# Don't forget to save the exported model
ov_pipe.save_pretrained("./openvino")

OpenVINO 会主动优化 bfloat16 模型,优化后的均匀提早降落到了 16.7 秒 ,相当不错的 2 倍减速。

上述 pipeline 反对动静输出尺寸,对输出图像 batch size 或分辨率没有任何限度。但在应用 Stable Diffusion 时,通常你的应用程序仅限于输入一种 (或几种) 不同分辨率的图像,例如 512×512 或 256×256。因而,通过固定 pipeline 的输入分辨率来解锁更高的性能增益有其实际意义。如果你须要不止一种输入分辨率,您能够简略地保护几个 pipeline 实例,每个分辨率一个。

ov_pipe.reshape(batch_size=1, height=512, width=512, num_images_per_prompt=1)
latency = elapsed_time(ov_pipe, prompt)

固定输入分辨率后,均匀提早进一步降至 4.7 秒 ,又取得了额定的 3.5 倍减速。

如你所见,OpenVINO 是减速 Stable Diffusion 推理的一种简略无效的办法。与 Sapphire Rapids CPU 联合应用时,和至强 Ice Lake 的最后性能的相比,推理性能减速近 10 倍。

如果你不能或不想应用 OpenVINO,本文下半局部会展现一系列其余优化技术。系好安全带!

零碎级优化

扩散模型是数 GB 的大模型,图像生成是一种内存密集型操作。通过装置高性能内存调配库,咱们可能减速内存操作并使之能在 CPU 核之间并行处理。请留神,这将更改零碎的默认内存调配库。你能够通过卸载新库来返回默认库。

jemalloc 和 tcmalloc 是两个很有意思的内存优化库。这里,咱们应用 jemalloc,因为咱们测试下来,它的性能比 tcmalloc 略好。jemalloc 还能够用于针对特定工作负载进行调优,如最大化 CPU 利用率。详情可参考 jemalloc 调优指南。

sudo apt-get install -y libjemalloc-dev
export LD_PRELOAD=$LD_PRELOAD:/usr/lib/x86_64-linux-gnu/libjemalloc.so
export MALLOC_CONF="oversize_threshold:1,background_thread:true,metadata_thp:auto,dirty_decay_ms: 60000,muzzy_decay_ms:60000"

接下来,咱们装置 libiomp 库来优化多核并行,这个库是 英特尔 OpenMP 运行时库 的一部分。

sudo apt-get install intel-mkl
export LD_PRELOAD=$LD_PRELOAD:/usr/lib/x86_64-linux-gnu/libiomp5.so
export OMP_NUM_THREADS=32

最初,咱们装置 numactl 命令行工具。它让咱们能够把咱们的 Python 过程绑定到指定的核,并防止一些上下文切换开销。

numactl -C 0-31 python sd_blog_1.py

应用这些优化后,原始的 Diffusers 代码只需 11.8 秒 就能够实现推理,快了简直 3 倍,而且无需任何代码更改。这些工具在咱们的 32 核至强 CPU 上运行得相当不错。

咱们还有招。当初咱们把 英特尔 PyTorch 扩大 (Intel Extension for PyTorch,IPEX) 引入进来。

IPEX 与 BF16

IPEX 扩大了 PyTorch 使之能够进一步充分利用英特尔 CPU 上的硬件加速性能,包含 AVX-512、矢量神经网络指令 (Vector Neural Network Instructions,AVX512 VNNI) 以及 先进矩阵扩大 (AMX)。

咱们先装置 IPEX

pip install intel_extension_for_pytorch==1.13.100

装好后,咱们须要批改局部代码以将 IPEX 优化利用到 pipeline 的每个模块 (你能够通过打印 pipe 对象列举出它有哪些模块 ),其中之一的优化就是把数据格式转换为 channels-last 格局。

import torch
import intel_extension_for_pytorch as ipex
...
pipe = StableDiffusionPipeline.from_pretrained(model_id)

# to channels last
pipe.unet = pipe.unet.to(memory_format=torch.channels_last)
pipe.vae = pipe.vae.to(memory_format=torch.channels_last)
pipe.text_encoder = pipe.text_encoder.to(memory_format=torch.channels_last)
pipe.safety_checker = pipe.safety_checker.to(memory_format=torch.channels_last)

# Create random input to enable JIT compilation
sample = torch.randn(2,4,64,64)
timestep = torch.rand(1)*999
encoder_hidden_status = torch.randn(2,77,768)
input_example = (sample, timestep, encoder_hidden_status)

# optimize with IPEX
pipe.unet = ipex.optimize(pipe.unet.eval(), dtype=torch.bfloat16, inplace=True, sample_input=input_example)
pipe.vae = ipex.optimize(pipe.vae.eval(), dtype=torch.bfloat16, inplace=True)
pipe.text_encoder = ipex.optimize(pipe.text_encoder.eval(), dtype=torch.bfloat16, inplace=True)
pipe.safety_checker = ipex.optimize(pipe.safety_checker.eval(), dtype=torch.bfloat16, inplace=True)

咱们应用了 bloat16 数据类型,以利用 Sapphire Rapids CPU 上的 AMX 加速器。

with torch.cpu.amp.autocast(enabled=True, dtype=torch.bfloat16):
    latency = elapsed_time(pipe, prompt)
    print(latency)

通过此番改变,推理提早从 11.9 秒进一步缩小到 5.4 秒 。感激 IPEX 和 AMX,推理速度进步了 2 倍以上。

还能榨点性能进去吗?能,咱们将眼光转向调度器 (scheduler)!

调度器

Diffusers 库反对为每个 Stable Diffusion pipiline 配置 调度器 (scheduler),用于在去噪速度和去噪品质之间找到最佳折衷。

依据文档所述:“ 截至本文档撰写时,DPMSolverMultistepScheduler 能实现最佳的速度 / 品质衡量,只需 20 步即可运行。”咱们能够试一下 DPMSolverMultistepScheduler

from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
...
dpm = DPMSolverMultistepScheduler.from_pretrained(model_id, subfolder="scheduler")
pipe = StableDiffusionPipeline.from_pretrained(model_id, scheduler=dpm)

最终,推理提早降至 5.05 秒 。与咱们最后的 Sapphire Rapids 基线 (32.3 秒) 相比,简直快了 6.5 倍!

运行环境: Amazon EC2 r7iz.metal-16xl, Ubuntu 20.04, Linux 5.15.0-1031-aws, libjemalloc-dev 5.2.1-1, intel-mkl 2020.0.166-1, PyTorch 1.13.1, Intel Extension for PyTorch 1.13.1, transformers 4.27.2, diffusers 0.14, accelerate 0.17.1, openvino 2023.0.0.dev20230217, optimum 1.7.1, optimum-intel 1.7

总结

在几秒钟内生成高质量图像的能力可用于许多场景,如 2C 的应用程序、营销和媒体畛域的内容生成,或生成合成数据以裁减数据集。

如你想要在这方面起步,以下是一些有用的资源:

  • Diffusers 文档
  • Optimum Intel 文档
  • 英特尔 IPEX on GitHub
  • 英特尔和 Hugging Face 联结出品的开发者资源网站

如果你有任何问题或反馈,请通过 Hugging Face 论坛 通知咱们。

感激垂阅!


英文原文: https://hf.co/blog/stable-diffusion-inference-intel

作者: Julien Simon, Ella Charlaix

译者: MatrixYao

审校 / 排版: zhongdongy (阿东)

退出移动版