Open trongnghia05 opened 1 year ago
I realize that when serving, I call model.run(df), and it seems like this function does something to reload the model using cloudpickle, but after loading, it does not convert it into a runner, causing the saved model to not have the registered call method when using save_model. How can I handle this situation?
The following simple code snippet also does not work because when run model.run, the model does not have the registered call method.
import bentoml
model = bentoml.picklable_model.get("xgboost:latest").to_runner()
model.init_local()
# print(getattr(model, "__call__"))
model.run([[5.9, 3., 5.1, 1.8]])
So the result of this line:
# Find best model
best_model = optimize(objective, space)
Can best_model
be called directly with best_model(...)
? If not, how is it supposed to be used in prediction?
Skipping the lengthy code above, I simply ran:
model = bentoml.picklable_model.get("xgboost:latest").to_runner()
model.init_local()
#print(getattr(model, "call"))
model.run([[5.9, 3., 5.1, 1.8]])
and an error occurred."
Result when run with model.run and comment print(getattr(model, "call")) :
Traceback (most recent call last):
File "a.py", line 7, in <module>
r.run([7])
File "/home/nghiamt/PycharmProjects/MLOps/end-to-end-project/venv/lib/python3.8/site-packages/bentoml/_internal/runner/runner.py", line 52, in run
return self.runner._runner_handle.run_method(self, *args, **kwargs)
File "/home/nghiamt/PycharmProjects/MLOps/end-to-end-project/venv/lib/python3.8/site-packages/bentoml/_internal/runner/runner_handle/local.py", line 48, in run_method
return getattr(self._runnable, __bentoml_method.name)(*args, **kwargs)
File "/home/nghiamt/PycharmProjects/MLOps/end-to-end-project/venv/lib/python3.8/site-packages/bentoml/_internal/runner/runnable.py", line 140, in method
return self.func(obj, *args, **kwargs)
File "/home/nghiamt/PycharmProjects/MLOps/end-to-end-project/venv/lib/python3.8/site-packages/bentoml/_internal/frameworks/picklable.py", line 171, in _run
return getattr(self.model, method_name)(
AttributeError: 'XGBClassifier' object has no attribute '__call__'
If I comment out the run method and run as follows, it still works, proving that the call method still exists. However, I don't understand why when I run the run method, it throws an error saying there is no call. Result when run with print(getattr(model, "call")) and comment run:
import bentoml
model= bentoml.picklable_model.get("xgboost:latest").to_runner()
model.init_local()
print(getattr(model, "__call__"))
# model.run([7])
/home/nghiamt/PycharmProjects/MLOps/end-to-end-project/venv/lib/python3.8/site-packages/requests/__init__.py:109: RequestsDependencyWarning: urllib3 (1.26.16) or chardet (5.2.0)/charset_normalizer (2.0.12) doesn't match a supported version!
warnings.warn(
'Runner.init_local' is for debugging and testing only. Make sure to remove it before deploying to production.
RunnerMethod(runner=Runner(name='xgboost', models=[Model(tag="xgboost:tzvcynrr2kpu5xjw", path="/home/nghiamt/bentoml/models/xgboost/tzvcynrr2kpu5xjw")], resource_config=None, runnable_class=<class 'bentoml._internal.frameworks.picklable.get_runnable.<locals>.PicklableRunnable'>, embedded=False, runner_methods=[...], scheduling_strategy=<class 'bentoml._internal.runner.strategy.DefaultStrategy'>, workers_per_resource=1, runnable_init_params={}, _runner_handle=<bentoml._internal.runner.runner_handle.local.LocalRunnerRef object at 0x7f9297c627f0>), name='__call__', config=RunnableMethodConfig(batchable=True, batch_dim=(0, 0), input_spec=None, output_spec=None), max_batch_size=100, max_latency_ms=60000)
This indicates that there is an issue with the run method.
The error says __call__
is missing on the model object, while what you are inspecting is the runner object, they are different objects and have different methods. Please inspect on the resulted best_model
to see if __call__
is present.
You can also get the underlying model by:
model= bentoml.picklable_model.load_model("xgboost:latest")
print(getattr(model, "__call__")) # <-- is it there?
BentoML also has built-in support for XGBoost framework, try saving and loading model with bentoml.xgboost.*
instead of bentoml.picklable_model
. And the default entry fro XGBoost model inference is .predict()
.
I tried getattr(model, "__call__")
to check __call__
method existed, If I ignore run method, my code worked:
I tried
getattr(model, "__call__")
to check__call__
method existed
Wrong object being checked, the model
in your screenshot is indeed a runner(it is returned by to_runner()
method). Please check the code given in my last reply, it has a difference.
You can also just check if runner.__call__.run
exists. But it seems like to me that the original model doesn't have a __call__
function.
Describe the bug
Oh, I have a model trained using the XGBoost library following these steps:
Step 1: Save the model after training using joblib.dump(best_model, abspath(config.model.path)).
Step 2: After training, I used BentoML to save the model using bentoml.picklable_model.save_model.
Step 3: When I try to load the model to perform an API call using bentoml.picklable_model.get, I encounter the error 'XGBClassifier' object has no attribute 'call'.
I'm not sure why, even though in Step 2, after using save_model, I saw that a call method was present in the model signature, specifically displayed as follows: "Using the default model signature for pickable model ({'call': ModelSignature(batchable=False, batch_dim=(0, 0), input_spec=None, output_spec=None)}) for model 'xgboost'." This means that my model already has the call method, but when trying to infer, the error still says "no attribute 'call'".
train code:
save model:
service:
To reproduce
Oh, I have a model trained using the XGBoost library following these steps:
Step 1: Save the model after training using joblib.dump(best_model, abspath(config.model.path)).
Step 2: After training, I used BentoML to save the model using bentoml.picklable_model.save_model.
Step 3: When I try to load the model to perform an API call using bentoml.picklable_model.get, I encounter the error 'XGBClassifier' object has no attribute 'call'.
I'm not sure why, even though in Step 2, after using save_model, I saw that a call method was present in the model signature, specifically displayed as follows: "Using the default model signature for pickable model ({'call': ModelSignature(batchable=False, batch_dim=(0, 0), input_spec=None, output_spec=None)}) for model 'xgboost'." This means that my model already has the call method, but when trying to infer, the error still says "no attribute 'call'".
Expected behavior
The expected behavior when calling the /predict API is to receive the correct results, not an error like "'XGBClassifier' object has no attribute 'call'."
Environment
These are the library versions I used:
bentoml==1.1.0 dagshub==0.1.8 deepchecks==0.6.1 hydra-core==1.2.0 hyperopt==0.2.7 joblib==1.1.1 mlflow==1.25.1 numpy==1.22.4 pandas==1.4.2 pandera==0.13.4 patsy==0.5.2 pydantic==1.9.1 pytest_steps==1.8.0 requests==2.28.0 scikit_learn==1.2.1 streamlit==1.10.0 xgboost==1.7.6 dvc==2.8.1 fsspec==2022.7.1