SageMaker部署SpaCy模型端点时遇CannotStartContainerError错误求助
排查AWS SageMaker部署SpaCy模型端点失败的问题
问题根源分析
出现CannotStartContainerError的核心原因是容器不符合SageMaker推理容器规范,同时代码和配置存在多处错误:
- 未实现SageMaker推理接口:SageMaker启动容器时会执行
docker run <image> serve命令,要求容器启动HTTP服务监听8080端口,处理/ping(健康检查)和/invocations(推理请求)两个端点。当前配置直接运行脚本,未处理serve参数也未启动服务。 - 模型路径错误:SageMaker会自动将S3中的
model.tar.gz解压到容器内的/opt/ml/model目录,而代码中写的./model/modelo路径不匹配。 - 依赖不匹配:Dockerfile中安装的是
en_core_web_sm,但代码调用的是es_core_news_sm,会导致模型加载失败。 - 调试代码报错:代码中使用
spacy.displacy.render(doc, style="ent", jupyter=True),容器内无Jupyter环境,运行时会抛出异常。 - 代码逻辑缩进错误:
productosReconocidos初始化和自定义模型加载代码被包含在for frase循环内,会重复加载模型并导致逻辑混乱。
解决方案
1. 修改inference.py,实现SageMaker推理接口
使用Flask搭建HTTP服务,适配SageMaker规范,同时修正代码逻辑:
import spacy from nltk.tokenize import sent_tokenize import string import es_core_news_sm from flask import Flask, request, jsonify import os # SageMaker自动解压模型到/opt/ml/model目录 model_local_path = '/opt/ml/model' # 提前加载模型,避免每次请求重复加载 nlp_preprocess = es_core_news_sm.load() nlp_ner = spacy.load(model_local_path) app = Flask(__name__) def process_text(text): frasesSolicitud = sent_tokenize(text) frasesProcesadas = [] for frase in frasesSolicitud: frasesSinVerbos = [] texto = frase.lower() texto = texto.translate(str.maketrans('', '', string.punctuation)) doc = nlp_preprocess(texto) for palabra in doc: if palabra.pos_ not in ['VERB', 'ADJ', 'PRON']: frasesSinVerbos.append(str(palabra)) textoSinVerbos = ' '.join(frasesSinVerbos) frasesProcesadas.append(textoSinVerbos) productosReconocidos = [] for item in frasesProcesadas: fraseProcesada = item.lower() doc = nlp_ner(fraseProcesada) # 移除Jupyter环境专属的调试代码 for ent in doc.ents: productosReconocidos.append(ent.label_) return productosReconocidos # 健康检查端点(SageMaker必选) @app.route('/ping', methods=['GET']) def ping(): return jsonify({'status': 'healthy'}), 200 # 推理请求端点(SageMaker必选) @app.route('/invocations', methods=['POST']) def invocations(): data = request.get_json() if 'text' not in data: return jsonify({'error': 'Missing "text" in request'}), 400 text = data['text'] result = process_text(text) return jsonify({'entities': result}), 200 if __name__ == '__main__': # 监听8080端口(SageMaker要求的默认端口) app.run(host='0.0.0.0', port=8080)
2. 修改Dockerfile,适配SageMaker规范
调整依赖安装逻辑,确保serve命令能正常启动服务,同时修正模型依赖:
FROM python:3.8-slim-bullseye # 设置SageMaker要求的工作目录 WORKDIR /opt/ml/code # 安装核心依赖 RUN pip install spacy nltk flask # 安装系统依赖,清理缓存减小镜像体积 RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libatlas-base-dev \ libcurl4-openssl-dev \ libssl-dev && \ rm -rf /var/lib/apt/lists/* # 安装代码中实际使用的西班牙语SpaCy模型 RUN python -m spacy download es_core_news_sm # 复制推理脚本到工作目录 COPY inference.py . # SageMaker环境变量配置 ENV SAGEMAKER_PROGRAM inference.py ENV PYTHONUNBUFFERED TRUE # 启动命令:SageMaker执行serve时启动Flask服务 ENTRYPOINT ["python", "inference.py"]
3. 调整模型打包方式
确保上传到S3的model.tar.gz是训练后模型文件夹内所有内容的压缩包(而非包含模型文件夹本身),这样解压后/opt/ml/model目录下会直接包含模型的完整文件。
4. 本地测试容器(关键步骤)
在本地先验证容器功能,避免重复上传ECR:
# 构建本地镜像 docker build -t spacy-sagemaker . # 模拟SageMaker启动命令运行容器 docker run -p 8080:8080 spacy-sagemaker serve # 另一个终端测试健康检查 curl http://localhost:8080/ping # 测试推理请求 curl -X POST http://localhost:8080/invocations -H "Content-Type: application/json" -d '{"text": "Tu texto de ejemplo aquí"}'
本地测试正常后,重新上传镜像到ECR,再在SageMaker中创建模型和端点即可。
内容的提问来源于stack exchange,提问作者DavDEV_02
相关产品推荐
相关产品推荐

