1. 概述
背景:主要用于图像、视频与文本的联合信息的理解场景。
本文以云产品功能、简单方案对比&售后技术排障的角度展开
2. 模型选型
Qwen2/Qwen2-VL-72B-Instruct:目标比较明确就是这个模型,需要结合阿里云的存储和异构算力在PAI上搭建该模型的推理服务。
Qwen2/Qwen2-VL-7B-Instruct:测试验证选择了模型参数量较小的7B模型,仅推理的话这里7B大概需要14G的显存,免费试用的机型ecs.gn7i-c8g1.2xlarge上配的24G显存的A10卡就可以cover。
这里采取小参数量模型的折中测试方案主要是考量到了如下几个点:
- 推理显存占用计算问题。以比较常见的推理精度,fp16来计算,显存占用大概是参数量2,72B大概140G,7B大概14G显存。这里有个比较简单的速算法供参考,大模型推理占用显存=参数量的数字(Billion为单位)* N(float32:N=4/float16:N=2/int8:N=1/int4:N=0.5),推理中显存占用较多的是模型权重,除此之外KV缓存以及激活显存的估算这里不展开细说了,用上述方式估算再留有富余的显存来估算用哪类卡,用几张是多数客户的选择。
- 硬件问题。PAI官方建议大于20B的模型走PAI灵骏智算的计算资源,主要原因是因为PAI通用计算的资源池中少有A100或H800等大显存的卡或4*以及8*多卡的机器,灵骏又因为资源紧俏需要到指定region加白才能购买。
- 方案调通后模型切换相对容易。这里涉及挂载模型文件的切换、GPU机型切换以及推理服务Device的调整。
- 挂载模型文件方面不管是本地调试的dsw还是eas都可以通过控制台或者json配置轻松的更换挂载的oss路径,通过jindo fuse映射到我们dsw或者eas的容器中用于模型参数的读取
- GPU机型可以在控制台或者eas的json配置中通过cloud.computing.instances来进行修改
- 推理服务Device调整分成多种。如果是用自定义镜像部署,那可能内含的诸如vllm等推理服务框架,可以通过调整tensor_parallel_size或pipeline-parallel-size;如果是fastapi或eas processor可能会内置transformer或者modelscope的库,也可以通过调整VISIBLE_DEVICES以及device_map的方式来使大模型不同层的参数分布到多个卡甚至多个机器上
3. 部署方案
3.1. model gallery
model gallery作为pai平台上的一个功能模块,集成丰富的预训练模型,提供一站式零代码的模型训练、评测、部署服务功能。
如下图样例,一键部署会按demo生成默认的eas json配置,我们可以看到相关的镜像,启动命令以及官方预置的模型文件,这种方式的优点很明显,如果model gallery中已经内置了需求的模型且没有对api请求的数据处理以及模型推理有个性化要求的话可以说是简单快捷。
该脚本根据model_type的取值加载不同的预训练模型,脚本中通过gradio,fastapi以及modelscope开源的ms-swift框架实现了eas服务的webui、http服务以及模型推理加速等场景。
相关框架感兴趣可以参考:
但比较遗憾的是目前Qwen2/Qwen2-VL-72B-Instruct尚未接入到gallery中来。
3.2. PAI-EAS
模型在线服务EAS(Elastic Algorithm Service)是PAI产品为实现一站式模型开发部署应用,针对在线推理场景提供的模型在线服务,支持将模型服务部署在公共资源组或专属资源组,实现基于异构硬件(CPU和GPU)的模型加载和数据请求的实时响应。
对于模型业务开发人员来说:
- 模型部署分成镜像部署以及processor部署两种。
- 镜像部署内细分普通服务和ai-web应用两种,http服务的框架可自行选择,最近比较主流的基于python的vllm,fastapi或者是java,c++的主流框架均可
- processor部署,一方面预置了常见的开源深度学习框架(如tf,pytorch等)只需提供模型文件即可,一方面eas也提供了基于c++自主开发的allspark推理框架兼容多种开发语言。根据历史case总结,对于模型规模较大的服务不建议processor部署,processor适合轻量化部署,对于vl-72B的模型,当前场景下还是建议自定义镜像方式更好。
- 推理部分。
- 基于自研blade和预置processor的推理加速
- 同、异步推理服务的支持
对于模型服务运维人员来说:
- 提供了简便快捷的白屏化调试页面与压测服务
- 非常全面的指标监控服务和基于指标或业务时间的弹性扩缩容,蓝绿部署,灰度发布切流等实用功能
基于客户对vl模型的需求场景以及多种自定义数据请求的需要,建议客户通过功能强大的EAS来部署推理服务。
3.3. PAI-DSW
写在这一章最后。
24年11月起,dsw支持自定义服务访问配置,助力测试、部署在dsw上的各类WebUI框架和应用开发框架及其开发者用于进行测试和验证。详情可参考:
通过摘要我们也可以看出,dsw的该功能定位在开发初期时开发人员之间的验证场景,dsw也不具备eas的弹性扩缩容,优雅下线,健康检查等能力。
无论是eas的自定义processor的环境搭建或者是自定义镜像服务都可以通过dsw的保存镜像功能快捷方便的环境构建或保存已经测试完备的镜像。
4. 模型文件下载与挂载
4.1. huggingface
4.1.1. 网络异常
由于众所周知的原因,如下的报错会是常态,即使是在公司办公网的加持下,通过git或者python的sdk下载也会有相关的问题:
OSError: We couldn't connect to 'https://huggingface.co' to load this file, couldn't find it in the cached files and it looks like Qwen/Qwen2-VL-72B-Instruct is not the path to a directory containing a file named config.json. Checkout your internet connection or see how to run the library in offline mode at 'https://huggingface.co/docs/transformers/installation#offline-mode'.
4.1.2. python类库安装架构异常
OSError: dlopen(/Users/adamsun/Library/Python/3.8/lib/python/site-packages/torch/lib/libtorch_global_deps.dylib, 0x000A): tried: '/Users/adamsun/Library/Python/3.8/lib/python/site-packages/torch/lib/libtorch_global_deps.dylib' (mach-o file, but is an incompatible architecture (have (arm64), need (x86_64)))
这个是安装的python类库对应的架构不一样导致的,一般如果本地通过macos通过python sdk下载时可能发生,可以通过如下的方式来切换重装后解决
# 查看当前架构 arch # 修改 arch -x86_64 zsh
4.2. modelscope
魔塔社区modelscope是一个模型开源社区及创新平台,由阿里巴巴通义实验室,联合CCF开源发展委员会,共同作为项目发起创建。对标huggingface,网络友好。
5. DSW模型部署测试与验证
http服务的拉起方式有很多:
- 大模型风口后有很多专注于LLM的开源推理框架,vLLM是一个比较火的框架,github链接,docs.vllm.ai,于前些日子被Pytorch官方宣布成为PyTorch生态系统项目,比较快速的可以通过vLLM来快速部署。不同LLM开源推理服务框架的优缺点可以参考如下的开源文章:https://zhuanlan.zhihu.com/p/647973148?1
- 基于FastAPI等python开源的http框架:https://fastapi.tiangolo.com/
- 基于EAS提供的自研自定义Processor allspark的http服务
5.1. 基于vllm
5.1.1. 测试与验证
- Offline Batched Inference
这种方式不是直接拉起http服务,需要配合其他第三方开源的http框架配合使用(如第六章中的依赖eas allspark的自定义Processor)
# 默认是hg,如果huggingface报超时,set下这个 或者用python环境中的os.environ后再执行LLM类的初始化 export VLLM_USE_MODELSCOPE=True from vllm import LLM # modelscope 需要添加 trust_remote_code llm = LLM(model=..., revision=..., task=..., trust_remote_code=True) output = llm.generate("...") print(output)
- OpenAI-Compatible Server
vllm serve /mnt/sunyf_oss_data/Qwen2-VL-7B-Instruct --limit-mm-per-prompt image=2 --dtype=half --max_model_len=976
或
python -m vllm.entrypoints.openai.api_server <options>
两个方式起的http服务是一样的 vllm serve的实现方式底层也是 vllm.entrypoints.openai.api_server,与python -m直接起是一样的效果,可以通过执行文件的代码以及绑定的回调函数判断。
启动后我们可以看到默认监听到了localhost的 8000端口,本地验证可以多开terminal或者通过nohup来做后台运行。
5.1.2. 相关报错及解决方案
5.1.2.1. ValueError: With `vllm serve`, you should provide the model as a positional argument instead of via the `--model` option.
通过-h的帮助我们可以看到
(myenv) root@dsw-677785-7c89699dd8-trs9f:/mnt/workspace# vllm serve -h usage: vllm serve <model_tag> [options] --model MODEL Name or path of the huggingface model to use.
但是类似的希望从本地load模型文件的命令会报错,可以通过vllm.engine.arg_utils.EngineArgs这里看到默认是facebook/opt-125m,需要通过model_tag的位置参数传入,然后通过下图所示的校验后会做args.model的重新复制,这里没做深究,按5.1.1.的部分改下model_tag 直接传路径即可
vllm serve Qwen/Qwen2-VL-7B-Instruct --model /mnt/sunyf_oss_data/Qwen2-VL-7B-Instruct
5.1.2.2. assert "factor" in rope_scaling AssertionError
vllm启动后,具体报错的堆栈如下:
Traceback (most recent call last): File "/mnt/root/miniconda/envs/myenv/bin/vllm", line 8, in <module> sys.exit(main()) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/scripts.py", line 165, in main args.dispatch_function(args) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/scripts.py", line 37, in serve asyncio.run(run_server(args)) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete return future.result() File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/entrypoints/openai/api_server.py", line 498, in run_server async with build_async_engine_client(args) as async_engine_client: File "/mnt/root/miniconda/envs/myenv/lib/python3.10/contextlib.py", line 199, in __aenter__ return await anext(self.gen) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/entrypoints/openai/api_server.py", line 110, in build_async_engine_client async with build_async_engine_client_from_engine_args( File "/mnt/root/miniconda/envs/myenv/lib/python3.10/contextlib.py", line 199, in __aenter__ return await anext(self.gen) File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/entrypoints/openai/api_server.py", line 132, in build_async_engine_client_from_engine_args if (model_is_embedding(engine_args.model, engine_args.trust_remote_code, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/entrypoints/openai/api_server.py", line 73, in model_is_embedding return ModelConfig(model=model_name, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/config.py", line 227, in __init__ self.max_model_len = _get_and_verify_max_len( File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/config.py", line 1747, in _get_and_verify_max_len assert "factor" in rope_scaling AssertionError
这部分通过堆栈我们可以看到
return ModelConfig(model=model_name, 读取到了我们指定模型的config文件
通过查看Qwen2-vl相关的模型文件,config.json中确实没有位置编码的缩放因子factor相关的配置,这个报错似乎是合理的,通过切换不同规模的vl模型我们发现都存在这个报错,通过模型结构我推测了下,模型有多头自注意力的实现,位置编码已经包含了对位置信息的处理,理论上不需要额外的缩放因子来调整位置编码的尺度。
带着疑问也是到开源社区做了相关问题的检索,发现了对应的issue:
https://github.com/huggingface/transformers/issues/33401
关联:https://github.com/QwenLM/Qwen2-VL/issues/247
同样的问题在qwen2-vl的github官网也有相关的说明,qwen2-vl是在hg transformers库的latest版本中的,推荐是从如下的方式做历史版本源码的构建
https://github.com/QwenLM/Qwen2-VL?tab=readme-ov-file#quickstart
类似的报错还有如KeyError: 'qwen2_vl'的相关内容
pip install git+https://github.com/huggingface/transformers@21fac7abba2a37fae86106f87fcf9974fd1e3830
也可以通过该commit hash找到对应的pr做源码编译
5.1.2.3. ImportError('/path/to/python/dist-packages/vllm/_C.abi3.so: undefined symbol
(myenv) root@dsw-677785-6dc4f7589d-225hf:~# vllm serve Qwen/Qwen2.5-1.5B-Instruct Traceback (most recent call last): File "/mnt/root/miniconda/envs/myenv/bin/vllm", line 5, in <module> from vllm.scripts import main File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/__init__.py", line 3, in <module> from vllm.engine.arg_utils import AsyncEngineArgs, EngineArgs File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/engine/arg_utils.py", line 11, in <module> from vllm.config import (CacheConfig, CompilationConfig, ConfigFormat, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/config.py", line 22, in <module> from vllm.model_executor.layers.quantization import (QUANTIZATION_METHODS, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/model_executor/__init__.py", line 1, in <module> from vllm.model_executor.parameter import (BasevLLMParameter, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/model_executor/parameter.py", line 7, in <module> from vllm.distributed import get_tensor_model_parallel_rank File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/__init__.py", line 1, in <module> from .communication_op import * File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/communication_op.py", line 6, in <module> from .parallel_state import get_tp_group File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/parallel_state.py", line 38, in <module> import vllm.distributed.kv_transfer.kv_transfer_agent as kv_transfer File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/kv_transfer/kv_transfer_agent.py", line 15, in <module> from vllm.distributed.kv_transfer.kv_connector.factory import ( File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/kv_transfer/kv_connector/factory.py", line 3, in <module> from .base import KVConnectorBase File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/distributed/kv_transfer/kv_connector/base.py", line 14, in <module> from vllm.sequence import IntermediateTensors File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/sequence.py", line 16, in <module> from vllm.inputs import SingletonInputs, SingletonInputsAdapter File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/inputs/__init__.py", line 7, in <module> from .registry import (DummyData, InputContext, InputProcessingContext, File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/inputs/registry.py", line 13, in <module> from vllm.transformers_utils.tokenizer import AnyTokenizer File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/transformers_utils/tokenizer.py", line 16, in <module> from vllm.utils import make_async File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/utils.py", line 46, in <module> from vllm.platforms import current_platform File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/platforms/__init__.py", line 100, in <module> from .cuda import CudaPlatform File "/mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/platforms/cuda.py", line 15, in <module> import vllm._C # noqa ImportError: /mnt/root/miniconda/envs/myenv/lib/python3.10/site-packages/vllm/_C.abi3.so: undefined symbol: cuTensorMapEncodeTiled
类似的报错还有:
ImportError('/usr/local/lib/python3.8/dist-packages/vllm/_C.abi3.so: undefined symbol: _ZN5torch7LibraryC1ENS0_4KindESsSt8optionalIN3c1011DispatchKeyEEPKcj')
作为简单排查,类似的.so编译的cpp库我们可以通过c++filt和nm来看下是否确实没有报错中的方法定义
# 查看具体的方法 c++filt _ZN5torch7LibraryC1ENS0_4KindESsSt8optionalIN3c1011DispatchKeyEEPKcj # 查找对应库的路径 pip3 show torch # 查看对应二进制文件是否有指定方法,实现是否相同 nm -AC ./* | grep torch::Library::Library
https://github.com/vllm-project/vllm/issues/5501
github官网上也有类似的报错,这个问题一般是指定类库的版本与CUDA的版本不兼容导致的
可以通过
nvidia-smi # 查看当前环境的CUDA版本
目前遇到的有vllm和pytorch两个
- vllm
vllm的二进制文件是CUDA 12.1编译的,如果我们机器cuda的版本不同的话(比如pai上多数机器还是CUDA 11.8)可以参考如下方案基于11.8的CUDA版本重新编译
# Install vLLM with CUDA 11.8. export VLLM_VERSION=0.6.1.post1 export PYTHON_VERSION=310 pip install https://github.com/vllm-project/vllm/releases/download/v${VLLM_VERSION}/vllm-${VLLM_VERSION}+cu118-cp${PYTHON_VERSION}-cp${PYTHON_VERSION}-manylinux1_x86_64.whl --extra-index-url https://download.pytorch.org/whl/cu118
- pytorch
python3 -c "import torch; print(torch.__version__)" # 2.4.0+cu118
可以根据报错未定义的方法找到对应的库去重装,如https://pytorch.org/官网根据自己机器所在的环境生成命令后重新执行。
5.1.2.4. ImportError: Using `low_cpu_mem_usage=True` or a `device_map` requires Accelerate
按报错手动装包,有依赖,手动编译的transformers可能会导致一些依赖有问题
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/mnt/root/miniconda/envs/eas/lib/python3.10/site-packages/modelscope/utils/hf_util.py", line 351, in from_pretrained module_obj = module_class.from_pretrained(model_dir, *model_args, File "/mnt/root/miniconda/envs/eas/lib/python3.10/site-packages/transformers/modeling_utils.py", line 3589, in from_pretrained raise ImportError( ImportError: Using `low_cpu_mem_usage=True` or a `device_map` requires Accelerate: `pip install 'accelerate>=0.26.0'`
5.1.2.5. RuntimeError: The NVIDIA driver on your system is too old
这个问题本质上也是库和环境的cuda版本不匹配的问题,建议装库之前可以根据机器的环境做下适配,一些特殊的场景下也可以通过工单的方式找PAI的产品侧对CUDA的版本做个更新
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/mnt/root/miniconda/envs/eas/lib/python3.10/site-packages/transformers/feature_extraction_utils.py", line 244, in to new_data[k] = v.to(device=device) File "/mnt/root/miniconda/envs/eas/lib/python3.10/site-packages/torch/cuda/__init__.py", line 319, in _lazy_init torch._C._cuda_init() RuntimeError: The NVIDIA driver on your system is too old (found version 11080). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver.
英伟达官网cuda toolkit的版本与driver version的相关说明
https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#major-components
5.1.2.6. ValueError: The model's max seq len (32768) is larger than the maximum number of tokens that can be stored in KV cache (976). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when initializing the engine.
https://github.com/vllm-project/vllm/issues/2418
类似的报错信息其实还是比较完备的,这里简单解释下就是模型的最大序列长度长于GPU的KV缓存的限制,比较方便的方案可以在起vllm的服务的时候,将max_model_len设置成976。
或者一些特殊情况下可以考虑修改模型的config.json,来关掉kv cache。
5.2. 基于自定义镜像
5.2.1. 以FastAPI为例
5.2.1.1. Dockerfile
FROM ubuntu:22.04 LABEL maintainer="syf373586@alibaba-inc.com" RUN chsh -s /bin/bash SHELL ["/bin/bash", "-c"] RUN mkdir -p /root/opt RUN mkdir -p /root/service COPY requirements.txt /root/service/ COPY fast_api_test01.py /root/service/ RUN apt-get update && \ apt-get install -y curl RUN curl "https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh" -o /root/opt/miniconda.sh && \ /bin/bash /root/opt/miniconda.sh -b -p /root/miniconda && \ ln -s /root/miniconda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \ echo ". /root/miniconda/etc/profile.d/conda.sh" >> ~/.bashrc ENV PATH /root/miniconda/bin:/root/miniconda/condabin:$PATH RUN conda create -n qwen2_vl python=3.10 -y RUN echo "conda activate qwen2_vl" >> ~/.bashrc ENV PATH /root/miniconda/envs/qwen2_vl/bin:$PATH RUN python3 -m pip install -r /root/service/requirements.txt
5.2.1.2. 镜像打包上传
# 构建镜像 # ENTRYPOINT ["python3" ,"/root/service/fast_api_test02.py"] docker build -t sunyf:1.0 . # 查看本地镜像 docker image ls -a # 登录acr镜像库 docker login --username=syf373586@1623027246845796 aes-acr-enterprise-registry.cn-hangzhou.cr.aliyuncs.com # tag docker tag [ImageId] aes-acr-enterprise-registry.cn-hangzhou.cr.aliyuncs.com/ns_for_pai/repo_for_pai:[镜像版本号] # push docker push aes-acr-enterprise-registry.cn-hangzhou.cr.aliyuncs.com/ns_for_pai/repo_for_pai:[镜像版本号]
5.2.1.3. 自建服务样例代码
from fastapi import FastAPI from typing import List app = FastAPI() from modelscope import Qwen2VLForConditionalGeneration, AutoTokenizer, AutoProcessor from qwen_vl_utils import process_vision_info from modelscope import snapshot_download model_dir = "/mnt/sunyf_oss_data/Qwen2-VL-7B-Instruct" model = Qwen2VLForConditionalGeneration.from_pretrained( model_dir, torch_dtype="half", device_map="auto" ) processor = AutoProcessor.from_pretrained(model_dir) @app.post("/sunyf_post") def test_post(data: List[dict]): # Preparation for inference text = processor.apply_chat_template( data, tokenize=False, add_generation_prompt=True ) image_inputs, video_inputs = process_vision_info(data) inputs = processor( text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt", ) inputs = inputs.to("cuda") # Inference: Generation of the output generated_ids = model.generate(**inputs, max_new_tokens=128) generated_ids_trimmed = [ out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids) ] output_text = processor.batch_decode( generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False ) return output_text
5.2.1.4. 服务启动样例
服务启动会打印相关的信息,我们可以看到默认起到localhost的800端口,dsw也提供了比较方便的代理,点击docs的url可以很丝滑的跳转到测试页面,基于dsw的大模型推理服务测试给了全生命周期的支持。
5.2.1.5. 服务doc及请求样例
基于Fastapi docs的url可以在跳转后看到类似swagger-ui的页面,我们可以从这里看到定义好的request data的类型以及请求的参数、返回的参数等信息,便于调试。
5.3. 基于EAS自定义processor allspark
eas的自定义processor与众多开源的http框架原理类似,参考文档
类似5.2.1.3. 中fastapi的实现逻辑,需要继承allspark.BaseProcessor的基类,实现如下几个关键的方法
- initialize,这里主要用于加载模型,在http服务启动的时候仅运行一次
- process,这里主要是每次post请求进行调用,主要用于inference的逻辑,与fastapi的实现中,装饰器:@app.post("/sunyf_post")所绑定的方法def test_post(data: List[dict]):是同样的功能
这部分逻辑比较相似,这里不做展开,后续将在第六章节「EAS模型部署与验证」的部分主要讲解一些常见的报错。
5.4. 基于DSW的镜像保存问题
dsw完成测试的环境可以基于DSW的制作镜像功能直接保存镜像到企业或者个人版的acr,供后续在eas上部署推理服务使用。这里建议除了python或者服务所需的基础环境外不要额外的添加过大的文件,会导致镜像保存超时,模型文件,代码以及其他的文件可以通过oss\nas等挂载的方式后期挂载到eas所在的pod上
6. EAS模型部署与验证常见报错
6.1. 常见的CUDA oom
类似的报错比较常见,可以通过扩机型规格、推理的时候降低batch大小、降低模型参数的精度等方法在业务允许的情况下避免这一问题
6.2. processor路径找不到,ENV dir not exists, please check it!
这个基本上有几大类,自定义processor的包解压后、mount的路径导致某些dir找不到,类似的问题可以申请下eas的容器登录权限,通过sleep命令到容器中看下具体的路径与自己写的命令是否有偏差导致的这个问题。
[2024-12-05 17:22:21] Uncompressing model[/home/admin/docker_ml/workspace/model] [2024-12-05 17:22:21] Uncompressing warm_up file[/home/admin/docker_ml/workspace/warm_up] [2024-12-05 17:22:21] Uncompressing processor[/home/admin/docker_ml/workspace/predictor] [2024-12-05 17:22:21] ENV dir not exists, please check it!
6.3. The specified VSwitch does not have enough IP addresses.
EAS服务启动时选择的vpc下的交换机的ip不够。可以看下vsw的可用ip的数量,更换交换机或者vpc后再尝试。
6.4. no space left on device
这类的报错比较明显,一般是镜像太大本地盘不够,EAS免费赠送30G系统盘,类似的问题可以手动扩一下盘。
Failed to pull image "registry-vpc.cn-shanghai.aliyuncs.com/csq-yiwei/csq-yiwei:test-qwen1": [failed to pull and unpack image "registry-vpc.cn-shanghai.aliyuncs.com/csq-yiwei/csq-yiwei:test-qwen1": failed to resolve reference "registry-vpc.cn-shanghai.aliyuncs.com/csq-yiwei/csq-yiwei:test-qwen1": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed, failed to pull and unpack image "registry-vpc.cn-shanghai.aliyuncs.com/csq-yiwei/csq-yiwei:test-qwen1": failed to extract layer sha256:979f8006b89e2599920199ee287311c3ff5b35571289df7543fdb35a4cc7b3a0: write /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/153/fs/usr/local/cuda-12.4/targets/x86_64-linux/lib/libcusparse.so.12.3.1.170: no space left on device: unknown]: ErrImagePull
6.5. Readiness probe failed: dial tcp ip:port: connect: connection refused
EAS控制台配置的http服务的监听端口没起来,EAS提供了基于K8s的健康检查能力,健康检查没过,服务会一直是waiting状态,worker没有非0的退出码也不会fo,类似的问题可以检查下启动命令和日志是否有异常导致端口没起来,也可以像6.1.2. 一样申请一下eas的容器登录权限登录排查。
6.6. eascmd的pysdk init初始化命令依赖conda,如果本地环境没有的话需要安装
6.7. No module named 'allspark'
eas的python自定义processor用到的基类来自allspark库,需要通过eascmd init进行初始化。
6.8. AttributeError: module 'allspark' has no attribute 'BaseProcessor'
eas的python自定义processor用到的基类来自allspark库,pypi上有个同名的库,如果是通过pip install 或者conda install直接根据allspark来安装的话则会有类似的问题,需要通过eascmd init进行初始化并用生成的python ENV起服务
6.9. [TypeError] in processor: MyProcessor.process() task 1 positional argument but 2 were given(base)
post请求传data的时候的报错,process方法的要有入参,除self外还有一个参数,这里建议process方法的入参不要修改,直接默认后根据自身业务的情况修改入参的格式即可