bentoml / BentoML

The easiest way to serve AI/ML models in production - Build Model Inference Service, LLM APIs, Multi-model Inference Graph/Pipelines, LLM/RAG apps, and more!
https://bentoml.com
Apache License 2.0
6.78k stars 767 forks source link

Trouble in saving the Keras model to the Bentoml model store #4631

Open rxiaogit opened 3 months ago

rxiaogit commented 3 months ago

Versions installed on Windows 11 desktop: bentoml 1.2.9 keras 3.1.1 tensorflow 2.16.1

The Issue: After training a Keras model of CNN with the MNIST dataset, need to save the trained Keras model to the Bentoml model store, but always got the ValueError complaining about the arguments of ['signatures', 'options'] not supported, though those were never passed as arguments in the save_model() call.

See the python codes below:

def main():

import bentoml
import tensorflow as tf
from tensorflow import keras

"""Trains a model for classifying digits using the MNIST dataset."""
train_images, train_labels, test_images, test_labels = prepare_mnist_training_data()

model = build_convnet_model(INPUT_SHAPE, NUM_CLASSES)

model = train_model(
    model, train_images, train_labels, test_images, test_labels, NUM_EPOCHS
)

# save the model to bento model store 
# model.save("cnn_model.keras")

bentoml.keras.save_model("keras_cnn", model)

if name == "main": main()

And the error messages when running above codes:

Traceback (most recent call last): File "C:\Users\rxiao\Tensorflow-Tutorial\mldeployment\mldeployment\training.py", line 138, in main() File "C:\Users\rxiao\Tensorflow-Tutorial\mldeployment\mldeployment\training.py", line 134, in main bentoml.keras.save_model("keras_cnn", model) File "C:\Users\rxiao\anaconda3\envs\tf\Lib\site-packages\bentoml_internal\frameworks\keras.py", line 267, in save_model model.save( File "C:\Users\rxiao\AppData\Roaming\Python\Python311\site-packages\keras\src\utils\traceback_utils.py", line 123, in error_handler raise e.with_traceback(filtered_tb) from None File "C:\Users\rxiao\AppData\Roaming\Python\Python311\site-packages\keras\src\models\model.py", line 309, in save raise ValueError( ValueError: The following argument(s) are not supported: ['signatures', 'options']

Is there a bug in the bentoml._internal.frameworks.keras library? Or What else do I miss here?

Thanks in advance for your help!!

dhj-git commented 1 month ago

i have the same problem

kascesar commented 1 month ago

same here!

kascesar commented 1 month ago

@rxiaogit @dhj-git Hello, i solved the problem. but you need to use bentoml.mlflow instead of bentoml.keras:

  1. Instantiate a server of mlflow
  2. save your model keras model into mlflow -lots of tutorials in web, just googleit-

    My code

    
    from datetime import datetime

import mlflow import pandas as pd import tensorflow as tf from hydra import compose, initialize from hydra.utils import instantiate from mlflow.models.signature import infer_signature from tensorflow.keras.callbacks import CSVLogger from tensorflow.keras.optimizers import Adam

from src.utils import parse_dataset

def main(): with initialize(version_base=None, config_path="config", job_name="test_app"): cfg = compose(config_name="main") mlflow.set_tracking_uri(cfg.mlflow.uri) mlflow.set_experiment("anomaly-det")

mlflow.keras.autolog()

    with mlflow.start_run(run_name="anomaly-csv2d-lstm-autoenconder"):
        model = instantiate(cfg.model)

        dataset = tf.data.TFRecordDataset(cfg.dataset.train)
        dataset = dataset.map(parse_dataset)
        dataset = dataset.batch(cfg.train.batch_size)
        opt = Adam(
            learning_rate=1e-4,
            epsilon=1e-6,
        )
        model.compile(loss="mse", optimizer=opt)
        csv_logger = CSVLogger("training.csv")
        model.fit(
            dataset,
            epochs=cfg.train.epocs,
            callbacks=[csv_logger],
        )
        # Login mlflow
        now = datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
        model_name = f"Conv2D_LSTM_Anomlay_Fatigue_Model_{now}"
        registered_model_name = f"Conv2D_LSTM_Anomaly_Fatigue_Model_{now}"

        df_loger = pd.read_csv("training.csv")

        # crea el signature para el modelo
        example_input = tf.random.normal((1, 1, 5, 4, 4))
        example_output = model.predict(example_input)
        signature = infer_signature(example_input.numpy(), example_output)

        mlflow.keras.log_model(
            model,
            artifact_path=model_name,
            registered_model_name=registered_model_name,
            signature=signature,
        )
        mlflow.log_table(data=df_loger, artifact_file="train-log.csv")
        mlflow.log_param("train-date", now.replace("_", " "))

if name == "main": main()


3. create a bento model

```python

import bentoml
import mlflow
from hydra import compose, initialize

from anomaly_x_builder import XBuilderAnomaly, anomaly_mesure

initialize(version_base=None, config_path="../../config", job_name="bento-create-model")
cfg = compose(config_name="main")
mlflow.set_tracking_uri(cfg.mlflow.uri)

bentoml.mlflow.import_model(
    "fatiguelog-anomaly-detector",
    model_uri=cfg.model.mlflow_uri,
    signatures={"predict": {"batchable": False, "batch_dim": 0}},
    custom_objects={
        "x_builder": XBuilderAnomaly(),
        "anomaly_mesure": anomaly_mesure,
    },
)
  1. build a bento

    My code for serve

    
    from io import StringIO
    import bentoml
    import pandas as pd
    from bentoml.io import JSON, Text

model_ref = bentoml.mlflow.get("fatiguelog-anomaly-detector:latest") runner = model_ref.to_runner() xbuilder = model_ref.custom_objects["x_builder"] mesure = model_ref.custom_objects["anomaly_mesure"] sample_input = pd.read_csv( "sample_input.csv", parse_dates=["shift_start_timestamp_utc", "fatigue_log_timestamp_utc"], )

svc = bentoml.Service( name="fatiguelog-anomaly-detector", runners=[runner], )

@svc.api(input=Text.from_sample(sample_input.to_csv(index=False)), output=JSON()) async def predict(data): data = pd.read_csv(StringIO(data), engine="pyarrow") X, dts = xbuilder(data) result = await runner.async_run(X) return {"anomaly-score": [f"{i}" for i in mesure(X, result)], "timestamp": dts}

```bash
bentoml build fatiguelog-anomaly-detector:latest
  1. serve the model run the following code in the folder where are the serve.py
    bentoml serve .

    Previously i had a problem with deplyment to AWS sagemaker , the version of bentoml thaths works for that is the 1.1.11, y don't know why.

Enjoy! Hope this help! :D