一、前置准备工作
1、首先是下载vllm的镜像文件,这不用赘述。
下载完后使用docker image查看镜像的名称备用。
2、下载MiniCPM-o-2_6模型文件。
方法1、SDK下载
#模型下载 from modelscope import snapshot_download model_dir = snapshot_download('OpenBMB/MiniCPM-o-2_6')
方法2、Git下载
请确保 lfs 已经被正确安装 否则无法下载safetensor
git lfs install
git clone https://www.modelscope.cn/OpenBMB/MiniCPM-o-2_6.git
二、进入模型文件文件夹,创建docker-compose.yaml文件
在tesla t4 4张卡上的docker-compose.yaml文件
services:
MiniCPM-o-2_6:
image: 10.75.240.230/vllm/vllm-openai:v0.8.5# 替换为实际的镜像名称
container_name: MiniCPM-o-2_6
restart: always
shm_size: 10.24g
environment:
- CUDA_VISIBLE_DEVICES=12,13,14,15
- TZ=Asia/Shanghai
- PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
volumes:
- /data/models/MiniCPM-o-2_6:/models # 替换为实际的宿主机路径
command: >
--model /models
--served-model-name MiniCPM-o-2_6
--tensor-parallel-size 4
--dtype half
--port 8000
--gpu_memory_utilization 1
--max-model-len=4096
--trust-remote-code
ports:
- "8080:8000"# 替换为实际的端口
附可供参考:在A10卡上测试代码
services:
MiniCPM-o-2_6:
image: 10.75.240.230/vllm/vllm-openai:v0.8.5
container_name: MiniCPM-o-2_6
restart: always
environment:
- CUDA_VISIBLE_DEVICES=0
- TZ=Asia/Shanghai
- PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
volumes:
- /data/MiniCPM-o-2_6:/models # 替换为实际的宿主机路径
command: >
--model /models
--served-model-name MiniCPM-o-2_6
--tensor-parallel-size 1
--dtype auto
--port 8000
--gpu_memory_utilization 1
--max-model-len=4096
--trust-remote-code
ports:
- "8080:8000"
显卡情况如下:
三、运行,查看容器日志,部署成功
docker compose up -d
四、测试代码:
- 图片测试代码:
import base64
import requests
import os
model_url = "http://10.75.0.51:8080/v1/chat/completions"
script_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(script_dir, 'data', 'image.jpg')
try:
with open(file_path, 'rb') as file:
image_base64 = base64.b64encode(file.read()).decode('utf-8')
except FileNotFoundError:
print(f"文件 {file_path} 未找到,请检查文件路径。")
else:
# 构建符合规范的请求体
data = {
"model": "MiniCPM-o-2_6",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "请描述这张图片"
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_base64}"
}
}
]
}
]
}
headers = {
"Content-Type": "application/json"
}
try:
response = requests.post(model_url, json=data, headers=headers)
response.raise_for_status()
chat_response = response.json()
print("Chat response:", chat_response)
print("Chat response content:", chat_response["choices"][0]["message"]["content"])
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
# 打印服务器返回的详细错误信息
if response.text:
print("服务器返回的错误信息:", response.text)
except (KeyError, IndexError):
print("无法解析响应内容。")
- 音频测试代码:
import base64
import requests
import os
# 服务器接口地址
model_url = "http://10.75.0.51:8080/v1/chat/completions"
# 获取脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))
# 构建音频文件的完整路径
file_path = os.path.join(script_dir, 'data', 'audio.mp3')
try:
# 以二进制模式打开音频文件
with open(file_path, 'rb') as audio_file:
# 对音频文件内容进行 Base64 编码并转换为字符串
audio_base64 = base64.b64encode(audio_file.read()).decode('utf-8')
except FileNotFoundError:
print(f"文件 {file_path} 未找到,请检查文件路径。")
else:
# 构建符合规范的请求体
data = {
"model": "MiniCPM-o-2_6",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "请描述这个音频,用中文回答"
},
{
"type": "audio_url",
"audio_url": {
"url": f"data:audio/mpeg;base64,{audio_base64}"
}
}
]
}
]
}
# 设置请求头,指定内容类型为 JSON
headers = {
"Content-Type": "application/json"
}
try:
# 发送 POST 请求到服务器
response = requests.post(model_url, json=data, headers=headers)
# 检查请求是否成功,如果不成功则抛出异常
response.raise_for_status()
# 将响应内容解析为 JSON 格式
chat_response = response.json()
print("Chat response:", chat_response)
print("Chat response content:", chat_response["choices"][0]["message"]["content"])
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
# 打印服务器返回的详细错误信息
if response.text:
print("服务器返回的错误信息:", response.text)
except (KeyError, IndexError):
print("无法解析响应内容。")
- 视频测试代码:
import base64
import requests
import os
# 服务器接口地址
model_url = "http://10.75.0.51:8080/v1/chat/completions"
# 获取脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))
# 构建视频文件的完整路径
file_path = os.path.join(script_dir, 'data', '视频2.mp4')
try:
# 以二进制模式打开视频文件
with open(file_path, 'rb') as video_file:
# 对视频文件内容进行 Base64 编码并转换为字符串
video_base64 = base64.b64encode(video_file.read()).decode('utf-8')
except FileNotFoundError:
print(f"文件 {file_path} 未找到,请检查文件路径。")
else:
# 构建符合规范的请求体
data = {
"model": "MiniCPM-o-2_6",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "请描述这个视频"
},
{
"type": "video_url",
"video_url": {
"url": f"data:video/mp4;base64,{video_base64}"
}
}
]
}
]
}
# 设置请求头,指定内容类型为 JSON
headers = {
"Content-Type": "application/json"
}
try:
# 发送 POST 请求到服务器
response = requests.post(model_url, json=data, headers=headers)
# 检查请求是否成功,如果不成功则抛出异常
response.raise_for_status()
# 将响应内容解析为 JSON 格式
chat_response = response.json()
print("Chat response:", chat_response)
print("Chat response content:", chat_response["choices"][0]["message"]["content"])
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
# 打印服务器返回的详细错误信息
if response.text:
print("服务器返回的错误信息:", response.text)
except (KeyError, IndexError):
print("无法解析响应内容。")
五、yaml文件解释
整体结构
services
是 Docker Compose 中用于定义多个服务的顶级关键字。
这里定义了一个名为 MiniCPM-o-2_6
的服务。
服务配置项解释
- 服务名称
MiniCPM-o-2_6:
这是服务的名称,用于在 Docker Compose 中唯一标识该服务。
- 镜像配置
image: 10.75.240.230/vllm/vllm-openai:v0.8.5
指定了要使用的 Docker 镜像。这里的镜像存储在私有镜像仓库 10.75.240.230
中,镜像名称为 vllm/vllm-openai
,版本标签是 v0.8.5
。你需要将其替换为实际的镜像名称。
- 容器名称
container_name: MiniCPM-o-2_6
为该服务创建的 Docker 容器指定一个名称。
- 重启策略
restart: always
设置容器的重启策略为 always
,意味着无论容器因何原因停止,Docker 都会自动重启它。
- 共享内存大小
shm_size: 10.24g
为容器分配的共享内存大小为 10.24GB。共享内存用于容器内进程间的通信。
- 环境变量配置
environment:
- CUDA_VISIBLE_DEVICES=12,13,14,15
- TZ=Asia/Shanghai
- PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
CUDA_VISIBLE_DEVICES=12,13,14,15
:指定容器内可见的 NVIDIA GPU 设备编号,即容器只能使用编号为 12、13、14、15 的 GPU。TZ=Asia/Shanghai
:设置容器内的时区为亚洲 / 上海。PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
:配置 PyTorch 的 CUDA 内存分配策略,允许 CUDA 内存段可扩展。
- 数据卷挂载
volumes:
- /data/models/MiniCPM-o-2_6:/models
将宿主机的 /data/models/MiniCPM-o-2_6
目录挂载到容器内的 /models
目录。你需要将宿主机路径替换为实际的路径。
- 容器启动命令
command: >
--model /models
--served-model-name MiniCPM-o-2_6
--tensor-parallel-size 4
--dtype half
--port 8000
--gpu_memory_utilization 1
--max-model-len=4096
--trust-remote-code
这是容器启动时执行的命令。具体参数含义如下:
--model /models
:指定模型的路径为容器内的/models
目录。--served-model-name MiniCPM-o-2_6
:指定服务的模型名称为MiniCPM-o-2_6
。--tensor-parallel-size 4
:设置张量并行的大小为 4,通常用于分布式训练或推理。--dtype half
:指定模型使用半精度浮点数(FP16)进行计算。--port 8000
:指定服务监听的端口为 8000。--gpu_memory_utilization 1
:设置 GPU 内存利用率为 100%。--max-model-len=4096
:指定模型的最大长度为 4096。--trust-remote-code
:允许使用远程代码。
- 端口映射
ports:
- "8080:8000"
将宿主机的 8080 端口映射到容器内的 8000 端口。这意味着可以通过访问宿主机的 8080 端口来访问容器内服务监听的 8000 端口。你需要将端口替换为实际的端口。
综上所述,这个 Docker Compose 服务配置文件的作用是启动一个基于特定镜像的 Docker 容器,配置容器的环境和资源,挂载数据卷,并运行一个模型服务,同时将服务端口映射到宿主机上。
遇到的坑:
问题1:如果遇到请求出错: 500 Server Error,服务器返回的错误信息: Internal Server Error
去查看容器日志问题:ImportError: Please install vllm[audio] for audio support
解决:在容器内去下载vllm[audio]、vllm[video]
docker exec -it MiniCPM-o-2_6 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple vllm[audio]
docker exec -it MiniCPM-o-2_6 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple vllm[video]
这两个都要安!!安了然后restart docker 容器 注意是restart!!当然如果你想新起一个容器配置好也是可以的。
问题2:Bfloat16 is only supported on GPUs with compute capability of at least 8.0. Your Tesla T4 GPU has compute capability 7.5. You can use float16 instead by explicitly setting the `dtype` flag in CLI, for example: --dtype=half.
解决:这表明你正在使用的 Tesla T4 GPU 的计算能力为 7.5,而 Bfloat16 数据类型仅支持计算能力至少为 8.0 的 GPU。当前的配置中使用了 Bfloat16 数据类型,导致程序无法正常初始化并报错。解决这个问题的方法正如错误信息中所提示的,需要在命令行中显式地设置 dtype 标志为 float16(half)。在你的 docker-compose.yml 文件中,你可以修改 command 字段来实现这一点。如果是其他的卡,例如A10没遇到这个问题可以设置为auto。