# 推理和部署

以下为swift支持的推理引擎以及接入部分的相应能力，三种推理加速引擎为SWIFT的推理、部署、评测模块提供推理加速：

| 推理加速引擎 | OpenAI API | 多模态 |  量化模型 | 多LoRA | QLoRA | Batch推理 | 并行技术       |
| ------------ | -------------- | ---------- | ------ | -------- | ------ | ----- | ----- |
| pytorch      | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/deploy/client/llm/chat/openai_client.py) | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/app/mllm.sh) |     ✅        | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_lora.py) | ✅     | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/batch_ddp.sh) |DDP/device_map |
| [vllm](https://github.com/vllm-project/vllm)         | ✅          | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/infer/vllm/mllm_tp.sh) |    ✅        | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/deploy/lora/server.sh) | ❌    | ✅ |  TP/PP/DP   |
| [sglang](https://github.com/sgl-project/sglang)    | ✅          | ❌ |      ✅        | ❌      | ❌     | ✅ | TP/PP/DP/EP |
| [lmdeploy](https://github.com/InternLM/lmdeploy)    | ✅          | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/infer/lmdeploy/mllm_tp.sh) |      ✅        | ❌      | ❌     | ✅ | TP/DP     |


## 推理
ms-swift使用了分层式的设计思想，用户可以使用命令行界面、Web-UI界面和直接使用Python的方式进行推理。

如果要查看LoRA微调后模型的推理，可以参考[预训练与微调文档](./预训练与微调.md#推理微调后模型)。

### 使用CLI

**全参数模型：**
```shell
CUDA_VISIBLE_DEVICES=0 swift infer \
    --model Qwen/Qwen2.5-7B-Instruct \
    --stream true \
    --infer_backend pt \
    --max_new_tokens 2048
```

**LoRA模型：**
```shell
CUDA_VISIBLE_DEVICES=0 swift infer \
    --model Qwen/Qwen2.5-7B-Instruct \
    --adapters swift/test_lora \
    --stream true \
    --infer_backend pt \
    --temperature 0 \
    --max_new_tokens 2048
```


**命令行推理指令**

以上为交互式命令行界面推理，脚本运行后仅需在terminal中输入query即可。你也可以输入以下特殊指令：
- `multi-line`: 切换到多行模式，在输入中支持换行输入，以`#`代表输入结束。
- `single-line`: 切换到单行模式，以换行代表输入结束。
- `reset-system`: 重置system并清空历史记录。
- `clear`: 清除历史记录。
- `quit` or `exit`: 退出对话。

**多模态模型**

```shell
CUDA_VISIBLE_DEVICES=0 \
MAX_PIXELS=1003520 \
VIDEO_MAX_PIXELS=50176 \
FPS_MAX_FRAMES=12 \
swift infer \
    --model Qwen/Qwen2.5-VL-3B-Instruct \
    --stream true \
    --infer_backend pt \
    --max_new_tokens 2048
```

如果要进行多模态模型的推理，可以在query中添加`<image>/<video>/<audio>`等标签（代表图像表征在`inputs_embeds`中的位置），例如输入`<image><image>这两张图有啥区别`，`<video>描述这段视频`。然后根据提示输入相应的图像/视频/音频即可。

以下为一个推理的示例：
```
<<< <image><image>这两张图有什么区别
Input an image path or URL <<< http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png
Input an image path or URL <<< http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/animal.png
这两张图片的区别在于它们所展示的动物和场景。

1. **第一张图片**：
  - 展示了一只小猫。
  - 小猫有大大的眼睛，表情显得有些困惑或好奇。
  - 背景是模糊的，可能是室内环境。

2. **第二张图片**：
  - 展示了一群羊。
  - 羊们站在草地上，背景是绿色的山丘和蓝天白云。
  - 羊的表情看起来很平静，似乎在享受大自然的环境。

总结来说，第一张图片是一只小猫，而第二张图片是一群羊。
--------------------------------------------------
<<< clear
<<< <video>描述这段视频
Input a video path or URL <<< https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4
The video shows a baby wearing sunglasses sitting on a bed and reading a book. The baby is holding the book with both hands and appears to be focused on the pages. The baby's feet are visible in the frame, and they are moving slightly as they read. The background of the video shows a room with a bed and some furniture.
```


**数据集推理：**
```shell
CUDA_VISIBLE_DEVICES=0 swift infer \
    --model Qwen/Qwen2.5-7B-Instruct \
    --stream true \
    --infer_backend pt \
    --val_dataset AI-ModelScope/alpaca-gpt4-data-zh \
    --max_new_tokens 2048
```

以上提供了全参数和LoRA流式推理的例子，以下介绍更多SWIFT中的推理技术：
- 界面推理：你可以将`swift infer`改成`swift app`。
- batch推理：`infer_backend=pt`可以指定`--max_batch_size`对大模型和多模态大模型进行batch推理，具体参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/batch_ddp.sh)。在进行batch推理时，你不能设置`--stream true`。
- DDP/device_map推理：`infer_backend=pt`支持使用DDP/device_map技术进行并行推理，具体参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/mllm_device_map.sh)。
- 推理加速：swift支持使用vllm/sglang/lmdeploy对推理、部署和评测模块进行推理加速，只需要额外指定`--infer_backend vllm/sglang/lmdeploy`即可。可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/vllm/ddp.sh)。
- 多模态模型：我们提供了[pt](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/mllm_device_map.sh)/[vllm](https://github.com/modelscope/ms-swift/blob/main/examples/infer/vllm/mllm_tp.sh)/[lmdeploy](https://github.com/modelscope/ms-swift/blob/main/examples/infer/lmdeploy/mllm_tp.sh)对多模态模型进行多GPU推理的shell脚本。
- 量化模型：直接选择GPTQ、AWQ、BNB量化的模型，例如：`--model Qwen/Qwen2.5-7B-Instruct-GPTQ-Int4`即可。
- 更多模型类型：我们提供了[bert](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/bert.sh)、[reward_model](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/reward_model.sh)、[prm](https://github.com/modelscope/ms-swift/blob/main/examples/infer/pt/prm.sh)的推理脚本。


**小帖士：**
- SWIFT会将推理结果保存起来，你可以通过`--result_path`指定保存路径。
- 如果要输出logprobs，只需要在推理时，指定`--logprobs true`即可。SWIFT会保存。注意，设置`--stream true`将不会存储。
- infer_backend为pt支持所有swift已支持模型的推理，而infer_backend为vllm/sglang/lmdeploy只支持部分模型，具体请参考[vllm](https://docs.vllm.ai/en/latest/models/supported_models.html)、[sglang](https://docs.sglang.ai/supported_models/generative_models.html)、[lmdeploy](https://lmdeploy.readthedocs.io/en/latest/supported_models/supported_models.html)文档。
- 使用`--infer_backend vllm`出现OOM，可以通过降低`--vllm_max_model_len`，`--vllm_max_num_seqs`，选择合适的`--vllm_gpu_memory_utilization`，设置`--vllm_enforce_eager true`。或者使用tensor并行`--vllm_tensor_parallel_size`来解决。
- 使用`--infer_backend vllm`推理多模态模型，需要传入多张图片。可以设置`--vllm_limit_mm_per_prompt`解决，例如：`--vllm_limit_mm_per_prompt '{"image": 10, "video": 5}'`。
- 推理qwen2-vl/qwen2.5-vl出现OOM，可以通过设置`MAX_PIXELS`、`VIDEO_MAX_PIXELS`、`FPS_MAX_FRAMES`解决，可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/app/mllm.sh)。
- swift内置对话模板与使用transformers运行的对话模板对齐，测试参考[这里](https://github.com/modelscope/ms-swift/blob/main/tests/test_align/test_template/test_vision.py)。如果出现未对齐情况，欢迎提issue/PR修正。


### 使用Web-UI
如果你要使用界面的方式进行推理，可以查看[Web-UI文档](../GetStarted/Web-UI.md)。

### 使用Python

文本模型：
```python
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import PtEngine, RequestConfig, InferRequest
model = 'Qwen/Qwen2.5-0.5B-Instruct'

# 加载推理引擎
engine = PtEngine(model, max_batch_size=2)
request_config = RequestConfig(max_tokens=512, temperature=0)

# 这里使用了2个infer_request来展示batch推理
infer_requests = [
    InferRequest(messages=[{'role': 'user', 'content': 'who are you?'}]),
    InferRequest(messages=[{'role': 'user', 'content': '浙江的省会在哪？'},
                           {'role': 'assistant', 'content': '浙江省的省会是杭州。'},
                           {'role': 'user', 'content': '这里有什么好玩的地方'},]),
]
resp_list = engine.infer(infer_requests, request_config)
query0 = infer_requests[0].messages[0]['content']
print(f'response0: {resp_list[0].choices[0].message.content}')
print(f'response1: {resp_list[1].choices[0].message.content}')
```

多模态模型：
```python
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['MAX_PIXELS'] = '1003520'
os.environ['VIDEO_MAX_PIXELS'] = '50176'
os.environ['FPS_MAX_FRAMES'] = '12'

from swift.llm import PtEngine, RequestConfig, InferRequest
model = 'Qwen/Qwen2.5-VL-3B-Instruct'

# 加载推理引擎
engine = PtEngine(model, max_batch_size=2)
request_config = RequestConfig(max_tokens=512, temperature=0)

# 这里使用了3个infer_request来展示batch推理
infer_requests = [
    InferRequest(messages=[{'role': 'user', 'content': 'who are you?'}]),
    InferRequest(messages=[{'role': 'user', 'content': '<image><image>两张图的区别是什么？'}],
                 images=['http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png',
                         'http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/animal.png']),
    InferRequest(messages=[{'role': 'user', 'content': '<video>describe the video'}],
                 videos=['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4']),
]
resp_list = engine.infer(infer_requests, request_config)
query0 = infer_requests[0].messages[0]['content']
print(f'response0: {resp_list[0].choices[0].message.content}')
print(f'response1: {resp_list[1].choices[0].message.content}')
print(f'response2: {resp_list[2].choices[0].message.content}')
```

我们也提供了更多使用python推理的demo：
- 使用流式推理以及`VllmEngine`、`SglangEngine`、`LmdeployEngine`进行推理加速，可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo.py)。
- 多模态推理：除了上述多模态输入格式外，swift兼容OpenAI的多模态输入格式，参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_mllm.py)。
- grounding任务：对多模态模型进行Grounding任务画框，可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_grounding.py)。
- 多LoRA推理：参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_lora.py)。
- agent推理：参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_agent.py)。
- 异步接口：使用`engine.infer_async`进行python方式推理，参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo.py)。


## 部署

如果要查看LoRA微调后模型的部署，可以参考[预训练与微调文档](./预训练与微调.md#部署微调后模型)。

这里主要介绍对多模态模型的部署和调用，文本大模型我们给出简单的部署和调用的简单案例：

服务端部署：
```shell
CUDA_VISIBLE_DEVICES=0 swift deploy \
    --model Qwen/Qwen2.5-7B-Instruct \
    --infer_backend vllm \
    --max_new_tokens 2048 \
    --served_model_name Qwen2.5-7B-Instruct
```

客户端调用测试：
```shell
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen2.5-7B-Instruct",
"messages": [{"role": "user", "content": "晚上睡不着觉怎么办？"}],
"max_tokens": 256,
"temperature": 0
}'
```


### 服务端

```shell
# test env: pip install transformers==4.51.3 vllm==0.8.5.post1
CUDA_VISIBLE_DEVICES=0 \
MAX_PIXELS=1003520 \
VIDEO_MAX_PIXELS=50176 \
FPS_MAX_FRAMES=12 \
swift deploy \
    --model Qwen/Qwen2.5-VL-3B-Instruct \
    --infer_backend vllm \
    --vllm_gpu_memory_utilization 0.9 \
    --vllm_max_model_len 8192 \
    --max_new_tokens 2048 \
    --vllm_limit_mm_per_prompt '{"image": 5, "video": 2}' \
    --served_model_name Qwen2.5-VL-3B-Instruct
```


### 客户端

这里介绍3种调用客户端的方式，分别是curl、openai库和swift客户端。


方案一: curl
```shell
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen2.5-VL-3B-Instruct",
"messages": [{"role": "user", "content": [
    {"type": "image", "image": "http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png"},
    {"type": "image", "image": "http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/animal.png"},
    {"type": "text", "text": "两张图的区别是什么？"}
]}],
"max_tokens": 256,
"temperature": 0
}'
```

方案2: openai库
```python
from openai import OpenAI

client = OpenAI(
    api_key='EMPTY',
    base_url=f'http://127.0.0.1:8000/v1',
)
model = client.models.list().data[0].id
print(f'model: {model}')

messages = [{'role': 'user', 'content': [
    {'type': 'video', 'video': 'https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4'},
    {'type': 'text', 'text': 'describe the video'}
]}]

resp = client.chat.completions.create(model=model, messages=messages, max_tokens=512, temperature=0)
query = messages[0]['content']
response = resp.choices[0].message.content
print(f'query: {query}')
print(f'response: {response}')

# base64
import base64
import requests
resp = requests.get('https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4')
base64_encoded = base64.b64encode(resp.content).decode('utf-8')
messages = [{'role': 'user', 'content': [
    {'type': 'video', 'video': f'data:video/mp4;base64,{base64_encoded}'},
    {'type': 'text', 'text': 'describe the video'}
]}]

gen = client.chat.completions.create(model=model, messages=messages, stream=True, temperature=0)
print(f'query: {query}\nresponse: ', end='')
for chunk in gen:
    if chunk is None:
        continue
    print(chunk.choices[0].delta.content, end='', flush=True)
print()
```

方案三：swift客户端

```python
from swift.llm import InferRequest, InferClient, RequestConfig
from swift.plugin import InferStats


engine = InferClient(host='127.0.0.1', port=8000)
print(f'models: {engine.models}')
metric = InferStats()
request_config = RequestConfig(max_tokens=512, temperature=0)

# 这里使用了3个infer_request来展示batch推理
# 支持传入本地路径、base64和url
infer_requests = [
    InferRequest(messages=[{'role': 'user', 'content': 'who are you?'}]),
    InferRequest(messages=[{'role': 'user', 'content': '<image><image>两张图的区别是什么？'}],
                 images=['http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png',
                         'http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/animal.png']),
    InferRequest(messages=[{'role': 'user', 'content': '<video>describe the video'}],
                 videos=['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4']),
]

resp_list = engine.infer(infer_requests, request_config, metrics=[metric])
print(f'response0: {resp_list[0].choices[0].message.content}')
print(f'response1: {resp_list[1].choices[0].message.content}')
print(f'response2: {resp_list[2].choices[0].message.content}')
print(metric.compute())
metric.reset()

# base64
import base64
import requests
resp = requests.get('https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4')
base64_encoded = base64.b64encode(resp.content).decode('utf-8')
messages = [{'role': 'user', 'content': [
    {'type': 'video', 'video': f'data:video/mp4;base64,{base64_encoded}'},
    {'type': 'text', 'text': 'describe the video'}
]}]
infer_request = InferRequest(messages=messages)
request_config = RequestConfig(max_tokens=512, temperature=0, stream=True)
gen_list = engine.infer([infer_request], request_config, metrics=[metric])
print(f'response0: ', end='')
for chunk in gen_list[0]:
    if chunk is None:
        continue
    print(chunk.choices[0].delta.content, end='', flush=True)
print()
print(metric.compute())
```
我们也提供了更多部署的demo：
- 多LoRA部署与调用: 参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/lora)。
- Base模型的部署与调用: 参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/client/llm/base)。
- 更多模型类型: 我们提供了[bert](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/bert)、[reward_model](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/reward_model)的部署脚本。
