Qwen3-30B-A3B部署(使用vllm和sglang)

Qwen3-30B-A3B部署(使用vllm和sglang)

  • 模型:Qwen3-30B-A3B

  • 显卡:4090 4 张

  • python版本

    python 3.12

  • 重要包的版本

    vllm==0.8.6
    sglang== 0.4.6.post1
    
  • 阿里云Qwen发布的微信公众号链接

    https://mp.weixin.qq.com/s/UZE5T7iyFqbXS05ReouOzw


安装

模型下载

  • 使用modelscope下载,需要安装modelscope库

    pip install modelscope
    

    已经有modelscope库的需要升级下面的几个包

    pip install --upgrade modelscope -i https://pypi.tuna.tsinghua.edu.cn/simple
    
    pip install --upgrade transformers -i https://pypi.tuna.tsinghua.edu.cn/simple
    pip install --upgrade peft -i https://pypi.tuna.tsinghua.edu.cn/simple
    pip install --upgrade diffusers -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  • 下载

    默认下载在当前用户的.cache文件夹下,比如现在是root用户,则默认在

    /root/.cache/modelscope/hub/models/Qwen/Qwen3-30B-A3B

    我们希望将其下载在

    /root/Qwen/Qwen3-30B-A3B

    from modelscope.hub.snapshot_download import snapshot_download
    
    model_name = "Qwen/Qwen3-30B-A3B"
    
    cache_dir = "/root"  # 替换为你希望的路径
    
    snapshot_download(model_name, cache_dir=cache_dir)
    
    

    image-20250430150442295

  • 下载完成后查看下

    ls -lha /root/Qwen/Qwen3-30B-A3B 
    

    image-20250430150545614

  • 按照官方提供的测试代码就是如下的,不过我们后续使用vllm和sglan启动

    from modelscope import AutoModelForCausalLM, AutoTokenizer
    import time
    
    model_name = "/root/Qwen/Qwen3-30B-A3B" 
    cache_dir = '/root'
    
    tokenizer = AutoTokenizer.from_pretrained(model_name,local_files_only=True)
    
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        torch_dtype="auto",
        device_map="auto",
        low_cpu_mem_usage=True,
        local_files_only=True
    )
    
    
    prompt = "介绍下你自己."
    messages = [
        {"role": "user", "content": prompt}
    ]
    
    text = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
        enable_thinking=True # Switch between thinking an non-thinking modes, Default is True
    )
    
    model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
    # conduct text completion
    start_time = time.time()
    generated_ids = model.generate(
        **model_inputs,
        max_new_tokens=32768
    )
    end_time = time.time() - start_time()
    output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()
    # parsing thinking content
    try:
        # rindex finding 151668</think>
        index = len(output_ids) -output_ids[::-1].index(151668)
    except ValueError:
        index=0
    
    thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
    content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")
    print("thinking content:", thinking_content)
    print("content:", content)
    

环境安装

  • 使用conda创建虚拟环境

    conda create -n sglang python=3.12
    
    conda activate sglang
    
  • 下载vllm(指定清华源,否则极慢)

    pip install vllm -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  • 下载sglang

    pip install sglang -i https://pypi.tuna.tsinghua.edu.cn/simple
    pip install sgl_kernel -i https://pypi.tuna.tsinghua.edu.cn/simple
    
  • 后续使用中一些其他报错需要装的包

    pip install orjson
    pip install torchao
    

vllm启动

  • vllm启动命令

    CUDA_VISIBLE_DEVICES=0,1,2,3 \
    vllm serve /root/Qwen/Qwen3-30B-A3B \
      --tensor-parallel-size 4 \
      --max-model-len 32768 \
      --gpu-memory-utilization 0.8 \
      --host 0.0.0.0 \
      --port 8081 \
      //--enable-reasoning --reasoning-parser deepseek_r1 \
      --served-model-name Qwen3-30B-A3B-vllm
    

    以下是对VLLM启动命令参数的简要说明

    参数简要说明
    CUDA_VISIBLE_DEVICES=0,1,2,3指定要使用的GPU设备编号,这里选择使用0、1、2、3四个GPU设备
    vllm serve /root/Qwen/Qwen3-30B-A3B启动VLLM服务、指定模型路径
    --tensor-parallel-size张量并行大小
    --max-model-le模型处理的最大序列长度
    --gpu-memory-utilization预分配的GPU内存比例 (vllm默认为0.9)
    --host设置服务监听的主机地址,0.0.0.0表示监听所有网络接口
    --port设置服务监听的端口号
    --enable-reasoning启用推理功能(think)
    --reasoning-parser指定推理解析器
    --served-model-nam设置模型名
  • 以8081端口启动成功

    image-20250430160957293

  • 显存占用情况

    image-20250430161014493

  • 测试

    测试代码

    from openai import OpenAI
    import openai
    
    openai.api_key = '1111111' # 这里随便填一个
    openai.base_url = 'http://127.0.0.1:8081/v1'
    
    
    def get_completion(prompt, model="QwQ-32B"):
        client = OpenAI(api_key=openai.api_key,
                        base_url=openai.base_url
                        )
        messages = [{"role": "user", "content": prompt}]
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            stream=False
        )
        return response.choices[0].message.content
    	
    prompt = '请计算straberry这个单词中字母r的出现次数'
    
    response = get_completion(prompt, 
                              model="Qwen3-30B-A3B-vllm"
    			              )
    print(response)
    
    

    image-20250430161750885

    能到 100tokens/s

    image-20250430162439992


sglang启动

  • sglang启动命令

    CUDA_VISIBLE_DEVICES=0,1,2,3 python -m sglang.launch_server \
      --model-path /root/Qwen/Qwen3-30B-A3B \
      --tp 4 \
      --max-prefill-tokens 32768 \
      --mem-fraction-static 0.8 \
      --host 0.0.0.0 \
      --port 8081 \
      --served-model-name Qwen3-30B-A3B
    
    

    参数说明:

    参数简要说明
    CUDA_VISIBLE_DEVICES=0,1,2,3指定要使用的GPU设备编号,这里选择使用0、1、2、3四个GPU设备
    python -m sglang.launch_server启动SGLang服务的主命令
    --model-path 指定模型权重的路径
    可以是本地文件夹或Hugging Face仓库ID
    --tp 张量并行大小
    --max-prefill-tokens最大token长度
    --mem-fraction-staticGPU内存使用比例
    --hos设置服务监听的主机地址,0.0.0.0表示监听所有网络接口
    --port 8081设置服务监听的端口号
    --served-model-name模型名称(在API响应中使用)
  • 以8081端口启动成功

    image-20250430154300449

  • 测试代码

    from openai import OpenAI
    import openai
    
    openai.api_key = '1111111' # 这里随便填一个
    openai.base_url = 'http://127.0.0.1:8081/v1'
    
    
    def get_completion(prompt, model="QwQ-32B"):
        client = OpenAI(api_key=openai.api_key,
                        base_url=openai.base_url
                        )
        messages = [{"role": "user", "content": prompt}]
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            stream=False
        )
        return response.choices[0].message.content
    	
    prompt = '请计算straberry这个单词中字母r的出现次数'
    
    response = get_completion(prompt, 
                              model="Qwen3-30B-A3B"
    			              )
    print(response)
    
    

    image-20250430154345491

  • 显存占用情况

    image-20250430223528716

  • 平均可以达到160 tokens /s

    image-20250430154411495


modelscope压测

压测结果

  • modelscope压测的方法可以看之前的博客

    https://blog.csdn.net/hbkybkzw/article/details/147641988

  • GPU机器4卡4090,在自己电脑使用modelscope分别对vllm和sglang进行以下并发数的压测,都统一用的开放数据集

    并发数列表

    parallel_list = [1,5,10,20,30,40,50]
    
  • vllm压测代码(使用---.--.--.---隐藏了GPU机器的ip )

    from evalscope.perf.main import run_perf_benchmark
    
    
    def run_perf(parallel,model_name):
        task_cfg = {
            'url': 'http://---.--.--.---:8081/v1/chat/completions',
            'parallel': parallel,
            'model': model_name,
            'number': 100,
            'api': 'openai',
            'dataset': 'openqa',
            'stream': True,
            'debug': False,
        }
        run_perf_benchmark(task_cfg)
    
    model_name = 'Qwen3-30B-A3B-vllm' # vllm启动时设置的model_name
    parallel_list = [1,5,10,20,30,40,50]
    
    if __name__ == '__main__':
        for parallel in parallel_list:
            run_perf(parallel,model_name)
    
    
    
  • sglang压测代码(使用---.--.--.---隐藏了GPU机器的ip )

    from evalscope.perf.main import run_perf_benchmark
    
    
    def run_perf(parallel,model_name):
        task_cfg = {
            'url': 'http://---.--.--.---:8081/v1/chat/completions',
            'parallel': parallel,
            'model': model_name,
            'number': 100,
            'api': 'openai',
            'dataset': 'openqa',
    	'stream': True,
            'debug': False,
        }
        run_perf_benchmark(task_cfg)
    
    model_name = 'Qwen3-30B-A3B' # sglang启动时设置的model_name
    parallel_list = [1,5,10,20,30,40,50]
    
    if __name__ == '__main__':
        for parallel in parallel_list:
            run_perf(parallel,model_name)
    
    
  • 整理了下压测结果如下

    推理引擎并发数总请求数成功数失败数总时长每秒输出tokens每秒总tokensqps平均用时平均首帧用时生成每个token的平均时间平均输入token长度平均输出token长度
    vllm110010001120.52110.20112.780.0911.200.150.0128.891234.81
    sglang11001000753.52162.47166.300.137.530.190.0128.891224.24
    vllm51001000375.81323.67331.350.2718.570.170.0228.891216.38
    sglang51001000306.32402.64412.070.3315.150.230.0128.891233.38
    vllm101001000282.89428.24438.460.3527.690.180.0228.891211.45
    sglang101001000234.75509.23521.540.4323.030.220.0228.891195.40
    vllm201001000189.23654.34669.610.5335.920.230.0328.891238.22
    sglang201001000159.30755.89774.020.6330.050.260.0228.891204.13
    vllm301001000145.56843.25863.100.6938.700.250.0328.891227.45
    sglang301001000133.24926.01947.690.7535.780.260.0328.891233.78
    vllm401001000132.34924.52946.350.7645.430.290.0428.891223.48
    sglang401001000122.121002.871026.520.8241.820.410.0328.891224.73
    vllm501001000133.63917.30938.920.7555.640.330.0528.891225.82
    sglang501001000119.471014.741038.920.8450.430.290.0428.891212.29

压测结果可视化

  • 每秒输出tokens对比

    image-20250502000343020

  • QPS对比

    image-20250502000408051

  • 平均用时对比

    image-20250502000428280

  • 首帧用时对比

    image-20250502000627462


压测结果分析

  • 针对vllm和sglang两种推理引擎在不同并发数下的性能进行了分析。

    1. 吞吐量分析(每秒输出tokens)

      vllm:随着并发数从1增加到30,每秒输出tokens从110.20提升到843.25,提升了约7.7倍。当并发数达到40时,性能达到峰值924.52。当并发数增加到50时,性能略有下降至917.30。

      sglang:随着并发数从1增加到50,每秒输出tokens持续增长,从162.47提升到1014.74,提升了约6.2倍。在所有并发数下,sglang的吞吐量均高于vllm。

    2. 响应时间分析

      平均用时:两种引擎的平均用时都随着并发数增加而增加,但sglang在各个并发数下的平均用时均低于vllm。

      平均首帧用时:两种引擎的首帧用时差异不大,但随着并发数增加,首帧用时也有所增加。

    3. 性能提升百分比

      sglang相对于vllm的性能提升:

      并发数每秒输出tokens提升平均用时改善
      147.4%32.8%
      524.4%18.4%
      1018.9%16.8%
      2015.5%16.3%
      309.8%7.5%
      408.5%7.9%
      5010.6%9.4%
    4. 稳定性分析

      从数据来看,两种引擎在所有测试的并发数下(1-50)都保持了100%的成功率,没有失败请求。但从性能曲线来看:

      vllm:在并发数为40时达到性能峰值(每秒输出tokens为924.52)当并发数增加到50时,性能略有下降(每秒输出tokens为917.30,下降约0.8%)平均用时从40并发的45.43秒增加到50并发的55.64秒,增加了22.5%

      sglang:在测试范围内(1-50并发),性能一直呈上升趋势,50并发时每秒输出tokens达到1014.74,比40并发时的1002.87略有提升(约1.2%),平均用时从40并发的41.82秒增加到50并发的50.43秒,增加了20.6%

结论

  • 在4卡3090下,vllm和sglang
  1. 性能对比:在所有测试的并发数下,sglang的性能均优于vllm,无论是吞吐量还是响应时间。

  2. 稳定支持的并发数

    vllm:可以稳定支持40并发,此时性能达到峰值,超过此并发数性能开始下降。

    sglang:在测试范围内(1-50并发)都表现稳定,且性能仍有上升趋势,可以稳定支持50并发。若需确定其极限,可以进行更高并发数的测试。

  • 选择建议

    如果追求更高的吞吐量和更低的响应时间,sglang是更好的选择。

    如果系统需要支持40以上的并发,sglang的优势更为明显。

    两种引擎在低并发数(如1-10)下的性能差异更大,如果主要在低并发场景使用,sglang的优势更为突出。

  • 总体而言,sglang在各项指标上均优于vllm,特别是在高并发场景下表现更为稳定,是部署Qwen3-30B-A3B模型的更佳选择。


### 关于 Qwen2.5-VL-3B 镜像部署 对于Qwen2.5-VL-3B镜像的部署,虽然具体针对此版本的直接描述较少见,可以借鉴相似规模功能的大模型部署流程来推断其部署方式。通常情况下,大型多模态模型如Qwen系列,在不同操作系统上的部署会遵循一定的通用原则。 #### 准备工作环境 确保目标机器满足最低硬件需求,并安装必要的软件包支持库。这包括但不限于Python解释器、PyTorch框架以及其他可能被提及作为依赖项的内容[^1]。 #### 获取并加载预训练权重文件 访问官方资源仓库获取对应的预训练参数文件。例如通过Hugging Face平台下载指定版本的模型权重。注意确认所选模型确实为所需的具体变体——即Qwen2.5-VL-3B而非其他尺寸或配置版本[^2]。 #### 安装运行所需的全部依赖关系 进入项目根目录后执行命令`pip install -r requirements.txt`以安装所有必需的Python库其他工具链组件。这里假设存在一个名为requirements.txt的文本文件列出了完整的依赖列表;如果特定于Web演示,则可能是requirements_web_demo.txt这样的命名。 #### 启动服务端口监听 依据具体的API接口设计文档启动相应的HTTP/HTTPS服务器实例。如果是基于Docker容器化方案实施的话,则需编写合适的docker-compose.yml文件定义服务栈结构以及网络通信设置等细节。 ```yaml version: &#39;3&#39; services: app: image: qwen/qwen2.5-vl-3b-instruct:latest ports: - "8080:80" environment: MODEL_NAME_OR_PATH: /path/to/model/directory/ ``` 上述YAML片段展示了如何利用Docker Compose快速搭建起能够提供RESTful API调用的服务节点。当然实际操作时还需参照最新的官方指导手册调整各项参数取值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值