Immich 机器学习服务实践:环境搭建、Locust 推理负载测试与源码级实现解析
发布时间:2026/9/7 8:33:05 锦皓数字建站

Immich 机器学习服务实践环境搭建、Locust 推理负载测试与源码级实现解析【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich本文基于 immich 仓库中的 machine-learning/README_es_ES.md 文档展开系统讲解 Immich 机器学习服务的核心能力CLIP 嵌入、人脸识别、Python 开发环境搭建方法以及如何用 Locust 对推理接口做吞吐与延迟压测并结合immich_ml源码剖析其服务启动方式、模型缓存与推理请求处理链路帮助你在自部署 Immich 时理解并调优 ML 组件。一、Immich 机器学习服务负责什么README_es_ES.md 开头列出了该服务的三项核心能力西班牙语原文Clasificación de imágenes图像理解/分类Incorporación de CLIPCLIP 嵌入Reconocimiento facial人脸识别也就是说machine-learning/是 Immich 中独立运行的 Python 推理服务Web 主服务在后台任务中把图像或文本发送给它由它返回 CLIP 向量与人脸检测结果。从源码结构看模型实现位于 immich_ml/models/ 下与文档列出的能力一一对应CLIP 文本/视觉编码textual.py、visual.py人脸检测与识别detection.py、recognition.py。需要说明的是该西语文档是早期版本的翻译版其中部分工具链描述见下文“环境搭建”一节已被仓库现状更新涉及命令与依赖管理时本文以当前仓库实际内容为准。二、环境搭建文档中的 Poetry 流程与当前仓库的 uv 现状2.1 文档描述的原始流程README_es_ES.md 给出的搭建步骤如下原文为西班牙语此处附译本项目使用 Poetry请先安装。运行poetry install --no-root --with dev会在一个隔离的虚拟环境中安装所需的一切。 添加或删除依赖分别使用poetry add $PACKAGE_NAME和poetry remove $PACKAGE_NAME提交代码时务必一并提交poetry.lock与pyproject.toml两个文件以反映依赖变化。其要点可以归纳为三条使用 Python 包管理器创建隔离虚拟环境避免污染系统环境dev额外依赖组中包含压测与测试工具当前仓库对应依赖组为dev其中含locust、pytest、mypy、ruff见 pyproject.toml 中[dependency-groups]一节锁文件必须入库保证任何人拉取代码后装出的依赖版本一致。2.2 当前仓库的实际工具链uv 与硬件加速 extra当前仓库已迁移到 uv且存在uv.lock而没有poetry.lock因此实际执行时请以 README.md英文版为准uv sync --extra cpu该命令会依据pyproject.toml在隔离虚拟环境中安装全部依赖。--extra cpu安装的是 CPU 版onnxruntime若需要硬件加速 API可替换为以下任一 extra取自 pyproject.toml 的[project.optional-dependencies]extra 名称对应依赖适用场景cpuonnxruntime1.23.2,2通用 CPU 推理cudaonnxruntime-gpuNVIDIA GPU要求 compute capability ≥ 5.2rocmonnxruntime-migraphxAMD ROCm 平台openvinoonnxruntime-openvinoIntel OpenVINO 平台armnn/rknnonnxruntimerknn-toolkit-lite2ARM / 瑞芯微 NPU添加、移除依赖对应uv add $PACKAGE_NAME/uv remove $PACKAGE_NAME然后用uv lock生成锁文件并把uv.lock与pyproject.toml一起提交——这与西语文档强调“锁文件必须入库”的原则完全一致。三、用 Locust 做推理负载测试这是 README_es_ES.md 的“Pruebas de carga负载测试”一节的核心内容也是该文档最具实操价值的部分。3.1 测试原理与前提原文要点要测量推理的速度吞吐与延迟可以使用 Locust 配合仓库提供的locustfile.py。Locust 通过查询模型端点并聚合统计结果工作因此应用必须先已部署运行。文档还提到可运行load_test.sh自动在本地拉起应用并启动 Locust该脚本在当前仓库中已不再存在现在可直接运行 Locust见下节也可以直接运行locust做更自定义的压测。“应用必须已部署”这一前提可以从源码得到印证locustfile.py 中的测试用户把目标固定为本地的 ML 服务地址class InferenceLoadTest(HttpUser): abstract: bool True host http://127.0.0.1:3003 # Immich ML 默认监听端口这与 config.py 中NonPrefixedSettings的默认端口immich_port: int 3003一致。3.2 locustfile.py 的完整结构locustfile.py 通过 Locust 的命令行参数钩子暴露 4 个可调参数parser.add_argument(--clip-model, typestr, defaultViT-B-32::openai) parser.add_argument(--face-model, typestr, defaultbuffalo_l) parser.add_argument( --face-min-score, typeint, default0.034, helpReturns all faces at or above this score. The default returns 1 face per request; setting this to 0 blows up the number of faces to the thousands., ) parser.add_argument(--image-size, typeint, default1000)--clip-model压测使用的 CLIP 模型默认ViT-B-32::openai--face-model人脸识别模型默认buffalo_l--face-min-score人脸检测置信度阈值默认0.034注释明确说明“设为 0 会使人脸数量暴增至数千个”可用于压测更重的检测负载--image-size压测图片边长默认 1000×1000 像素的纯色 JPEG。测试启动时通过test_start事件生成一张 JPEG 并序列化到内存所有用户实例共享同一份字节数据以节省开销events.test_start.add_listener def on_test_start(environment: Environment, **kwargs: Any) - None: global byte_image image Image.new(RGB, (size, size)) image.save(byte_image, formatjpeg)随后定义了三个HttpUser子类分别对应文档所说的“三个端点”实际都打到/predict只是负载类型不同CLIPTextFormDataLoadTest——POST/predict携带clip.textual请求与text表单字段压测文本编码CLIPVisionFormDataLoadTest——POST/predict携带clip.visual请求与image文件字段压测图像编码RecognitionFormDataLoadTest——POST/predict同时携带facial-recognition.recognition与facial-recognition.detection两个条目后者带minScore选项压测人脸检测 识别。这些请求体的字段结构不是凭空设计的而是与 main.py 中/predict接口的签名一一对应app.post(/predict, dependencies[Depends(update_state)]) async def predict( entries: InferenceEntries Depends(get_entries), image: bytes | None File(defaultNone), text: str | None Form(defaultNone), ) - Any:其中entries是一个 JSON 字符串按“任务 → 类型 → 条目”组织get_entries会把它解析为(without_deps, with_deps)两类推理条目并做 Pydantic 校验main.py。3.3 运行方式按 README.md 的当前说明启动压测只需locust --web-host 127.0.0.1然后打开浏览器访问localhost:8089进入 Locust Web UI在界面上设置并发用户数与启动速率还可以调整模型或评分阈值等选项。3.4 并发数换算文档给出的关键经验公式README_es_ES.md 特别强调的一条注意事项原文照录其含义在 Locust 的术语中并发以users用户数衡量且每个用户同一时刻只执行一个任务。要达成某个“单端点并发”需把目标值乘以要查询的端点数。例如有 3 个端点、希望每个端点同时收到 8 个请求则应把用户数设为 24。这条公式对压测结果解读非常关键locustfile 中定义了 3 个用户类Locust 会把用户均分到各类报告中“总请求数/吞吐量”是三者叠加后的数值。若想单独评估某个模型端点的表现应按上述公式反推该端点实际承担的并发必要时可以只保留一个用户类再跑。四、服务是怎么跑起来的从源码看启动链路压测前提是“应用已部署”。下面结合源码说明 ML 服务的启动与运行机制这也是自部署Docker时排查问题的基础。4.1 入口Gunicorn 自定义 Uvicorn WorkerDocker 镜像的启动命令是python -m immich_ml见 Dockerfile 的CMD。main.py 随即以子进程方式拉起 Gunicorn并把 FastAPI 应用immich_ml.main:app交给自定义 workersubprocess.Popen( [python, -m, gunicorn, immich_ml.main:app, -k, immich_ml.config.CustomUvicornWorker, -b, bind_address, # 默认 [::]:3003 -w, str(settings.workers), # 默认 1 -t, str(settings.worker_timeout), ...] )几个值得注意的实现细节多 worker 的 GPU 轮转分配gunicorn_conf.py 在pre_fork钩子里按 worker 序号对MACHINE_LEARNING_DEVICE_IDS逗号分隔的设备列表取模给每个 worker 分配一个推理设备实现多卡轮询ROCm 平台超时放宽config.py 中worker_timeout在DEVICErocm时为 900 秒否则 300 秒避免模型首次加载超时被 Gunicorn 误杀。4.2 可配置项环境变量config.py 用 pydantic-settings 声明了全部配置环境变量前缀为MACHINE_LEARNING_。与压测和自部署最相关的默认值如下配置项环境变量默认值作用workersMACHINE_LEARNING_WORKERS1Gunicorn 进程数model_ttlMACHINE_LEARNING_MODEL_TTL300秒模型空闲 TTL超时后进程自杀释放显存/内存request_threadsMACHINE_LEARNING_REQUEST_THREADSCPU 核数推理线程池大小cache_folderMACHINE_LEARNING_CACHE_FOLDER~/.cache/immich_ml模型缓存目录Docker 内为/cachemodel_arenaMACHINE_LEARNING_MODEL_ARENATrueONNX Runtime 内存 arena 开关Docker 中默认关闭4.3 推理请求处理链与空闲退出/predict收到请求后的完整链路main.py校验输入image与text二选一空维度图像直接返回 400run_inference先执行无依赖条目、再执行有依赖条目例如人脸识别的 recognition 依赖 detection 的输出每类条目用asyncio.gather并发处理每个条目先从ModelCache按(name, type, task, options)取模型带model_ttl失效策略必要时经全局锁加载进内存阻塞型推理统一投递到ThreadPoolExecutormain.py避免 asyncio 成为吞吐瓶颈。另外update_state依赖会维护active_requests计数与最后调用时间idle_shutdown_taskmain.py周期性检查若无活跃请求且距上次调用超过model_ttl就向自身发送SIGINT优雅退出把显存/内存交还给系统——这对长期空闲的自部署实例省资源很有意义容器编排层只需自动重启即可。压测时该参数意味着长时间不请求后首个请求会重新触发模型加载解读延迟数据时要留意。五、小结README_es_ES.md 的核心价值在于两点ML 服务的功能边界CLIP 嵌入 人脸识别与 Locust 压测方法含“用户数 单端点并发 × 端点数”的换算公式工具链以当前仓库为准uv sync --extra cpu/cuda/rocm/openvinouv.lock入库替代了文档中的 Poetry 命令压测入口是 locustfile.py目标端点为http://127.0.0.1:3003/predict可通过--clip-model、--face-model、--face-min-score、--image-size四个参数定制负载服务由main.py 以 Gunicorn 自定义 Uvicorn worker 启动设备分配、空闲退出、线程池等关键机制均可在 immich_ml/main.py 与 immich_ml/config.py 中查证。【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。