bentoml / BentoML

The easiest way to serve AI apps and models - Build Model Inference APIs, Job queues, LLM apps, Multi-model pipelines, and more!
https://bentoml.com
Apache License 2.0
7.17k stars 792 forks source link

Unable to load model:version from remote yatai server #1787

Closed alborotogarcia closed 3 years ago

alborotogarcia commented 3 years ago

Describe the bug

The remote yatai client lists the model artifacts but fails to load them. Bentoml client works fine: bentoml retrieve IrisClassifier:20210728102908_1CDF04 --target_dir $MYDIR

But is there a way to do this in python ideally predefining some env variables? I know this can be done predefining boto3 python config but i'd like to skip S3 authentication with .aws/ directory

To Reproduce

from bentoml.yatai.client import get_yatai_client
remote_yatai_client = get_yatai_client('http://yatai:50051')

remote_yatai_client.repository.list()#.load('IrisClassifier:20210728102908_1CDF04')
[name: "IrisClassifier"
version: "20210728102908_1CDF04"
uri {
  type: S3
  uri: "s3://bentoml/artifacts/IrisClassifier/20210728102908_1CDF04.tar.gz"
}
bento_service_metadata {
  name: "IrisClassifier"
  version: "20210728102908_1CDF04"
  created_at {
    seconds: 1627460949
    nanos: 518355000
  }
  env {
    conda_env: "name: bentoml-default-conda-env\ndependencies: []\n"
    python_version: "3.8.10"
    docker_base_image: "bentoml/model-server:0.13.1-py38"
    pip_packages: "bentoml==0.13.1"
    pip_packages: "pandas==1.2.5"
    pip_packages: "scikit-learn==0.24.2"
  }
  artifacts {
    name: "model"
    artifact_type: "SklearnModelArtifact"
    metadata {
    }
  }
  apis {
    name: "predict"
    input_type: "DataframeInput"
    docs: "\n        An inference API named `predict` with Dataframe input adapter, which codifies\n        how HTTP requests or CSV files are converted to a pandas Dataframe object as the\n        inference API function input\n        "
    input_config {
      fields {
        key: "dtype"
        value {
          null_value: NULL_VALUE
        }
      }
      fields {
        key: "orient"
        value {
          null_value: NULL_VALUE
        }
      }
      fields {
        key: "typ"
        value {
          string_value: "frame"
        }
      }
    }
    output_type: "DefaultOutput"
    mb_max_latency: 20000
    mb_max_batch_size: 4000
    batch: true
    route: "predict"
  }
}
]

remote_yatai_client.repository.load('s3://bentoml/artifacts/IrisClassifier/20210728102908_1CDF04.tar.gz')
---------------------------------------------------------------------------
ClientError                               Traceback (most recent call last)
/tmp/ipykernel_175/710710685.py in <module>
----> 1 remote_yatai_client.repository.load('s3://bentoml/artifacts/IrisClassifier/20210728102908_1CDF04.tar.gz')

~/.local/lib/python3.8/site-packages/bentoml/yatai/client/bento_repository_api.py in load(self, bento)
    683             else:
    684                 saved_bundle_path = resolve_bento_bundle_uri(bento_pb)
--> 685         svc = load_from_dir(saved_bundle_path)
    686         return svc
    687 

~/.local/lib/python3.8/site-packages/bentoml/saved_bundle/loader.py in wrapper(bundle_path, *args)
    105     def wrapper(bundle_path, *args):
    106         if _is_remote_path(bundle_path):
--> 107             with _resolve_remote_bundle_path(bundle_path) as local_bundle_path:
    108                 return func(local_bundle_path, *args)
    109 

/opt/conda/envs/rapids/lib/python3.8/contextlib.py in __enter__(self)
    111         del self.args, self.kwds, self.func
    112         try:
--> 113             return next(self.gen)
    114         except StopIteration:
    115             raise RuntimeError("generator didn't yield") from None

~/.local/lib/python3.8/site-packages/bentoml/saved_bundle/loader.py in _resolve_remote_bundle_path(bundle_path)
     62         s3 = boto3.client('s3')
     63         fileobj = io.BytesIO()
---> 64         s3.download_fileobj(bucket_name, object_name, fileobj)
     65         fileobj.seek(0, 0)
     66     elif is_gcs_url(bundle_path):

/opt/conda/envs/rapids/lib/python3.8/site-packages/boto3/s3/inject.py in download_fileobj(self, Bucket, Key, Fileobj, ExtraArgs, Callback, Config)
    676             bucket=Bucket, key=Key, fileobj=Fileobj,
    677             extra_args=ExtraArgs, subscribers=subscribers)
--> 678         return future.result()
    679 
    680 

/opt/conda/envs/rapids/lib/python3.8/site-packages/s3transfer/futures.py in result(self)
    104             # however if a KeyboardInterrupt is raised we want want to exit
    105             # out of this and propogate the exception.
--> 106             return self._coordinator.result()
    107         except KeyboardInterrupt as e:
    108             self.cancel()

/opt/conda/envs/rapids/lib/python3.8/site-packages/s3transfer/futures.py in result(self)
    263         # final result.
    264         if self._exception:
--> 265             raise self._exception
    266         return self._result
    267 

/opt/conda/envs/rapids/lib/python3.8/site-packages/s3transfer/tasks.py in _main(self, transfer_future, **kwargs)
    253             # Call the submit method to start submitting tasks to execute the
    254             # transfer.
--> 255             self._submit(transfer_future=transfer_future, **kwargs)
    256         except BaseException as e:
    257             # If there was an exception raised during the submission of task

/opt/conda/envs/rapids/lib/python3.8/site-packages/s3transfer/download.py in _submit(self, client, config, osutil, request_executor, io_executor, transfer_future, bandwidth_limiter)
    338             # If a size was not provided figure out the size for the
    339             # user.
--> 340             response = client.head_object(
    341                 Bucket=transfer_future.meta.call_args.bucket,
    342                 Key=transfer_future.meta.call_args.key,

/opt/conda/envs/rapids/lib/python3.8/site-packages/botocore/client.py in _api_call(self, *args, **kwargs)
    384                     "%s() only accepts keyword arguments." % py_operation_name)
    385             # The "self" in this scope is referring to the BaseClient.
--> 386             return self._make_api_call(operation_name, kwargs)
    387 
    388         _api_call.__name__ = str(py_operation_name)

/opt/conda/envs/rapids/lib/python3.8/site-packages/botocore/client.py in _make_api_call(self, operation_name, api_params)
    703             error_code = parsed_response.get("Error", {}).get("Code")
    704             error_class = self.exceptions.from_code(error_code)
--> 705             raise error_class(parsed_response, operation_name)
    706         else:
    707             return parsed_response

ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden

Expected behavior

Screenshots/Logs image

Environment:

Additional context

alborotogarcia commented 3 years ago

Already solved, I got a problem generating the pickle model artifact