forked from openvinotoolkit/model_server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Go client sample (openvinotoolkit#1014)
- Loading branch information
Showing
13 changed files
with
1,778 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# | ||
# Copyright (c) 2021 Intel Corporation | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
FROM golang:latest | ||
ARG http_proxy | ||
|
||
RUN echo "Acquire::http::Proxy \"$http_proxy\";" > /etc/apt/apt.conf.d/proxy.conf | ||
RUN apt-get update && \ | ||
apt-get -y install git unzip build-essential autoconf libtool protobuf-compiler libprotobuf-dev | ||
RUN go get google.golang.org/grpc | ||
RUN go get github.com/golang/protobuf/protoc-gen-go | ||
|
||
# Install Go OpenCV (to simplify postprocessing) | ||
RUN apt-get install -y sudo && \ | ||
git clone https://github.com/hybridgroup/gocv.git && \ | ||
cd gocv && \ | ||
make install | ||
|
||
RUN mkdir /app | ||
COPY . /app | ||
WORKDIR /app | ||
|
||
# Compile API | ||
RUN protoc -I apis/ apis/tensorflow_serving/apis/*.proto --go_out=plugins=grpc:. | ||
RUN protoc -I apis/ apis/tensorflow/core/framework/*.proto --go_out=plugins=grpc:. | ||
|
||
# Move compiled protos under GOROOT | ||
RUN mv tensorflow /usr/local/go/src/ | ||
RUN mv tensorflow_serving /usr/local/go/src/ | ||
|
||
## we run go build to compile the binary | ||
RUN go mod init ovmsclient | ||
RUN go mod tidy | ||
RUN go build . | ||
|
||
|
||
ENTRYPOINT ["/app/ovmsclient"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Go client for prediction | ||
|
||
This client has been created to demostrate how to interact with OpenVINO Model Server prediction endpoint from Go application. Presented example demonstrates end to end flow for running classification on JPG/PNG image using ResNet50 model. For simplicity of the environment setup, the example is run in the Docker container. | ||
|
||
|
||
## Get the model | ||
|
||
To run end to end flow and get correct results, please download `resnet-50-tf` model and convert it to IR format by following [instructions available on the OpenVINO Model Zoo page](https://docs.openvinotoolkit.org/latest/omz_models_model_resnet_50_tf.html) | ||
|
||
Place converted model files (XML and BIN) under the following path: `<PATH_TO_MODELS>/resnet/1` | ||
|
||
Where `PATH_TO_MODELS` is the path to the directory with models on the host filesystem. | ||
|
||
For example: | ||
``` | ||
/home/user/models/resnet/1/resnet-50-tf.xml | ||
/home/user/models/resnet/1/resnet-50-tf.bin | ||
``` | ||
|
||
## Build Go client docker image | ||
|
||
To build the docker image and tag it `ovmsclient` run: | ||
``` | ||
docker build . -t ovmsclient | ||
``` | ||
|
||
## Start OpenVINO Model Server with ResNet model | ||
|
||
Before running the client launch OVMS with prepared ResNet model. You can do that with a command similar to: | ||
|
||
``` | ||
docker run -d --rm -p 9000:9000 -v <PATH_TO_MODELS>/resnet:/models/resnet openvino/model-server:latest --model_name resnet --model_path /models/resnet --port 9000 --layout NHWC | ||
``` | ||
|
||
**Note** Changing the layout with `--layout NHWC` option is necessary in this example, so the model will accept binary input generated by the client. See [binary inputs](../../docs/binary_input.md) doc if you want to learn more about this feature. | ||
|
||
## Run prediction with Go client | ||
|
||
In order to run prediction on the model served by the OVMS using Go client run the following command: | ||
|
||
`docker run --net=host --rm ovmsclient --serving-address localhost:9000 zebra.jpeg` | ||
|
||
Command explained: | ||
- `--net=host` option is required so the container with the client can access container with the model server via host network (localhost), | ||
- `--serving-address` parameter defines the address of the model server gRPC endpoint, | ||
- the last part in the command is a path to the image that will be send to OVMS for prediction. The image must be accessible from the inside of the container (could be mounted). Single zebra picture - `zebra.jpeg` - has been embedded in the docker image to simplify the example, so above command would work out of the box. If you wish to use other image you need to provide it to the container and change the path. | ||
|
||
You can also choose if the image should be sent as binary input (raw JPG or PNG bytes) or should be converted on the client side to the data array accepted by the model. | ||
To send raw bytes just add `--binary-input` flag like this: | ||
|
||
`docker run --net=host --rm ovmsclient --serving-address localhost:9000 --binary-input zebra.jpeg` | ||
|
||
### Exemplary output: | ||
|
||
If the client successfully prepared and sent the request and then received a valid response, the output of this command should look somewhat like this: | ||
``` | ||
$ docker run --net=host --rm ovmsclient --serving-address localhost:9000 zebra.jpeg | ||
2021/08/30 15:46:40 Request sent successfully | ||
Predicted class: zebra | ||
Classification confidence: 98.353996% | ||
``` |
45 changes: 45 additions & 0 deletions
45
example_client/go/apis/tensorflow/core/framework/resource_handle.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
syntax = "proto3"; | ||
|
||
package tensorflow; | ||
|
||
import "tensorflow/core/framework/tensor_shape.proto"; | ||
import "tensorflow/core/framework/types.proto"; | ||
|
||
option cc_enable_arenas = true; | ||
option java_outer_classname = "ResourceHandle"; | ||
option java_multiple_files = true; | ||
option java_package = "org.tensorflow.framework"; | ||
option go_package = "tensorflow/core/framework"; | ||
|
||
// Protocol buffer representing a handle to a tensorflow resource. Handles are | ||
// not valid across executions, but can be serialized back and forth from within | ||
// a single run. | ||
message ResourceHandleProto { | ||
// Unique name for the device containing the resource. | ||
string device = 1; | ||
|
||
// Container in which this resource is placed. | ||
string container = 2; | ||
|
||
// Unique name of this resource. | ||
string name = 3; | ||
|
||
// Hash code for the type of the resource. Is only valid in the same device | ||
// and in the same execution. | ||
uint64 hash_code = 4; | ||
|
||
// For debug-only, the name of the type pointed to by this handle, if | ||
// available. | ||
string maybe_type_name = 5; | ||
|
||
// Protocol buffer representing a pair of (data type, tensor shape). | ||
message DtypeAndShape { | ||
DataType dtype = 1; | ||
TensorShapeProto shape = 2; | ||
} | ||
|
||
// Data types and shapes for the underlying resource. | ||
repeated DtypeAndShape dtypes_and_shapes = 6; | ||
|
||
reserved 7; | ||
} |
96 changes: 96 additions & 0 deletions
96
example_client/go/apis/tensorflow/core/framework/tensor.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
syntax = "proto3"; | ||
|
||
package tensorflow; | ||
|
||
import "tensorflow/core/framework/resource_handle.proto"; | ||
import "tensorflow/core/framework/tensor_shape.proto"; | ||
import "tensorflow/core/framework/types.proto"; | ||
|
||
option cc_enable_arenas = true; | ||
option java_outer_classname = "TensorProtos"; | ||
option java_multiple_files = true; | ||
option java_package = "org.tensorflow.framework"; | ||
option go_package = "tensorflow/core/framework"; | ||
|
||
// Protocol buffer representing a tensor. | ||
message TensorProto { | ||
DataType dtype = 1; | ||
|
||
// Shape of the tensor. TODO(touts): sort out the 0-rank issues. | ||
TensorShapeProto tensor_shape = 2; | ||
|
||
// Only one of the representations below is set, one of "tensor_contents" and | ||
// the "xxx_val" attributes. We are not using oneof because as oneofs cannot | ||
// contain repeated fields it would require another extra set of messages. | ||
|
||
// Version number. | ||
// | ||
// In version 0, if the "repeated xxx" representations contain only one | ||
// element, that element is repeated to fill the shape. This makes it easy | ||
// to represent a constant Tensor with a single value. | ||
int32 version_number = 3; | ||
|
||
// Serialized raw tensor content from either Tensor::AsProtoTensorContent or | ||
// memcpy in tensorflow::grpc::EncodeTensorToByteBuffer. This representation | ||
// can be used for all tensor types. The purpose of this representation is to | ||
// reduce serialization overhead during RPC call by avoiding serialization of | ||
// many repeated small items. | ||
bytes tensor_content = 4; | ||
|
||
// Type specific representations that make it easy to create tensor protos in | ||
// all languages. Only the representation corresponding to "dtype" can | ||
// be set. The values hold the flattened representation of the tensor in | ||
// row major order. | ||
|
||
// DT_HALF, DT_BFLOAT16. Note that since protobuf has no int16 type, we'll | ||
// have some pointless zero padding for each value here. | ||
repeated int32 half_val = 13 [packed = true]; | ||
|
||
// DT_FLOAT. | ||
repeated float float_val = 5 [packed = true]; | ||
|
||
// DT_DOUBLE. | ||
repeated double double_val = 6 [packed = true]; | ||
|
||
// DT_INT32, DT_INT16, DT_INT8, DT_UINT8. | ||
repeated int32 int_val = 7 [packed = true]; | ||
|
||
// DT_STRING | ||
repeated bytes string_val = 8; | ||
|
||
// DT_COMPLEX64. scomplex_val(2*i) and scomplex_val(2*i+1) are real | ||
// and imaginary parts of i-th single precision complex. | ||
repeated float scomplex_val = 9 [packed = true]; | ||
|
||
// DT_INT64 | ||
repeated int64 int64_val = 10 [packed = true]; | ||
|
||
// DT_BOOL | ||
repeated bool bool_val = 11 [packed = true]; | ||
|
||
// DT_COMPLEX128. dcomplex_val(2*i) and dcomplex_val(2*i+1) are real | ||
// and imaginary parts of i-th double precision complex. | ||
repeated double dcomplex_val = 12 [packed = true]; | ||
|
||
// DT_RESOURCE | ||
repeated ResourceHandleProto resource_handle_val = 14; | ||
|
||
// DT_VARIANT | ||
repeated VariantTensorDataProto variant_val = 15; | ||
|
||
// DT_UINT32 | ||
repeated uint32 uint32_val = 16 [packed = true]; | ||
|
||
// DT_UINT64 | ||
repeated uint64 uint64_val = 17 [packed = true]; | ||
} | ||
|
||
// Protocol buffer representing the serialization format of DT_VARIANT tensors. | ||
message VariantTensorDataProto { | ||
// Name of the type of objects being serialized. | ||
string type_name = 1; | ||
// Portions of the object that are not Tensors. | ||
bytes metadata = 2; | ||
// Tensors contained within objects being serialized. | ||
repeated TensorProto tensors = 3; | ||
} |
46 changes: 46 additions & 0 deletions
46
example_client/go/apis/tensorflow/core/framework/tensor_shape.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Protocol buffer representing the shape of tensors. | ||
|
||
syntax = "proto3"; | ||
option cc_enable_arenas = true; | ||
option java_outer_classname = "TensorShapeProtos"; | ||
option java_multiple_files = true; | ||
option java_package = "org.tensorflow.framework"; | ||
option go_package = "tensorflow/core/framework"; | ||
|
||
package tensorflow; | ||
|
||
// Dimensions of a tensor. | ||
message TensorShapeProto { | ||
// One dimension of the tensor. | ||
message Dim { | ||
// Size of the tensor in that dimension. | ||
// This value must be >= -1, but values of -1 are reserved for "unknown" | ||
// shapes (values of -1 mean "unknown" dimension). Certain wrappers | ||
// that work with TensorShapeProto may fail at runtime when deserializing | ||
// a TensorShapeProto containing a dim value of -1. | ||
int64 size = 1; | ||
|
||
// Optional name of the tensor dimension. | ||
string name = 2; | ||
}; | ||
|
||
// Dimensions of the tensor, such as {"input", 30}, {"output", 40} | ||
// for a 30 x 40 2D tensor. If an entry has size -1, this | ||
// corresponds to a dimension of unknown size. The names are | ||
// optional. | ||
// | ||
// The order of entries in "dim" matters: It indicates the layout of the | ||
// values in the tensor in-memory representation. | ||
// | ||
// The first entry in "dim" is the outermost dimension used to layout the | ||
// values, the last entry is the innermost dimension. This matches the | ||
// in-memory layout of RowMajor Eigen tensors. | ||
// | ||
// If "dim.size()" > 0, "unknown_rank" must be false. | ||
repeated Dim dim = 2; | ||
|
||
// If true, the number of dimensions in the shape is unknown. | ||
// | ||
// If true, "dim.size()" must be 0. | ||
bool unknown_rank = 3; | ||
}; |
89 changes: 89 additions & 0 deletions
89
example_client/go/apis/tensorflow/core/framework/types.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
syntax = "proto3"; | ||
|
||
package tensorflow; | ||
option cc_enable_arenas = true; | ||
option java_outer_classname = "TypesProtos"; | ||
option java_multiple_files = true; | ||
option java_package = "org.tensorflow.framework"; | ||
option go_package = "tensorflow/core/framework"; | ||
|
||
// (== suppress_warning documentation-presence ==) | ||
// LINT.IfChange | ||
enum DataType { | ||
// Not a legal value for DataType. Used to indicate a DataType field | ||
// has not been set. | ||
DT_INVALID = 0; | ||
|
||
// Data types that all computation devices are expected to be | ||
// capable to support. | ||
DT_FLOAT = 1; | ||
DT_DOUBLE = 2; | ||
DT_INT32 = 3; | ||
DT_UINT8 = 4; | ||
DT_INT16 = 5; | ||
DT_INT8 = 6; | ||
DT_STRING = 7; | ||
DT_COMPLEX64 = 8; // Single-precision complex | ||
DT_INT64 = 9; | ||
DT_BOOL = 10; | ||
DT_QINT8 = 11; // Quantized int8 | ||
DT_QUINT8 = 12; // Quantized uint8 | ||
DT_QINT32 = 13; // Quantized int32 | ||
DT_BFLOAT16 = 14; // Float32 truncated to 16 bits. Only for cast ops. | ||
DT_QINT16 = 15; // Quantized int16 | ||
DT_QUINT16 = 16; // Quantized uint16 | ||
DT_UINT16 = 17; | ||
DT_COMPLEX128 = 18; // Double-precision complex | ||
DT_HALF = 19; | ||
DT_RESOURCE = 20; | ||
DT_VARIANT = 21; // Arbitrary C++ data types | ||
DT_UINT32 = 22; | ||
DT_UINT64 = 23; | ||
|
||
// Do not use! These are only for parameters. Every enum above | ||
// should have a corresponding value below (verified by types_test). | ||
DT_FLOAT_REF = 101; | ||
DT_DOUBLE_REF = 102; | ||
DT_INT32_REF = 103; | ||
DT_UINT8_REF = 104; | ||
DT_INT16_REF = 105; | ||
DT_INT8_REF = 106; | ||
DT_STRING_REF = 107; | ||
DT_COMPLEX64_REF = 108; | ||
DT_INT64_REF = 109; | ||
DT_BOOL_REF = 110; | ||
DT_QINT8_REF = 111; | ||
DT_QUINT8_REF = 112; | ||
DT_QINT32_REF = 113; | ||
DT_BFLOAT16_REF = 114; | ||
DT_QINT16_REF = 115; | ||
DT_QUINT16_REF = 116; | ||
DT_UINT16_REF = 117; | ||
DT_COMPLEX128_REF = 118; | ||
DT_HALF_REF = 119; | ||
DT_RESOURCE_REF = 120; | ||
DT_VARIANT_REF = 121; | ||
DT_UINT32_REF = 122; | ||
DT_UINT64_REF = 123; | ||
} | ||
// LINT.ThenChange( | ||
// https://www.tensorflow.org/code/tensorflow/c/tf_datatype.h, | ||
// https://www.tensorflow.org/code/tensorflow/go/tensor.go, | ||
// https://www.tensorflow.org/code/tensorflow/core/framework/tensor.cc, | ||
// https://www.tensorflow.org/code/tensorflow/core/framework/types.h, | ||
// https://www.tensorflow.org/code/tensorflow/core/framework/types.cc, | ||
// https://www.tensorflow.org/code/tensorflow/python/framework/dtypes.py, | ||
// https://www.tensorflow.org/code/tensorflow/python/framework/function.py) | ||
|
||
// For identifying the underlying type of a variant. For variants, the types | ||
// listed here are a subset of the types in the variant type registry, | ||
// corresponding to commonly used variants which must occasionally be | ||
// special-cased. | ||
enum SpecializedType { | ||
// Invalid/unknown specialized type. | ||
ST_INVALID = 0; | ||
// "tensorflow::TensorList" in the variant type registry. | ||
ST_TENSOR_LIST = 1; | ||
// "tensorflow::data::Optional" in the variant type registry. | ||
ST_OPTIONAL = 2; | ||
} |
Oops, something went wrong.