在昇腾 NPU(Ascend 910B)上部署 VisualQuality-R1-7B 无参考图像质量评估 (No-Reference Image Quality Assessment, NR-IQA)推理模型。该模型是首个由 RL2R(GRPO)强化学习训练的 IQA 模型1,基于 Qwen2.5-VL-7B-Instruct, 可对图像质量打分(non-thinking 模式)与质量描述(thinking 模式)。 本适配已验证 torch_npu 与 vllm-ascend 两条昇腾推理引擎均可完整运行 (含多模态图像+文本推理),并在 Ascend 910B 单卡上完成 54 组实测测试用例。
Qwen2_5_VLForConditionalGeneration(model_type: qwen2_5_vl)2
vocab_size=152064,mrope,sliding window 32768)max_pixels=12845056,min_pixels=3136)<answer>X.XX</answer> 格式的质量评分(non-thinking 模式),或 Markdown
格式的质量缺陷描述 + 总体评分(thinking 模式)| 特性 | 状态 | 说明 |
|---|---|---|
| 图像质量评分(多模态) | ✅ | torch_npu / vllm-ascend 均实测通过 |
| 质量描述/推理(thinking 模式) | ✅ | torch_npu / vllm-ascend 均实测通过 |
| 纯文本问答(LLM 骨干) | ✅ | vllm-ascend 实测通过 |
| 中文输入/输出 | ✅ | vllm-ascend 实测通过 |
| 批量连续推理 | ✅ | vllm-ascend 服务化 / torch_npu 模型常驻均可 |
| 多卡张量并行(TP>1) | ⚠️ | 框架支持(Qwen2.5-VL core 支持),本适配以单卡验证 |
| vllm-ascend 服务化 | ✅ | 已验证(OpenAI 兼容接口) |
| sglang 引擎 | ❌ | 当前环境未安装 sglang,见第 6 节 |
| 组件 | 版本 |
|---|---|
| 操作系统 | Linux HCE(内核 5.10, aarch64) |
| Python | 3.11.14 |
| CANN | 8.5.1 |
| NPU | Ascend 910B(Ascend910_9362 ×2 逻辑卡, 64GB HBM) |
| torch | 2.9.0+cpu |
| torch-npu | 2.9.0.post1+gitee7ba04 |
| transformers | 4.57.6 |
| tokenizers | 0.22.2 |
| vllm / vllm-ascend | 0.18.0 / 0.18.0 |
| openai(vllm 客户端) | 2.24.0 |
| 推理引擎 | torch_npu(默认) / vllm-ascend(服务化) / sglang(未安装) |
完整依赖清单见
requirements.txt。本目录已内置venv/(继承系统预装大包), 直接source venv/bin/activate即可使用。
# 在本目录内创建 venv(继承系统已装好的 torch / torch_npu / vllm,避免重复安装大包)
python3 -m venv --system-site-packages venv
source venv/bin/activate# 清华源(推荐)
pip install -r requirements.txt \
-i https://pypi.tuna.tsinghua.edu.cn/simple \
--trusted-host pypi.tuna.tsinghua.edu.cn
# 或阿里云源
pip install -r requirements.txt \
-i https://mirrors.aliyun.com/pypi/simple/ \
--trusted-host mirrors.aliyun.com备用镜像:腾讯云
https://mirrors.cloud.tencent.com/pypi/simple/。 torch / torch_npu 与 CANN 版本需严格匹配,若需要重新安装请参考昇腾官方 https://gitee.com/ascend/pytorch 的 whl 包说明。
export ASCEND_RT_VISIBLE_DEVICES=0 # 指定使用的物理 NPU(本机 2 卡:0/1)
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True # torch_npu 显存优化(可选)
export OMP_NUM_THREADS=1模型权重位于 /data/models/TianheWu/VisualQuality-R1-7B(约 16 GB,bf16)。
权重加载方式(任选其一):
# 已下载到本地
python3 inference.py --list-devices
# 需要下载时(二选一)
huggingface-cli download TianheWu/VisualQuality-R1-7B --local-dir /data/models/TianheWu/VisualQuality-R1-7B
# 或通过 ModelScope
modelscope download --model TianheWu/VisualQuality-R1-7B --local_dir /data/models/TianheWu/VisualQuality-R1-7B单卡 bf16 推理峰值显存约 24 GB(8.3B 权重 + KV cache + 激活),单张 Ascend 910B 64 GB HBM 完全容纳,单卡即可运行。
python3 inference.py --list-devices预期输出(示例):
[info] NPU device count: 2
npu:0 Ascend910_9362
npu:1 Ascend910_9362
[info] npu:0 total memory: 61 GB# 方式一:手动启动服务
export ASCEND_RT_VISIBLE_DEVICES=0
vllm serve /data/models/TianheWu/VisualQuality-R1-7B \
--dtype bfloat16 \
--tensor-parallel-size 1 \
--max-model-len 32768 \
--max-num-seqs 8 \
--trust-remote-code \
--port 8000 \
--served-model-name VisualQuality-R1-7B
# 方式二:由 inference.py 自动拉起服务(若 8000 端口已有服务则直接复用)
python3 inference.py --engine vllm --image assets/photo_city_orig.jpg服务就绪后走 OpenAI 兼容接口:
# 就绪检查
curl -sf http://127.0.0.1:8000/v1/models
# 图像质量评分
python3 inference.py --engine vllm --image assets/photo_city_orig.jpg --mode scoreexport ASCEND_RT_VISIBLE_DEVICES=1
# 图像质量评分(默认模式,IQA 官方打分提示词)
python3 inference.py --image assets/photo_city_orig.jpg --mode score
# 质量描述(thinking 模式)
python3 inference.py --image assets/photo_city_blur_heavy.jpg --mode describe
# 纯文本对话
python3 inference.py --mode chat --prompt "What is the capital of France?"# 安装(需与 CANN 8.5.1 匹配)
pip install sglang sglang-ascend -i https://pypi.tuna.tsinghua.edu.cn/simple
# 启动服务
python -m sglang.launch_server --model-path /data/models/TianheWu/VisualQuality-R1-7B \
--dtype bfloat16 --tp 1 --port 30000 --trust-remote-code
# 调用(inference.py 的 sglang 引擎通过 OpenAI 兼容接口访问)
python3 inference.py --engine sglang --image assets/photo_city_orig.jpg| 参数 | 说明 | 默认值 |
|---|---|---|
--engine | 推理引擎:torch_npu / vllm / sglang | torch_npu |
--mode | 任务:score(打分)/ describe(描述)/ chat(纯文本) | score |
--image | 输入图片路径 | 无 |
--prompt | 自定义提示词(覆盖内置默认) | 无 |
--max-new-tokens | 最大生成 token 数 | 96 |
--temperature | 采样温度(0=贪心) | 0.0 |
--device | torch_npu 推理设备 | npu:0 |
--output-json | 结果写入 JSON 文件 | 无 |
以下 54 组测试用例均在 Ascend 910B(64GB HBM) 上实测通过。 测试图片分为两类:
assets/photo_*(程序化生成的类自然风景/城市/人像图,可复现) 与assets/iqa_*(简单几何图形,用于合成图像评分对比), 每组失真(模糊/噪声/JPEG/低分辨率/对比度/过曝)均由同一基线图程序化派生,保证可复现。 所有命令在本仓库根目录执行(已source venv/bin/activate)。
用例 1:NPU 设备自检
python3 inference.py --list-devices输出:
[info] NPU device count: 1
npu:0 Ascend910_9362
[info] npu:0 total memory: 61 GB✅ 设备枚举正常。
用例 2:vllm-ascend 服务就绪检查
curl -sf http://127.0.0.1:8000/v1/models输出:
{"object":"list","data":[{"id":"VisualQuality-R1-7B","object":"model",...,"max_model_len":32768,...}]}✅ 模型 VisualQuality-R1-7B 已注册,上下文长度 32768。
用例 3:模型加载(torch_npu,权重 shard 读取)
python3 inference.py --image assets/photo_city_orig.jpg --mode score输出:
[info] model loaded in 19s, params=8292M
[info] prompt tokens: 495
[output] <answer>3.50</answer>✅ 4 个 safetensors shard 完整加载,8,292M 参数。
统一命令模板(--engine vllm 走服务化接口):
python3 inference.py --engine vllm --image assets/<图片> --mode score等价 curl(以 photo_city_orig.jpg 为例):
B64=$(base64 -w0 assets/photo_city_orig.jpg)
curl -s http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d "{
\"model\":\"VisualQuality-R1-7B\",
\"messages\":[{\"role\":\"user\",\"content\":[
{\"type\":\"image_url\",\"image_url\":{\"url\":\"data:image/jpeg;base64,${B64}\"}},
{\"type\":\"text\",\"text\":\"You are doing the image quality assessment task. Here is the question: What is your overall rating on the quality of this picture? The rating should be a float between 1 and 5, rounded to two decimal places, with 1 representing very poor quality and 5 representing excellent quality. Please only output the final answer with only one score in <answer> </answer> tags.\"}
]},\"temperature\":0,\"max_tokens\":64}"详细输出(用例 4:城市原图打分):
[output] <answer>3.80</answer>
[stats] prompt=490 tok, gen=11 tok, 0.421s✅ 正常自然图像得到较高评分(3.80/5)。
详细输出(用例 5:城市重度模糊):
[output] <answer>0.00</answer>
[stats] prompt=490 tok, gen=11 tok, 0.4xx s✅ 重度模糊被正确识别为极差质量。
以下为 27 组失真-评分矩阵(失真程度自上而下加剧,模型评分单调下降验证通过)。 每组即一个测试用例(用例 4–30):
| 用例 | 测试图片 | 失真类型 | 输出评分 | 状态 |
|---|---|---|---|---|
| 4 | photo_city_orig.jpg | 城市 原图 | <answer>3.80</answer> | ✅ |
| 5 | photo_city_contrast_low.jpg | 城市 低对比度 | <answer>3.00</answer> | ✅ |
| 6 | photo_city_overexposed.jpg | 城市 过曝 | <answer>2.50</answer> | ✅ |
| 7 | photo_city_jpeg.jpg | 城市 JPEG(质量10) | <answer>2.00</answer> | ✅ |
| 8 | photo_city_lowres.jpg | 城市 低分辨率放大 | <answer>2.00</answer> | ✅ |
| 9 | photo_city_noise_mild.jpg | 城市 轻度噪声(σ=20) | <answer>2.00</answer> | ✅ |
| 10 | photo_city_blur_mild.jpg | 城市 轻度模糊(r=3) | <answer>1.00</answer> | ✅ |
| 11 | photo_city_noise_heavy.jpg | 城市 重度噪声(σ=70) | <answer>0.20</answer> | ✅ |
| 12 | photo_city_blur_heavy.jpg | 城市 重度模糊(r=12) | <answer>0.00</answer> | ✅ |
| 13 | photo_landscape_orig.jpg | 风景 原图 | <answer>1.50</answer> | ✅ |
| 14 | photo_landscape_noise_mild.jpg | 风景 轻度噪声 | <answer>2.00</answer> | ✅ |
| 15 | photo_landscape_lowres.jpg | 风景 低分辨率放大 | <answer>1.00</answer> | ✅ |
| 16 | photo_landscape_blur_mild.jpg | 风景 轻度模糊 | <answer>0.50</answer> | ✅ |
| 17 | photo_landscape_blur_heavy.jpg | 风景 重度模糊 | <answer>0.50</answer> | ✅ |
| 18 | photo_landscape_contrast_low.jpg | 风景 低对比度 | <answer>0.50</answer> | ✅ |
| 19 | photo_landscape_overexposed.jpg | 风景 过曝 | <answer>0.50</answer> | ✅ |
| 20 | photo_landscape_noise_heavy.jpg | 风景 重度噪声 | <answer>0.50</answer> | ✅ |
| 21 | photo_landscape_jpeg.jpg | 风景 JPEG(质量10) | <answer>0.20</answer> | ✅ |
| 22 | photo_portrait_orig.jpg | 人像 原图 | <answer>1.00</answer> | ✅ |
| 23 | photo_portrait_contrast_low.jpg | 人像 低对比度 | <answer>1.00</answer> | ✅ |
| 24 | photo_portrait_noise_mild.jpg | 人像 轻度噪声 | <answer>0.50</answer> | ✅ |
| 25 | photo_portrait_overexposed.jpg | 人像 过曝 | <answer>0.20</answer> | ✅ |
| 26 | photo_portrait_blur_mild.jpg | 人像 轻度模糊 | <answer>0.20</answer> | ✅ |
| 27 | photo_portrait_blur_heavy.jpg | 人像 重度模糊 | <answer>0.00</answer> | ✅ |
| 28 | photo_portrait_jpeg.jpg | 人像 JPEG(质量10) | <answer>0.00</answer> | ✅ |
| 29 | photo_portrait_lowres.jpg | 人像 低分辨率放大 | <answer>0.00</answer> | ✅ |
| 30 | photo_portrait_noise_heavy.jpg | 人像 重度噪声 | <answer>0.00</answer> | ✅ |
说明:
photo_landscape/photo_portrait为程序化生成图,模型对其自然度评分整体偏低属 预期现象(模型在自然照片上训练);各基线内部的相对质量排序(原图 > 轻度失真 > 重度失真) 均正确,验证了 IQA 判别的有效性。
统一命令:
python3 inference.py --engine vllm --image assets/<图片> --mode score| 用例 | 测试图片 | 内容 | 输出评分 | 状态 |
|---|---|---|---|---|
| 31 | iqa_gradient.png | 平滑渐变图 | <answer>3.80</answer> | ✅ |
| 32 | iqa_jpeg.jpg | 几何图 + JPEG(质量8) | <answer>2.50</answer> | ✅ |
| 33 | iqa_test1.png | 红圆+蓝矩形+绿线 | <answer>2.00</answer> | ✅ |
| 34 | iqa_lowres.png | 几何图 低分辨率 | <answer>2.00</answer> | ✅ |
| 35 | iqa_noise.png | 几何图 + 高斯噪声 | <answer>1.00</answer> | ✅ |
| 36 | iqa_blur.png | 几何图 + 高斯模糊 | <answer>0.00</answer> | ✅ |
用例 37:城市原图质量描述
python3 inference.py --engine vllm --image assets/photo_city_orig.jpg --mode describe --max-new-tokens 128输出:
### Image Quality Assessment
#### Description:
The image appears to be a stylized representation of a cityscape at night, with buildings depicted
using a grid-like pattern of yellow and blue dots. The background is a solid dark blue, which contrasts
with the illuminated buildings.
#### Quality Issues:
1. **Artistic Style vs. Clarity**: The image is intentionally designed with a pixelated or dot matrix
style ... However, this style can sometimes be confusing for viewers who expect a more realistic or
high-resolution image.
2. **Color Consistency**: The colors used for the buildings (yellow and blue) are consistent and distinct
against the dark background ...
3. **Resolution and Detail**: The image lacks fine detail and sharpness ...✅ 结构化描述(Description / Quality Issues / Rating)输出正常。
用例 38:城市重度模糊质量描述
python3 inference.py --engine vllm --image assets/photo_city_blur_heavy.jpg --mode describe --max-new-tokens 128输出:
### Image Quality Assessment
#### Description:
The provided image appears to be intentionally blurred or out of focus. The lack of sharpness makes it
difficult to discern any specific details or features within the image. The colors seem to be muted and
there is no clear subject or object that can be identified due to the blurriness.
#### Quality Issues:
1. **Blurriness/Focus**: The entire image is out of focus, which significantly reduces its clarity and detail.
2. **Lack of Detail**: Due to the blurriness, there is no discernible texture or fine details ...
3. **Color Muting**: The colors appear to be subdued and lack vibrancy ...
4. **Lack of Context**: Without clear details or identifiable elements, it is challenging to determine ...✅ 正确识别出"重度模糊 / 失焦 / 细节缺失"等质量缺陷。
用例 39:城市重度噪声质量描述
python3 inference.py --engine vllm --image assets/photo_city_noise_heavy.jpg --mode describe --max-new-tokens 128输出:
### Image Quality Assessment
#### Description:
The image appears to be a pixelated or heavily compressed representation of text. The text is not legible
due to the high level of noise and pixelation. The colors are primarily shades of blue and yellow ...
#### Quality Issues:
1. **Pixelation**: The image is highly pixelated, making it difficult to discern any details or text.
2. **Noise**: There is significant noise present, which further obscures any potential details or patterns.
3. **Color Consistency**: The colors are not uniform and appear to be randomly distributed, which is
typical for heavily compressed or corrupted images.
...✅ 正确识别出"像素化 / 噪声 / 颜色分布不均"等缺陷。
统一命令:
python3 inference.py --engine vllm --mode chat --prompt "<问题>" --max-new-tokens <N>| 用例 | 输入问题 | 输出结果 | 状态 |
|---|---|---|---|
| 40 | What is the capital of France? Answer in one word. | Paris | ✅ |
| 41 | A train travels 120 km in 2 hours. What is its average speed in km/h? | To determine the average speed ... v = Total Distance / Total Time ...(数学推理完整) | ✅ |
| 42 | 用一句中文回答:太阳系有几颗行星? | 太阳系有八颗行星。 | ✅ |
| 43 | Write a Python one-liner to compute the mean of a list. | mean = sum(lst) / len(lst) | ✅ |
| 44 | If all roses are flowers and some flowers fade quickly, can we conclude that some roses fade quickly? | Yes, because if all roses are flowers and some flowers fade quickly, then by the transitive property of inclusion, it follows that some roses must also fade quickly. | ✅ |
| 45 | Translate "The quality of this photograph is excellent" into Chinese. | 这张照片的质量非常好。 | ✅ |
| 46 | What is 17 * 8? Answer with just the number. | 136 | ✅ |
统一命令(模型常驻,连续推理):
python3 inference.py --engine torch_npu --device npu:0 --image assets/<图片> --mode <score|describe|chat>| 用例 | 测试图片 / 输入 | 模式 | 输出结果 | 状态 |
|---|---|---|---|---|
| 47 | photo_city_orig.jpg | score | <answer>3.50</answer>(11 tok, 1.08s) | ✅ |
| 48 | photo_city_blur_heavy.jpg | score | <answer>0.00</answer>(11 tok, 0.54s) | ✅ |
| 49 | photo_city_noise_mild.jpg | score | <answer>2.00</answer>(11 tok, 0.55s) | ✅ |
| 50 | photo_city_jpeg.jpg | score | <answer>2.00</answer>(11 tok, 0.54s) | ✅ |
| 51 | photo_landscape_orig.jpg | score | <answer>1.00</answer>(11 tok, 0.55s) | ✅ |
| 52 | photo_portrait_orig.jpg | score | <answer>0.50</answer>(11 tok, 0.55s) | ✅ |
| 53 | photo_city_orig.jpg | describe | ### Image Quality Assessment\n#### Description: ...(128 tok, 4.31s) | ✅ |
| 54 | prompt: What is the capital of France? | chat | Paris(2 tok, 0.07s) | ✅ |
说明:torch_npu 与 vllm-ascend 对同一图像的评分存在轻微差异(如城市原图 torch_npu 3.50 vs vllm 3.80),源于两引擎解码参数(采样策略/温度)默认值不同, 属正常现象,质量排序结论一致。
| 分类 | 用例区间 | 数量 |
|---|---|---|
| 环境与模型加载校验 | 1–3 | 3 |
| vllm-ascend 多模态 IQA 打分 | 4–30 | 27 |
| vllm-ascend 合成图像打分 | 31–36 | 6 |
| vllm-ascend 质量描述/推理 | 37–39 | 3 |
| vllm-ascend 纯文本能力 | 40–46 | 7 |
| torch_npu 引擎验证 | 47–54 | 8 |
| 合计 | 54 |
本机未安装 sglang,故 inference.py --engine sglang 会打印安装与启动指引后返回。
社区版 sglang-ascend 已支持 Qwen2.5-VL,
安装并启动后(见 4.4 节)即可通过 OpenAI 兼容接口调用,不影响本模型在其他两引擎下的运行。
模型对重度失真图像(如重度模糊/噪声)可能输出 <answer>0.00</answer>,略低于提示词中
"1 表示极差"的下界。这是 R1-IQA 类模型对极端失真图像的真实行为,与 NPU 适配无关;
使用方若需严格落在 1~5 区间,可在后处理中 clamp(score, 1, 5)。
photo_landscape / photo_portrait / iqa_* 为程序化生成的测试图,非真实照片,
模型对其自然度评分整体偏低(0~2 区间)。测试集设计以"相对质量排序"为准绳验证 IQA
判别力,真实照片的绝对评分更具参考价值。
8.3B 模型 bf16 权重约 16 GB,vllm-ascend 服务常驻约 10~12 GB 显存。若在同一物理卡上 同时启动 vllm 服务并再用 torch_npu 加载模型,将触发 NPU OOM。本机共 2 张 Ascend 910B, 建议 vllm 服务占用卡 0、torch_npu 推理使用卡 1(见 4.2 / 4.3 节的环境变量设置), 单引擎单独运行时单卡即可容纳。
Qwen2_5_VLForConditionalGeneration 已注册于 vLLM 模型注册表
(vllm/model_executor/models/registry.py),vllm-ascend 0.18.0 将其列为 core 支持
(见 vllm-ascend supported-models,Qwen2.5-VL ✅,含 BF16 / W8A8 / Chunked Prefill / LoRA)。
本适配无需修改任何建模代码,纯推理侧适配。Qwen2_5_VLProcessor),图像经 --trust-remote-code 由本地 processor 文件加载,
无需联网。<answer> 标签中",
inference.py --mode score 已内置该模板,保证输出可直接用正则解析出分数。# 1) 进入仓库并激活 venv
cd /opt/atomgit/model_adapt/VisualQuality-R1-7B-NPU
source venv/bin/activate
# 2) 安装依赖(国内镜像,仅首次需要)
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 3) 环境自检
export ASCEND_RT_VISIBLE_DEVICES=0
python3 inference.py --list-devices
# 4) vllm-ascend 服务化(推荐)
vllm serve /data/models/TianheWu/VisualQuality-R1-7B \
--dtype bfloat16 --tensor-parallel-size 1 --max-model-len 32768 \
--trust-remote-code --port 8000 --served-model-name VisualQuality-R1-7B &
python3 inference.py --engine vllm --image assets/photo_city_orig.jpg --mode score
# 5) torch_npu 直接推理
python3 inference.py --image assets/photo_city_orig.jpg --mode score
python3 inference.py --image assets/photo_city_blur_heavy.jpg --mode describe
python3 inference.py --mode chat --prompt "What is the capital of France?"贡献者:model-adapt 适配团队 | 赛道:模型适配赛道 | 引擎:torch_npu + vllm-ascend | 设备:Ascend 910B