vLLM实战部署embedding、reranker、senseVoice模型(上)

概述

一个开源的支持高并发的高性能大模型推理引擎。在这篇博客有简单提到过。

学习资料:官方文档官方中文文档中文文档

modelscope

通过vLLM(或其他平台、框架)部署模型前,需要先下载模型。国内一般使用魔搭社区,模型库里搜索想要下载的模型。输入qwen3会看到很多个候选项,主要是:

  • 参数量不一致;
  • 量化版本不一致;
  • 提交者不一致。

总之,找到模型下载路径(/Qwen/Qwen3-30B-A3B)是需要花点时间的。

下载模型有多种方式:

  • 通过浏览器下载:打开魔搭页面,默认下载到C:\Users\johnny\Downloads目录下。模型文件通常非常大,如Qwen3-30B-A3B-FP8,分割为7个文件共30+G。Chrome下载效果如下,不便之处在于文件名可辨识度非常低,最后极有可能不知道下载下来的是哪个模型的子文件。而且这么做,也不太专业。
    在这里插入图片描述
  • 通过命令行下载:在有Python和pip的环境下,pip install modelscope安装modelscope。使用modelscope命令行下载,如下载reranker模型:modelscope download --model BAAI/bge-reranker-v2-m3 --local_dir /home/models/BAAI/bge-reranker-v2-m3
  • 通过客户端下载:vim ms_download.py,填入如下内容
from modelscope import snapshot_download
import os

os.environ['HTTP_PROXY'] = 'http://192.168.4.123:7890'
os.environ['HTTPS_PROXY'] = 'http://192.168.4.123:7890'

model_dir = snapshot_download('JunHowie/Qwen3-30B-A3B-GPTQ-Int8')

embedding

使用BAAI提供的模型,docker启动命令(一行):

docker run --name=embedding --volume /home/models:/home/models --network=host --workdir=/ --restart=unless-stopped --runtime=nvidia --detach=true docker.1ms.run/dustynv/vllm:0.7.4-r36.4.0-cu128-24.04  python3 -m vllm.entrypoints.openai.api_server --served-model-name BAAI/bge-m3 --task embedding --enable-prefix-caching   --model /home/models/BAAI/bge-m3 --host 0.0.0.0 --port 8001 --trust-remote-code

docker logs -f <container_id>查看日志:
在这里插入图片描述
实际上,上述截图还省略掉不少有价值的日志:

  • embedding模型只花费2.38s就成功加载权重值,只使用1G内存(显存),这也是被称为小模型的原因,下面的reranker和语音模型也是如此;
  • 暴露的端点,即Endpoint,或routes,有很多,不一一列举;
  • 端口是8001;本地访问使用http://0.0.0.0:8001/http://localhost:8001,同一个局域网访问需要使用固定IP形式:http://192.168.4.134:8001/openapi.json
  • 192.168.4.123:63143是什么?

curl请求截图:
在这里插入图片描述
在这里插入图片描述
postman请求接口如下:
在这里插入图片描述
一行命令的可视化效果可能不太好,docker启动命令(多行):

docker run -it \
--name=embedding \
--volume /home/models:/home/models \
--network=host \
--workdir=/ \
--restart=unless-stopped \
--runtime=nvidia \
--detach=true \
dustynv/vllm:0.7.4-r36.4.0-cu128-24.04 \
python3 -m vllm.entrypoints.openai.api_server \
--served-model-name BAAI/bge-m3 \
--task embedding \
--enable-prefix-caching \
--model /home/models/BAAI/bge-m3 \
--host 0.0.0.0 \
--port 8001 \
--trust-remote-code

测试

使用postman简单测试,POST请求,requestBody如下:

{
    "model":"BAAI/bge-m3",
    "input":"智能家居系统如何帮助提高家庭能源效率?"
}

执行效果如下:
在这里插入图片描述
使用更加专业的py脚本来执行测试:

import requests
import concurrent.futures

BASE_URL = "http://192.168.4.134:30011"
MODEL = "BAAI/bge-m3"

def create_request_body():
	return {
		"model": MODEL,
		"input": "智能家居系统如何帮助提高家庭能源效率?"
	}

def make_request(request_body):
	headers = {
		"Content-Type": "application/json"
	}
	response = requests.post(f"{BASE_URL}/v1/embeddings", json=request_body, headers=headers, verify=False)
	return response.json()

def parallel_requests(num_requests):
	request_body = create_request_body()
	with concurrent.futures.ThreadPoolExecutor(max_workers=num_requests) as executor:
		futures = [executor.submit(make_request, request_body) for _ in range(num_requests)]
		results = [future.result() for future in concurrent.futures.as_completed(futures)]
	return results

if __name__ == "__main__":
	num_requests = 50  # Example: Set the number of parallel requests
	responses = parallel_requests(num_requests)
	for i, response in enumerate(responses):
		print(f"Response {i+1}: {response}")

k8s

上面是使用docker方式启动模型,--restart=unless-stopped参数可以实现自动重启,但是重启(包括探针)机制不如k8s。

将上面的启动脚本扔给GPT,再经过调整,不难得到一个符合k8s或k3s的yaml文件:

# embedding-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-embedding
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm-embedding
  template:
    metadata:
      labels:
        app: vllm-embedding
    spec:
      nodeSelector:
        kubernetes.io/hostname: k3s-master-2
      runtimeClassName: nvidia  # 需提前配置GPU运行时
      containers:
        - name: vllm-embedding
          image: dustynv/vllm:0.7.4-r36.4.0-cu128-24.04
          command: ["python3"]
          args:
            - "-m"
            - "vllm.entrypoints.openai.api_server"
            - "--served-model-name"
            - "BAAI/bge-m3"
            - "--task"
            - "embedding"  # 关键参数:指定任务类型
            - "--enable-prefix-caching"
            - "--model"
            - "/home/models/BAAI/bge-m3"
            - "--host"
            - "0.0.0.0"
            - "--port"
            - "8011"
            - "--trust-remote-code"
          volumeMounts:
            - name: model-storage
              mountPath: /home/models
          startupProbe:
            httpGet:
              path: /health
              port: 8011
            initialDelaySeconds: 120
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health
              port: 8011
            initialDelaySeconds: 90
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health
              port: 8011
            initialDelaySeconds: 90
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 1
      volumes:
        - name: model-storage
          hostPath:
            path: /home/models  # 主机模型存储路径
---
# embedding-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: vllm-embedding-service
spec:
  selector:
    app: vllm-embedding
  ports:
    - protocol: TCP
      port: 8011      # 集群内部访问端口
      targetPort: 8011  # 容器端口
      nodePort: 30011
  type: NodePort      # 外部访问方式

reranker

与embedding经常一起出现的就是重排序,即reranker小模型。魔搭社区地址,一般用BAAI/bge-reranker-v2-m3

直接给出docker启动模型命令:

docker run -it --name=rerank --volume /home/models:/home/models --network=host --workdir=/ --restart=unless-stopped --runtime=nvidia --detach=true dustynv/vllm:0.7.4-r36.4.0-cu128-24.04  python3 -m vllm.entrypoints.openai.api_server --served-model-name BAAI/bge-reranker-v2-m3 --enable-prefix-caching --model /home/models/BAAI/bge-reranker-v2-m3 --host 0.0.0.0 --port 8002  --trust-remote-code

转化为k3s或k8s的yaml文件也很简单,将上面的embedding模型的yaml文件稍加改动即可。

语音

此处的语言模型指的是ASR模型,参考语音转文本ASR、文本转语音TTS

魔搭社区地址为iic/SenseVoiceSmall。启动SenseVoiceSmall模型的镜像不是vLLM,需要自己构建Docker镜像。如果转换为k3s yaml文件,则还需要将Docker镜像转化成crictl镜像。具体参考docker、ctr、crictl命令简介与使用

使用开源代码仓库,Fork到公司内部代码仓库地址,调整一些配置,维护自己的Dockerfile,即可自主构建Docker镜像。

比如准备好如下Docker镜像:
在这里插入图片描述
对于语言模型,其yaml文件也非常简单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sense-voice
  labels:
    app: sense-voice
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sense-voice
  template:
    metadata:
      labels:
        app: sense-voice
    spec:
      containers:
      - name: sense-voice
        image: harbor.tesla.com/agent/sense-voice-api:arm64-9a358d5f-2025-05-07-18-46-55
        imagePullPolicy: IfNotPresent
        env:
        - name: model_path
          value: "/mnt/models/BAAI/SenseVoiceSmall"
        volumeMounts:
        - name: model-storage
          mountPath: /mnt/models
        startupProbe:
            httpGet:
              path: /health
              port: 8003
            initialDelaySeconds: 120
            periodSeconds: 10
            failureThreshold: 3
        livenessProbe:
          httpGet:
            path: /health
            port: 8003
          initialDelaySeconds: 90
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health
            port: 8003
          initialDelaySeconds: 90
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 1
        resources:
          limits:
            cpu: "2"
            memory: "4Gi"
          requests:
            cpu: "1"
            memory: "2Gi"
      volumes:
      - name: model-storage
        hostPath:
          path: /mnt/models
---
apiVersion: v1
kind: Service
metadata:
  name: sense-voice-service
spec:
  selector:
    app: sense-voice
  ports:
    - protocol: TCP
      port: 8003        # 服务端口
      targetPort: 8003  # 容器端口
      nodePort: 30003
  type: NodePort        # 暴露为NodePort便于外部访问

如果使用k3s部署yaml文件,由于k3s使用的是crictl镜像,k3s会在启动模型时将Docker镜像转换成crictl镜像:
在这里插入图片描述
如上图所示,两个镜像其ID是一样的,但crictl镜像更轻量级一些。

vLLM模型部署,下篇

### 替换 Qwen2.5VL 模型中的 Embedding 层 对于希望替换 Qwen2.5VL 大模型Embedding 层的需求,操作涉及对现有模型架构的理解以及 PyTorch 或其他框架的具体实现方法。通常情况下,在基于 Transformer 的预训练模型中修改特定组件如 Embedding 需要遵循一定的流程。 #### 加载原始模型并定义新嵌入层 首先加载现有的 Qwen2.5VL 模型实例,并创建一个新的自定义 Embedding 层来替代原有的部分: ```python from transformers import AutoModelForCausalLM, AutoConfig config = AutoConfig.from_pretrained("Qwen/Qwen-2.5VL") # 获取配置文件 model = AutoModelForCausalLM.from_config(config) new_embedding_layer = torch.nn.Embedding( num_embeddings=custom_vocab_size, embedding_dim=config.hidden_size ).to(model.device) ``` 此处 `custom_vocab_size` 应该被设置为你想要的新词汇表大小[^1]。 #### 更新模型结构 接着将新的 Embedding 层集成到原模型内部,这一步骤可能因具体库版本而异,但对于大多数情况而言可以这样做: ```python # 假设 'transformer.wte' 是目标位置的名字空间 original_wte_name = "transformer.wte" setattr(model.transformer, original_wte_name, new_embedding_layer) # 如果还需要更新 token embeddings mapping,则执行如下命令 if hasattr(model.lm_head.decoder, 'weight'): model.lm_head.decoder.weight = new_embedding_layer.weight else: model.set_input_embeddings(new_embedding_layer) ``` 这段代码会把之前准备好的 `new_embedding_layer` 插入到指定的位置(`transformer.wte`),并且同步更改解码器权重以便保持一致性[^3]。 #### 测试与验证 完成上述改动之后非常重要的一环是对整个过程进行充分测试以确认一切正常工作。可以通过简单的前向传播检查输出形状是否符合预期;也可以利用一些已知输入样本来对比改造前后结果差异。 ```python test_input_ids = ... # 准备用于测试的数据集样本 ID 列表 output_before_modification = model(test_input_ids)[0].detach().cpu() output_after_modification = modified_model(test_input_ids)[0].detach().cpu() print(f"Output shapes match? {output_before_modification.shape == output_after_modification.shape}") ``` 以上就是关于如何在 Qwen2.5VL 中替换 Embedding 层的一个基本指导方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

johnny233

晚饭能不能加鸡腿就靠你了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值