Skip to content

Path based model format detection #251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/apis/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Serve models at scale.
- kind: api
name: <string> # API name (required)
model: <string> # path to an exported model (e.g. s3://my-bucket/model.zip)
model_format: <string> # model format, must be "tensorflow" or "onnx"
model_format: <string> # model format, must be "tensorflow" or "onnx" (default: "onnx" if model path ends with .onnx, "tensorflow" if model path ends with .zip)
request_handler: <string> # path to the request handler implementation file, relative to the cortex root
compute:
min_replicas: <int> # minimum number of replicas (default: 1)
Expand Down
2 changes: 0 additions & 2 deletions docs/apis/packaging-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Reference your `model` in an API:
```yaml
- kind: api
name: my-api
model_format: tensorflow
model: s3://my-bucket/model.zip
```

Expand Down Expand Up @@ -65,5 +64,4 @@ Reference your `model` in an API:
- kind: api
name: my-api
model: s3://my-bucket/model.onnx
model_format: onnx
```
1 change: 0 additions & 1 deletion docs/apis/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Cortex requires a `cortex.yaml` file which defines a `deployment` resource. An `
- kind: api
name: classifier
model: s3://cortex-examples/iris/tensorflow.zip
model_format: tensorflow
```

Cortex is able to read from any S3 bucket that you have access to.
Expand Down
5 changes: 0 additions & 5 deletions examples/iris/cortex.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,23 @@
- kind: api
name: tensorflow
model: s3://cortex-examples/iris/tensorflow.zip
model_format: tensorflow

- kind: api
name: pytorch
model: s3://cortex-examples/iris/pytorch.onnx
model_format: onnx
request_handler: pytorch/handler.py

- kind: api
name: xgboost
model: s3://cortex-examples/iris/xgboost.onnx
model_format: onnx
request_handler: xgboost/handler.py

- kind: api
name: sklearn
model: s3://cortex-examples/iris/sklearn.onnx
model_format: onnx
request_handler: sklearn/handler.py

- kind: api
name: keras
model: s3://cortex-examples/iris/keras.onnx
model_format: onnx
request_handler: keras/handler.py
26 changes: 13 additions & 13 deletions examples/iris/keras/irises.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"samples": [
[
5.9,
3.0,
5.1,
1.8
],
[
5.6,
2.5,
3.9,
1.1
]
"samples": [
[
5.9,
3.0,
5.1,
1.8
],
[
5.6,
2.5,
3.9,
1.1
]
]
}
26 changes: 13 additions & 13 deletions examples/iris/xgboost/irises.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"samples": [
[
5.9,
3.0,
5.1,
1.8
],
[
5.6,
2.5,
3.9,
1.1
]
"samples": [
[
5.9,
3.0,
5.1,
1.8
],
[
5.6,
2.5,
3.9,
1.1
]
]
}
14 changes: 10 additions & 4 deletions pkg/operator/api/userconfig/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,20 @@ func (api *API) Validate() error {
if yaml.StartsWithEscapedAtSymbol(api.Model) {
api.ModelFormat = TensorFlowModelFormat
} else {
if api.ModelFormat == UnknownModelFormat {
return errors.Wrap(cr.ErrorMustBeDefined(), Identify(api), ModelFormatKey)
}

if !aws.IsValidS3Path(api.Model) {
return errors.Wrap(ErrorInvalidS3PathOrResourceReference(api.Model), Identify(api), ModelKey)
}

if api.ModelFormat == UnknownModelFormat {
if strings.HasSuffix(api.Model, ".onnx") {
api.ModelFormat = ONNXModelFormat
} else if strings.HasSuffix(api.Model, ".zip") {
api.ModelFormat = TensorFlowModelFormat
} else {
return errors.Wrap(ErrorUnableToInferModelFormat(), Identify(api))
}
}

if ok, err := aws.IsS3PathFileExternal(api.Model); err != nil || !ok {
return errors.Wrap(ErrorExternalNotFound(api.Model), Identify(api), ModelKey)
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/operator/api/userconfig/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const (
ErrExtraResourcesWithExternalAPIs
ErrImplDoesNotExist
ErrInvalidS3PathOrResourceReference
ErrUnableToInferModelFormat
ErrExternalNotFound
)

Expand Down Expand Up @@ -130,6 +131,7 @@ var errorKinds = []string{
"err_extra_resources_with_external_apis",
"err_impl_does_not_exist",
"err_invalid_s3_path_or_resource_reference",
"err_unable_to_infer_model_format",
"err_external_not_found",
}

Expand Down Expand Up @@ -597,6 +599,13 @@ func ErrorExternalNotFound(path string) error {
}
}

func ErrorUnableToInferModelFormat() error {
return Error{
Kind: ErrUnableToInferModelFormat,
message: "unable to infer " + ModelFormatKey + ": path to model should end in .zip for TensorFlow models, .onnx for ONNX models, or the " + ModelFormatKey + " key must be specified",
}
}

func ErrorInvalidS3PathOrResourceReference(provided string) error {
s3ErrMsg := aws.ErrorInvalidS3Path(provided).Error()
return Error{
Expand Down