社区版Dify 基于vLLM部署Qwen2.5-VL系列视觉大模型与推理加速策略

前言 (为什么在vLLM部署Qwen2.5-VL系列)

去年,我在这个社区版Dify专栏上发布过一篇视觉大模型的博文。社区版Dify+Ollama+llama3.2-vision 实现多模态聊天 。这个大模型管理平台是Ollama,部署的视觉大模型是llama3.2-vision。实现的功能就是可以上存图像跟大模型多轮对话聊天。
但是,我发现有些问题,在一些需要读取其中文文本的(中文OCR)时候,llama3.2-vision并不出色,并且它大概是11b的模型,在Ollama 平台上推理并不算快。而vLLM推理平台可以支持多并发的需求,更重要的是,Ollama 目前并不支持推理Qwen2.5-VL系列(官方的版本)。
视觉多模态模型的最主要最主要的一个功能是(图像/视频内容理解) Image caption & Video caption。推理速度的需求也是存在,因此本篇博文主要介绍 vLLM部署Qwen2.5-VL,并且发布到Dify 平台上使用,其次,分享一些可以推理加速的经验。
Qwen2.5-VL-7B-Instruct 单卡推理实现效果:
在这里插入图片描述

一、vLLM安装Qwen2.5-VL系列

主要是参考这个Qwen2.5-VL 系列vLLM部署官方Github 仓库,我的建议是建立conda 虚拟 环境,直接安装就行。
然后按照其中步骤,实现推理和安装就行。
由于vLLM的推理只要是发布一个API,官方的教程是这样的。你可以部署这几个系列模型:

  • Qwen/Qwen2.5-VL-3B-Instruct
  • Qwen/Qwen2.5-VL-7B-Instruct
  • Qwen/Qwen2.5-VL-32B-Instruct
  • Qwen/Qwen2.5-VL-72B-Instruct

以下是以Qwen/Qwen2.5-VL-7B-Instruct 在vLLM发布API的例子:

vllm serve Qwen/Qwen2.5-VL-7B-Instruct --port 8000 --host 0.0.0.0 --dtype bfloat16 --limit-mm-per-prompt image=5,video=5

命令解释:

  • port是web 端口;
  • host是设置允许访问的主机IP;
  • dtype bfloat16 是设置为混合精度;提高推理速度;
  • limit-mm-per-prompt image=5,video=5 是设置单次聊天中最多的图像和最多的视频数目。

经常遇到的两个问题:
下载模型的网络问题和指定卡推理的问题,因此你可以在命令行上加上指定的HF镜像网站,和指定的显卡运行,如:

sudo CUDA_VISIBLE_DEVICES=2 HF_ENDPOINT=https://hf-mirror.com vllm serve Qwen/Qwen2.5-VL-7B-Instruct --port 8000 --host 0.0.0.0 --dtype bfloat16 --limit-mm-per-prompt image=5,video=5

如果你需要多卡推理和多卡使用,请参考:

sudo CUDA_VISIBLE_DEVICES=2,3 HF_ENDPOINT=https://hf-mirror.com vllm serve Qwen/Qwen2.5-VL-7B-Instruct --port 8000 --host 0.0.0.0 --dtype bfloat16 --tensor-parallel-size 2 --limit-mm-per-prompt image=5,video=5

安装完成后,按照官方的测试代码来测试即可实现,如有特殊的vLLM 的问题可以参考 vLLM官方的使用指南,这里有更详细的说明。

二、推理加速策略1:vLLM中使用flash attention推理加速

在vLLM 中,我们可以使用Flash attention 推理加速,链接在这里
在这里插入图片描述
我在第一次运行 vllm serve … 命令的时候,出现了 一个warning:

WARNING 04-01 15:36:33 [vision.py:97] Current `vllm-flash-attn` has a bug inside vision module, 
so we use xformers backend instead. You can run pip install flash-attn to use flash-attention backend.                                                            

也就是说建议我使用xformers backend 的flash-attention 来推理加速。

pip install flash-attn

然后重新启动 vllm serve ,即可在推理中得到加速,注意当你安装这个库文件之后不用在命令行添加任何flash attention 的命令了,也就是说, vllm 是间接地在xformers 上使用的flash-attention

三、推理加速策略2:预处理Resize图像实现推理加速

首先,让我们先看一下 Qwen2.5-VL Technical Report 论文的创新点:

  1. 基于 Qwen2.5系列 LLM;
  2. 编码部分:动态分辨率 和 视频绝对时间编码;
  3. 引入window attention 从头开始训练 ViT;
  4. ViT之后,引入2层MLP再传到LLM(多尺寸输入,动态压缩,而不是直接ViT输入!);

  5. 我顺便讲一下ViT编码部分:
    在这里插入图片描述
    以上图像来自 Qwen2.5-VL官方论文,链接地址:https://arxiv.org/abs/2502.13923

    这里说明下,Qwen2.5-VL 的ViT 编码需要统一尺寸为28的倍数,其pacth size 是14,stride是14,所以一张图的长宽都除以28,之后相乘就是tokens的数目! 而视频的采样,是在图像的基础上加上三组不同的帧率采样得到三种倍数增长的tokens。这会直接影响 Image Caption 速度,不管你用的是哪个模型,因为Qwen2.5-VL系列都用同一个ViT
    在这里插入图片描述
以上图像来自Qwen2.5-VL官方论文,链接地址:https://arxiv.org/abs/2502.13923

尽管Qwen2.5-VL是支持动态的分辨率输入,但是越大的图,Tokens越多,其次,可以顺便resize为28的倍数。因此我的推理加速策略,选取最大的图像分辨率,并且保持比例resize为28的倍数。
我的最大分辨率设置为1260,其中处理过程代码如下:
├── utils/
│ ├── resize_base64.py
├── main.py
resize_base64.py 代码:

import cv2
import base64
def resize_to_multiples_of_28_and_get_base64(image_path):
    # 读取图片
    if isinstance(image_path, str):
        # 如果输入是文件路径
        img = cv2.imread(image_path)
    else:
        # 如果输入是numpy数组
        img = image_path

    if img is None:
        return "无法读取图片"

    # 获取原始图片尺寸
    height, width = img.shape[:2]

    # 设置最大尺寸
    max_dimension = 1260

    # 保持原始比例进行缩放
    if width > max_dimension or height > max_dimension:
        # 确定哪个维度超出了限制
        if width >= height:
            # 如果宽度是较大的维度
            new_width = max_dimension
            new_height = int(height * (max_dimension / width))
        else:
            # 如果高度是较大的维度
            new_height = max_dimension
            new_width = int(width * (max_dimension / height))
    else:
        # 如果两个维度都没有超过最大值,保持原始尺寸
        new_width = width
        new_height = height

    # 调整为28的倍数
    new_width = new_width - (new_width % 28) if new_width % 28 != 0 else new_width
    new_height = new_height - (new_height % 28) if new_height % 28 != 0 else new_height

    # 确保尺寸至少为28x28
    new_width = max(28, new_width)
    new_height = max(28, new_height)

    # 调整图片大小
    resized_img = cv2.resize(img, (new_width, new_height))
    print(new_width, new_height)
    # 转换为base64
    _, buffer = cv2.imencode('.png', resized_img)
    encoded_image = base64.b64encode(buffer)
    encoded_image_text = encoded_image.decode("utf-8")
    return f"data:image;base64,{encoded_image_text}"

main.py 代码:

from openai import OpenAI
from utils.resize_base64 import resize_to_multiples_of_28_and_get_base64
import time
import  cv2
openai_api_key = "EMPTY"
openai_api_base = "http://ip addr:port/v1/" # vllm 
client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)
t0 = time.time()
image_path = r"./995.jpg"
print(cv2.imread(image_path).shape)
base64_qwen = resize_to_multiples_of_28_and_get_base64(image_path)


chat_response = client.chat.completions.create(
    model="Qwen/Qwen2.5-VL-7B-Instruct",
    messages=[
        {
    
    "role": "system", "content": "You are a helpful assistant."},
        {
    
    
            "role": "user",
            "content": [
                {
    
    
                    "type": "image_url",
                    "image_url": {
    
    
                        "url": base64_qwen
                    },
                },
                {
    
    "type": "text", "text": "简要地描述这张图?"},
            ],
        },
    ],
)
print("Chat response:", chat_response)
content = chat_response.choices[0].message.content
print(content)
print(time.time()-t0)

一张分辨率为6000*8000的图,在没有经过resize时, Qwen/Qwen2.5-VL-7B-Instruct 识别需要8.56秒
在这里插入图片描述
同一张图,而经过resize 处理后的图分辨率是840 *1260,Qwen/Qwen2.5-VL-7B-Instruct 识别时间是1.98秒
在这里插入图片描述
经过resize 到范围内的图,明显可以提高Image Caption 的速度!

四、Dify OpenAI-API-compatible上调用vLLM的Qwen2.5-VL 系列

在0.14.0 版本的Dify上暂时还没有支持vLLM 的插件,而在1.1.3版本的Dify上 vLLM插件不能正常调用模型。怎么办,非常简单,Dify 上的OpenAI-API-compatible完全支持调用vLLM,换句话说,vLLM可以按照OpenAI 那套交互协议来调用API。
在这里插入图片描述
当然啦,要在下面选择支持vision:
在这里插入图片描述
最后,Dify 的工作流很快就能实现了:
在这里插入图片描述

五、社区版Dify的LLM推理平台选哪个?

我之前的文章发布了Dify 的LLM推理平台都是Ollama,这里主要介绍了vLLM,该如何做选择?这里给你提供参考:

  • vLLM:
    依赖NVIDIA GPU,显存占用较高,支持动态批处理和千级并发请求,适合处理大规模推理任务。显存占用固定,需为峰值负载预留资源,适合高并发、低延迟的企业级应用场景。
  • Ollama:优化了单次推理速度,但并发处理能力有限,能动态调整资源占用,空闲时释放显存,适合个人开发者和小规模实验场景的本地化。

如本文内容对你有帮助,请点赞支持原创,欢迎留言和私信讨论。