我正在使用 Keras 开发自定义深度学习模型,这不是顺序模型。该模型具有双重输出:它生成用于预测的连续值和用于预测的多类标签。为了简化我的工作,我使用 scikit-learn Pipelines 并使用 joblib 保存整个管道。
我遇到了 scikit-learn 的 Keras 包装器的问题,该包装器是为顺序模型设计的。因此,我成功地构建了自己的自定义模型,并且它在本地表现良好。我什至付出了额外的努力,创建了一个概念验证 API 和一个小型网站来服务这个模型。
在我的本地环境中一切都运行顺利。然而,当我尝试构建 Docker 镜像时,遇到了问题。管道无法加载模型权重,导致出现如下错误消息:
Layer 'lstm_cell' expected 3 variables, but received 0 variables during loading. Expected: ['lstm/lstm_cell/kernel:0', 'lstm/lstm_cell/recurrent_kernel:0', 'lstm/lstm_cell/bias:0']
我想知道其他人以前是否遇到过这种情况。在 Docker 中处理 .pkl 文件是否存在问题,或者是否需要在上传之前压缩文件?我花了几个小时试图解决这个问题,我们将不胜感激任何帮助。
这是我的文件夹的一瞥:
.
└── END2END/
├── pipelines/
│ ├── scripts
│ ├── __init__py
│ └── myscripts.py
├── train_models/
│ ├── __init__.py
│ ├── script2.py
│ └── my_model_.pkl
├── api.py
└── Dockerfile
还有我的模型:
def ModelLSTM(input_shape, hidden_units: int,
output_1: int, output_2: int,
lr: float, model_name: str) -> keras.Model:
""" LSTM model - single multioutput model
### Arguments:
- input_shape : input shapes
- hidden_units : hidden units (LSTM units)
- output_1 : number of outputs (forecasting outputs)
- output_2 : number of outputs (failures outputs)
- lr : learning rate
- name: name of the model
### Returns:
model (keras.Model)"""
# Data Input
inputs_ = keras.Input(
shape=(input_shape[1], input_shape[2]),
name='inputs'
)
# Lstm Layer
hiddens_layers = layers.LSTM(hidden_units, return_sequences=True)(inputs_)
# output forecasting
output_forecast = layers.Dense(output_1, activation='linear', name='forecast')(hiddens_layers)
# output failures
output_failures = layers.Dense(output_2, activation='sigmoid', name='failures')(hiddens_layers)
# Create Model
model = keras.Model(inputs=inputs_, outputs=[output_forecast, output_failures], name=model_name)
model.compile(loss={
'forecast': 'mean_squared_error',
'failures': custom_multilabel_loss},
optimizer= tf.keras.optimizers.Adam(learning_rate=lr),
metrics ={
'forecast': 'mae',
'failures': 'accuracy'})
return model
这是我的 docker 文件
# Variables
ARG WorkingDirectory=/project
# Pull Docker Image
FROM python:3.11-bullseye
# Set up Working Environment
WORKDIR $WorkingDirectory
# Create an "application" directory
RUN mkdir -p $WorkingDirectory/application
RUN export PYTHONPATH=$WorkingDirectory
# Copy Files
COPY . $WorkingDirectory/application
# Update Requirements
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r $WorkingDirectory/application/requirements/requirements.txt
EXPOSE 8000
# Start API Server
CMD ["sh", "-c", "python ${ADD_DIR}/application/main.py"]
他们是我保存和加载管道的方式:
def save_pipeline(*, pipeline_to_saved: Pipeline, name: str) -> None:
"""
Saved the versioned model and overwrite any previos saved models,
this ensure there is only one trained model that can be called
### Arguments:
- pipeline_to_save (`sklearn.Pipeline`) : pipeline already trained
"""
# Versioned file name
save_file_name = f"{name}_{_version}.pkl"
save_path = TRAINED_MODEL_DIR / save_file_name
# Re-write or delete model file
remove_old_pipelines(files_to_keep=save_file_name)
# saved
joblib.dump(pipeline_to_saved, save_path)
def load_pipeline(*, file_name: str) -> Pipeline:
""" Load Pipeline from trained model
### Arguments:
- file_name (str): pipeline file name
### Returns:
train_pipeline : Pipeline object
"""
file_path = TRAINED_MODEL_DIR / f"{file_name}_{_version}.pkl"
print(file_path)
trained_pipeline = joblib.load(filename=file_path)
return trained_pipeline
我对模型进行了两次重新训练,以确保其重量没有问题。在本地运行时,模型加载、运行并进行预测不会出现任何问题。
我尝试将权重文件移动到与“api.py”相同的位置,甚至尝试将路径硬编码到“.pkl”文件。
我知道我可以分割管道并使用“keras.load_weights”加载模型,然后将模型重新插入管道。但是,如果它在本地运行正常,我想知道为什么它在 Docker 中无法运行。”
经过大量研究,我找不到解决问题的简单方法。我认为发生的事情是这样的:我首先在 Windows 计算机上训练我的模型,但我尝试在 Linux 计算机上运行的 Docker 容器中使用它。这两个系统并不总是完美相处(我缺乏跨系统兼容性的复杂性方面的专业知识)。
我读到 .pkl 模型文件应该与创建它们时使用的相同版本的 Python (在 python 3.11.6 上训练并在 python 3.11.6 上构建)一起使用,所以我确定了这一点,但是 它没有无法解决问题我也尝试过压缩.pkl文件,正如一些人建议的那样,但是也不起作用。有些人说 Docker 可能在处理 .pkl 文件时遇到问题,但我可以确认这不是我的情况的问题。
最终对我有用的是一种不同的方法。我不只是复制文件,而是像以前一样重新创建了整个目录结构。然后,当我构建 Docker 容器时,我再次训练了模型(在 docker 映像内部)。令人惊讶的是,这解决了我的问题,并且该模型在 Docker 容器中完美运行。问题似乎是因为该模型是在 Windows 上训练的,但在 Linux 上的 Docker 容器中使用(我的假设)。
我分享这个以防其他人遇到同样的问题。 干杯