容器化TorchServe Worker启动时自动下载额外模型权重问题
自动下载resnet50权重的行为和TorchServe的mar包打包机制无关,触发点是模型初始化代码的默认逻辑。
你调用torchvision提供的fasterrcnn_resnet50_fpn接口时,默认参数pretrained_backbone=True会触发torchvision的权重校验逻辑:自动检查/home/model-server/.cache/torch/hub/checkpoints/路径下是否存在哈希匹配的resnet50-0676ba61.pth文件,文件不存在或哈希不匹配就会自动从官方源拉取。
mar包内的文件在服务启动时只会被解压到TorchServe为每个模型分配的临时工作目录,不会被自动加入torchhub的缓存搜索路径,因此即使你把权重打进mar包,torchvision的默认加载逻辑也感知不到文件存在。
- 将resnet50权重作为extra-files打入mar包:extra-files仅会被解压到模型临时工作目录,你没有在模型加载代码中显式指定从该路径读取backbone权重,torchvision的自动下载逻辑不会检索这个路径。
- 用resnet50权重替换完整Faster R-CNN主权重:
fasterrcnn_resnet50_fpn_coco-258fb6c6.pth是包含backbone、FPN、RPN、检测头的完整检测模型权重,resnet50-0676ba61.pth仅为backbone部分的权重,直接替换会导致权重加载时参数键不匹配,代码会回退到默认的预训练backbone加载逻辑,触发下载。
二选一即可:
方案1:修改模型加载逻辑(推荐,无额外构建步骤)
调整model.py中的模型初始化代码,显式关闭自动预训练权重下载,从mar包内的本地路径加载完整权重,示例代码:
import os import torch from torchvision.models.detection import fasterrcnn_resnet50_fpn def model_fn(model_dir): # 初始化模型时关闭所有默认预训练权重加载,禁止自动下载 model = fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False) # 显式从mar包解压目录加载完整Faster R-CNN权重 weight_path = os.path.join(model_dir, "fasterrcnn_resnet50_fpn_coco-258fb6c6.pth") model.load_state_dict(torch.load(weight_path, map_location="cpu")) model.eval() return model
重新打包mar包时无需额外传入resnet50权重,常规打包即可:
torch-model-archiver \ --model-name fastrcnn \ --version 1.0 \ --serialized-file fasterrcnn_resnet50_fpn_coco-258fb6c6.pth \ --handler object_detector \ --extra-files index_to_name.json,model.py \ --export-path model-store \ --force
方案2:构建镜像时提前预热缓存
如果不想修改模型代码,可以在Dockerfile构建阶段直接把resnet50权重预置到torchhub的默认缓存目录,示例配置:
# 创建torchhub缓存目录 RUN mkdir -p /home/model-server/.cache/torch/hub/checkpoints/ # 将本地准备好的对应版本resnet50权重拷贝到缓存目录 COPY resnet50-0676ba61.pth /home/model-server/.cache/torch/hub/checkpoints/ # 配置权限保证model-server用户可读 RUN chown -R model-server:model-server /home/model-server/.cache/
TorchServe的mar包本质是zip格式的归档文件,打包逻辑仅负责将你指定的文件整合到压缩包内,不会自动修改你自定义的模型加载代码,也不会自动将包内文件注册到第三方库(torchvision、huggingface transformers等)的默认搜索路径。所有包内的自定义文件,都需要在加载代码中通过model_dir(mar包解压后的根目录)显式拼接路径读取,不要依赖第三方库的默认自动下载、缓存检索逻辑。
内容的提问来源于stack exchange,提问作者VEHC

