x
This commit is contained in:
+145
-1
@@ -381,4 +381,148 @@ ENV ... \
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*最后更新: 2026-06-17*
|
## 7. 运行时类
|
||||||
|
|
||||||
|
### 7.1 vllm `_version.py` 缺失导致 `InvalidVersion: 'dev'`
|
||||||
|
|
||||||
|
**现象**:镜像构建成功,WebUI 启动正常,但解析任务全部失败:
|
||||||
|
|
||||||
|
```
|
||||||
|
File ".../mineru/backend/vlm/utils.py", line 88, in set_default_gpu_memory_utilization
|
||||||
|
if version.parse(vllm_version) >= version.parse("0.11.0") and gpu_memory <= 8:
|
||||||
|
│ │ └ 'dev'
|
||||||
|
packaging.version.InvalidVersion: Invalid version: 'dev'
|
||||||
|
```
|
||||||
|
|
||||||
|
日志开头同时有信号:
|
||||||
|
|
||||||
|
```
|
||||||
|
/opt/vllm/vllm/__init__.py:7: RuntimeWarning: Failed to read commit hash:
|
||||||
|
No module named 'vllm._version'
|
||||||
|
vllm runtime import OK: dev, platform=UnspecifiedPlatform
|
||||||
|
```
|
||||||
|
|
||||||
|
**原因**:阶段 8b 跳过了 `pip install -e .`(见 6.1 节),而 `setuptools_scm` 正是在 `pip install -e .` 时生成 `vllm/_version.py`。该文件缺失后,vllm 的 `version.py` 回退成 `__version__ = 'dev'`。`'dev'` 不是合法 PEP 440 版本号,mineru 调 `packaging.version.parse('dev')` 即抛 `InvalidVersion`,导致每个解析任务必失败。
|
||||||
|
|
||||||
|
**解决**:阶段 8b 手写 `vllm/_version.py`,替代 `setuptools_scm` 生成:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# 阶段 8b(egg-info 创建之后):
|
||||||
|
printf '__version__ = "0.11.0"\n__version_tuple__ = (0, 11, 0)\n' > /opt/vllm/vllm/_version.py
|
||||||
|
```
|
||||||
|
|
||||||
|
同时在 `patch_vllm_platform.py` 的 `ensure_vllm_dist_info()` 中对 `vllm.__version__` 做 PEP 440 合法性校验,非法时回退安全值 `0.11.0` 并回写 `vllm.__version__`(兜底,防止上游 version.py 再改回退逻辑)。
|
||||||
|
|
||||||
|
**版本号选 `0.11.0` 的理由**:
|
||||||
|
- 合法 PEP 440,`packaging.version.parse` 不报错
|
||||||
|
- 满足 `mineru[vllm]` 的约束 `>=0.10.1.1,<0.22.0`
|
||||||
|
- mineru 代码 `version.parse(vllm_version) >= version.parse("0.11.0")` 走新分支(更合理的 GPU 显存策略)
|
||||||
|
|
||||||
|
**注意**:`mineru[core]`(Dockerfile 阶段 9 安装的)= vlm + pipeline + gradio,**不包含 `mineru[vllm]`**,因此 vllm 版本约束不会触发 pip 依赖冲突——editable 注册的假版本号只要功能上不被校验即可,而 `0.11.0` 恰好让校验逻辑走正确分支。
|
||||||
|
|
||||||
|
### 7.2 amdsmi 缺失导致 `Device string must not be empty`
|
||||||
|
|
||||||
|
**现象**:7.1 修复后(`vllm runtime import OK: 0.11.0`),解析任务在模型初始化阶段失败:
|
||||||
|
|
||||||
|
```
|
||||||
|
File ".../vllm/config/device.py", line 78, in __post_init__
|
||||||
|
self.device = torch.device(self.device_type)
|
||||||
|
RuntimeError: Device string must not be empty
|
||||||
|
```
|
||||||
|
|
||||||
|
启动日志里同时有:
|
||||||
|
|
||||||
|
```
|
||||||
|
WARNING [rocm.py:39] Failed to import from amdsmi: No module named 'amdsmi'
|
||||||
|
vllm runtime import OK: 0.11.0, platform=UnspecifiedPlatform
|
||||||
|
WARNING: vLLM platform detection returned UnspecifiedPlatform.
|
||||||
|
```
|
||||||
|
|
||||||
|
**原因**:vllm main 的 ROCm 平台检测依赖 `amdsmi`。检测链:
|
||||||
|
|
||||||
|
1. `resolve_current_platform_cls_qualname()` 遍历 `builtin_platform_plugins`,调用 `rocm_platform_plugin()`
|
||||||
|
2. `rocm_platform_plugin()` 内部 `import amdsmi` → 失败(except)→ `is_rocm=False` → 返回 `None`
|
||||||
|
3. 无任何 builtin plugin 激活 → `platform_cls_qualname = "vllm.platforms.interface.UnspecifiedPlatform"`
|
||||||
|
4. `current_platform.device_type = ''` → `torch.device('')` 抛 `Device string must not be empty`
|
||||||
|
|
||||||
|
`amdsmi` 缺失的根因:阶段 6.5 的条件安装 `if [ -d /opt/rocm/share/amd_smi ]`,**ROCm 7.2 的 apt 包不再提供该目录**(`pip list` 无 amdsmi、`/opt/rocm/share/amd_smi` 不存在、dpkg 无 amdsmi 包),安装被跳过。
|
||||||
|
|
||||||
|
> 注:`rocm_platform_plugin` 定义在 `platforms/__init__.py`(第 111 行附近),**不是** `platforms/rocm.py`。早期补丁脚本尝试 `from vllm.platforms.rocm import rocm_platform_plugin` 注册 entry_point,路径错误导致 `ImportError`——这是 entry_point 注册失败的根因,但本方案不依赖 entry_point,改走 builtin plugin 修复。
|
||||||
|
|
||||||
|
**解决**:在 `patch_vllm_platform.py` 的补丁 6 中,向 `rocm_platform_plugin()` 的 `return` 语句前注入 `torch.version.hip` 兜底:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# __init__.py 中 rocm_platform_plugin 的 return 前:
|
||||||
|
if not is_rocm:
|
||||||
|
try:
|
||||||
|
import torch as _torch
|
||||||
|
if _torch.version.hip is not None:
|
||||||
|
is_rocm = True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return "vllm.platforms.rocm.RocmPlatform" if is_rocm else None
|
||||||
|
```
|
||||||
|
|
||||||
|
amdsmi 缺失时 `is_rocm=False`,补丁用 `torch.version.hip` 翻转为 `True` → 返回 `RocmPlatform` → `device_type='cuda'` → 错误消失。
|
||||||
|
|
||||||
|
**关键实现细节**(补丁 6 多次失效的教训):
|
||||||
|
- **不能用精确字符串匹配**。vllm main 频繁重构,引号风格、空格、行结构都会变。早期补丁用 `old = " return 'vllm.platforms.rocm.RocmPlatform' if is_rocm else None"`(单引号)匹配,但实际文件是双引号,导致 `pattern not found`。
|
||||||
|
- **改用语义定位**:遍历行,找同时含 `RocmPlatform` + `return` + `is_rocm` 的行作为注入点,取该行缩进对齐。兼容单/双引号。
|
||||||
|
- 幂等:注入前检查文件内是否已有 `torch.version.hip is not None`,避免重复注入。
|
||||||
|
|
||||||
|
**验证**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec mineru-gradio /opt/mineru_venv/bin/python -c "
|
||||||
|
from vllm.platforms import current_platform
|
||||||
|
print('platform:', type(current_platform).__name__)
|
||||||
|
print('device_type:', repr(current_platform.device_type))
|
||||||
|
"
|
||||||
|
# 期望:platform: RocmPlatform / device_type: 'cuda'
|
||||||
|
```
|
||||||
|
|
||||||
|
**放弃的方案**:`sitecustomize.py` 运行时强制注入 `current_platform`。失败原因:`current_platform` 是 lazy init(首次访问才 resolve),sitecustomize 在 Python 启动最早期执行时触发提前 resolve,而那时补丁 6 尚未应用(或被 `except: pass` 吞错),赋值后可能被后续逻辑覆盖。改 builtin plugin 本体(补丁 6)才是 vllm 官方检测路径,最干净。
|
||||||
|
|
||||||
|
### 7.3 热修复与镜像固化的操作流程
|
||||||
|
|
||||||
|
容器运行中(不重建镜像)热修复时注意:
|
||||||
|
|
||||||
|
1. **`./scripts:/opt/scripts:ro` 是只读卷挂载**(见 `docker-compose.yml`)。`docker cp` 写 `/opt/scripts` 会报 `mounted volume is marked read-only`。但容器内 `/opt/scripts` 直接映射宿主机 `./scripts`,**改宿主机文件即生效**,无需 `docker cp`。
|
||||||
|
2. **`/opt/vllm` 在镜像层**(非只读挂载),可直接 `docker exec` 写入,重启不丢失。
|
||||||
|
3. 补丁脚本幂等且检测 `already applied`,重启容器重跑 entrypoint 不会撤销已注入的改动。
|
||||||
|
|
||||||
|
完整固化流程(让修复进入镜像):
|
||||||
|
- 修改 `Dockerfile` 阶段 8b(写 `_version.py` + egg-info 用 `0.11.0`)
|
||||||
|
- 修改 `scripts/patch_vllm_platform.py`(补丁 6 语义定位 + PEP 440 校验)
|
||||||
|
- 重建镜像(8a 的 ninja 编译层有缓存,几分钟):
|
||||||
|
```bash
|
||||||
|
docker compose build && docker compose --profile gradio up -d --force-recreate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 模型架构 inspect 失败(待解决)
|
||||||
|
|
||||||
|
**现象**:7.1、7.2 修复后(`platform=RocmPlatform`),解析任务在 vllm 加载模型阶段失败:
|
||||||
|
|
||||||
|
```
|
||||||
|
1 validation error for ModelConfig
|
||||||
|
Value error, Model architectures ['Qwen2VLForConditionalGeneration']
|
||||||
|
failed to be inspected. Please check the logs for more details.
|
||||||
|
```
|
||||||
|
|
||||||
|
启动日志同时有:
|
||||||
|
|
||||||
|
```
|
||||||
|
WARNING [config.py:71] Support for Transformers v4 is deprecated.
|
||||||
|
The Transformers v4 codepath will become unmaintained in vLLM v0.22.0
|
||||||
|
... Please upgrade to Transformers v5: pip install --upgrade transformers
|
||||||
|
```
|
||||||
|
|
||||||
|
**初步判断**:transformers 版本与 vllm main 的模型 inspect 逻辑不兼容。矛盾在于:
|
||||||
|
- vllm 提示升级到 transformers v5
|
||||||
|
- `mineru[pipeline]` 依赖锁死 `transformers<5.0.0,>=4.57.3`(强制 v4)
|
||||||
|
|
||||||
|
待诊断(确认实际版本、Qwen2VL 是否在 transformers 注册表、inspect 真实报错)后再补最终方案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*最后更新: 2026-06-23*
|
||||||
|
|||||||
@@ -101,6 +101,56 @@ def patch7_rocm_break_import_cycle():
|
|||||||
print('Patch 7: already applied or pattern not found.')
|
print('Patch 7: already applied or pattern not found.')
|
||||||
|
|
||||||
|
|
||||||
|
def patch9_registry_model_impl_compat():
|
||||||
|
"""补丁 9:registry.py —— vllm main 与 transformers v4 兼容
|
||||||
|
|
||||||
|
问题:vllm main 的 ModelRegistry 大量访问 model_config.model_impl,
|
||||||
|
该属性是 vllm ModelConfig 的字段(默认 "auto"),但 inspect 链路传入的
|
||||||
|
有时是 transformers config 对象(如 Qwen2VLConfig),v4 没有此属性 →
|
||||||
|
AttributeError → "Model architectures [...] failed to be inspected"。
|
||||||
|
同时 _try_resolve_transformers 末尾调用 model_config._get_transformers_backend_cls(),
|
||||||
|
v4 的 config 也没有该方法。
|
||||||
|
|
||||||
|
根因:mineru[core] 锁定 transformers<5.0.0(v4),vllm main 期望 v5。
|
||||||
|
本补丁把所有 model_config.model_impl 访问改成 getattr 兜底(缺属性时当 "auto",
|
||||||
|
走 fallback 分支匹配 vllm 注册表),并给 _get_transformers_backend_cls 加兜底。
|
||||||
|
|
||||||
|
采用逐处 getattr 替换,不依赖方法定位(比方法注入更可靠)。
|
||||||
|
"""
|
||||||
|
f = os.path.join(VLLM_DIR, 'model_executor', 'models', 'registry.py')
|
||||||
|
if not os.path.exists(f):
|
||||||
|
print('Patch 9: registry.py not found; skipping.')
|
||||||
|
return
|
||||||
|
c = open(f).read()
|
||||||
|
if '# mineru-rocm: model_impl v4 compat' in c:
|
||||||
|
print('Patch 9: already applied (model_impl v4 compat present).')
|
||||||
|
return
|
||||||
|
|
||||||
|
# 把 model_config.model_impl 访问替换为 getattr 兜底
|
||||||
|
before = c.count('model_config.model_impl')
|
||||||
|
c2 = c.replace(
|
||||||
|
'model_config.model_impl',
|
||||||
|
'getattr(model_config, "model_impl", "auto")'
|
||||||
|
)
|
||||||
|
replaced = before - c2.count('model_config.model_impl')
|
||||||
|
|
||||||
|
# _get_transformers_backend_cls 兜底:v4 无此方法
|
||||||
|
c2 = c2.replace(
|
||||||
|
'return model_config._get_transformers_backend_cls()',
|
||||||
|
'return getattr(model_config, "_get_transformers_backend_cls", lambda: None)()'
|
||||||
|
)
|
||||||
|
|
||||||
|
# 写入幂等标记(注释,便于重入检测)
|
||||||
|
c2 = '# mineru-rocm: model_impl v4 compat\n' + c2
|
||||||
|
|
||||||
|
if c2 != c:
|
||||||
|
open(f, 'w').write(c2)
|
||||||
|
print(f'Patch 9: registry.py model_impl v4 compat applied '
|
||||||
|
f'({replaced} access(es) wrapped).')
|
||||||
|
else:
|
||||||
|
print('Patch 9: no changes applied (pattern not found).')
|
||||||
|
|
||||||
|
|
||||||
def ensure_vllm_dist_info():
|
def ensure_vllm_dist_info():
|
||||||
"""为 /opt/vllm 源码导入创建最小 dist-info。
|
"""为 /opt/vllm 源码导入创建最小 dist-info。
|
||||||
|
|
||||||
@@ -233,6 +283,7 @@ def install_sitecustomize_force_rocm():
|
|||||||
def main():
|
def main():
|
||||||
patch6_init_platform_fallback()
|
patch6_init_platform_fallback()
|
||||||
patch7_rocm_break_import_cycle()
|
patch7_rocm_break_import_cycle()
|
||||||
|
patch9_registry_model_impl_compat()
|
||||||
install_sitecustomize_force_rocm()
|
install_sitecustomize_force_rocm()
|
||||||
try:
|
try:
|
||||||
ensure_vllm_installed()
|
ensure_vllm_installed()
|
||||||
|
|||||||
Reference in New Issue
Block a user