"Введение"TensorFlow Serving предоставляет интерфейс GRPC для эффективного выполнения запросов прогнозирования к модели, но он предоставляет только API на основе Python. Если мы хотим использовать другие языки для доступа к GRPC, нам нужно вручную сгенерировать соответствующий файл интерфейса GRPC. В этой статье в основном представлены метод и метод использования инструмента protoc для создания файла API обслуживания TensorFlow, а также приведен полный пример проекта для справки.
Компиляция файла ProtoBuf
TensorFlow Servingоснован наProtocol Bufferсогласие на выполнениеGPRCобщение, исходный код которого начинается сprotoРяд структур данных определен для файлов с суффиксами (message) а такжеRPCСлужить (service), которые используются для представления формата обмена данными и интерфейса для выполнения удаленных операций соответственно.protoСами файлы нельзя использовать непосредственно в коде, их необходимо дополнительно преобразовать в файлы кода, зависящие от языка, для нормальной компиляции и запуска.
Protocol Bufferофициально предоставленProtocol Buffer Compiler (protoc) скомпилировать инструменты дляprotoфайл для компиляции и создания файлов кода, зависящих от языка, инструмент в настоящее время поддерживает работу по генерации кода на нескольких языках, включаяgolang,java,c++а такжеc#Ждать. использоватьprotocИнструменты могут значительно сократить наши усилия по кодированию, позволяя нам больше сосредоточиться на конкретных бизнес-реализациях без хлопот, связанных с определением различных структур данных, зависящих от языка.
Поэтому при использовании других языков сTensorFlow ServingпровестиGRPCПри общении мы должны полагаться наprotocинструменты для создания зависимых от языкаAPIфайл для последующего использования. Следует отметить, что из-заTensorFlow Servingчасть исходного кодаprotoфайл должен зависеть отTensorFlowсерединаprotoфайл, поэтому нам нужно использовать исходный код обоих для создания необходимогоAPIдокумент.
Ниже краткое введениеprotocинструменты вLinuxПроцесс установки под систему:
-
первый в
Protocol BufferизGithubЗагрузите последнюю версию страницы выпуска программного обеспеченияprotocДвоичный сжатый файл пакета или используйте следующую команду для прямой загрузки.wget https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/protoc-3.12.3-linux-x86_64.zip -
Затем распакуйте архив в
/usr/local/protocПод содержанием.unzip protoc-3.12.3-linux-x86_64.zip -d /usr/local/protoc -
Тогда будет
/usr/local/protoc/binкаталог добавлен вPATHв переменных окружения. Вы можете добавить следующую строку в/etc/profileдокумент для достижения вышеуказанных целей.export PATH=$PATH:/usr/local/protoc/bin -
Окончательная тестовая установка прошла успешно
protoc --version
Генерация и использование файла API
Вообще говоря, покаProtocol BufferиGRPCПоддерживаемые языки могут быть сгенерированыTensorFlow ServingизAPIдокумент. в предыдущей статьеTensorFlow 2.x 模型 Serving 服务中Я уже представил использованиеPythonвыполнятьGPRCПример запроса, эта статья в основном знакомит с использованиемGolangа такжеJavaгенерироватьTensorFlow ServingизAPIфайл и провестиGPRCспособ запроса.
Чтобы сгенерировать исполняемый файл кода, нам сначала нужноTensorFlowиTensorFlow Servingисходный кодcloneк местному.
mkdir tensorflow-serving-api && cd tensorflow-serving-api
git clone https://github.com/tensorflow/tensorflow.git
git clone https://github.com/tensorflow/serving.git
Затем вы можете использовать исходный кодprotoфайл для создания соответствующего языкаTensorFlow Serving APIфайл.
Golang
в созданииgolangСвязанныйAPIфайл кода, нам нужно установитьgolangокружающая среда и некоторыеprotocПлагины, помогающие нам в операциях по созданию файлов. Следующие связанные операцииLinuxСистема завершена.
-
Установить
golang, процесс выглядит следующим образом.wget https://dl.google.com/go/go1.14.4.linux-amd64.tar.gz tar zxvf go1.14.4.linux-amd64.tar.gz -C /usr/local export PATH=$PATH:/usr/local/go/bin go version -
Установить
protoc-gen-goплагин для генерацииgoдокумент.go get -u google.golang.org/protobuf/cmd/protoc-gen-go # or go get -u github.com/golang/protobuf/protoc-gen-goprotoc-gen-goПо умолчанию он будет установлен в$GOPATH/binкаталог, вам нужно убедиться, что каталог находится вPATHниже, чтобыprotocИнструмент может найти плагин. -
Установить
grpcплагин для генерацииgrpc goдокумент.go get -u google.golang.org/grpc -
Переключите исходный код на указанную ветку или тег.
cd tensorflow-serving-api/tensorflow git checkout tags/v2.2.0 cd tensorflow-serving-api/serving git checkout tags/2.2.0 -
использовать
protocсоздание инструментаgoдокумент.cd tensorflow-serving-api protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang serving/tensorflow_serving/*/*.proto protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang serving/tensorflow_serving/sources/storage_path/*.proto protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang tensorflow/tensorflow/core/framework/*.proto protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang tensorflow/tensorflow/core/example/*.proto protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang tensorflow/tensorflow/core/protobuf/*.proto protoc -I=serving -I=tensorflow --go_out=plugins=grpc:golang tensorflow/tensorflow/stream_executor/*.protoв
-IуказанныйprotoПуть к файлу для поиска зависимых файлов, который можно указать несколько раз.--go_outсохранение указаноgoкаталог файла (здесьgolang) и используемыйgrpcплагин. Последний элемент команды указан как подстановочный знакprotoВходное местоположение файла.Что касается того, почему выберите выше
protoфайл дляAPIсоздано, основано на фактическом использовании иprotoЗависимости между файлами определяются. можно начать сservingизprotoНачните с исходного кода и обратитесь к егоPython GRPCРеализация кода примера, найти записьprotoфайл, то по себе и своим зависимостямprotoфайл для создания соответствующегоAPIкодовые файлы, а затем выполнять тесты кодирования для проверки недостатков и заполнения упущений до тех пор, пока все кодовые файлы не будут скомпилированы без ошибок. -
После выполнения вышеуказанной команды
golangПод каталогом создаются два каталога, а именноgithub.comиtensorflow_serving, первый содержит отtensorflowв исходном кодеprotoфайл созданgoфайл, последний содержит изservingв исходном кодеprotoфайл созданgoдокумент. так какtensorflowв исходном кодеprotoфайлы содержатgo_packageварианты, такие какoption go_package = "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/tensor_go_proto";, которые определяют сгенерированныйgoвыходной каталог файла, поэтому он сгенерированgoфайл будет вgithub.comкаталог иservingв исходном кодеprotoфайл не содержит этой опции, поэтомуgoВыходной каталог файла по умолчанию находится в том же каталоге, что и исходный файл. -
tensorflow_servingсоздается в каталогеgoОшибки циклических ссылок могут возникать в файлах следующим образом:import cycle not allowed package github.com/alex/tensorflow-serving-api-go imports tensorflow_serving/apis imports tensorflow_serving/core imports tensorflow_serving/apisВ этот момент вам нужно
tensorflow_serving/coreПод содержаниемlogging.pb.goдокументы иtensorflow_serving/apisв каталогеprediction_log.pb.goудаление файла для решения вышеуказанной проблемы. Удаление вышеуказанных файлов кода не влияет на последующиеGRPCЗапрос предсказания модели. -
Предположим, у меня есть файл с именем
first_modelМодель развернута вTensorFlow ServingИнформация о метаданных службы выглядит следующим образом:$ curl http://localhost:8501/v1/models/first_model/versions/0/metadata { "model_spec": { "name": "first_model", "signature_name": "", "version": "0" }, "metadata": { "signature_def": { "signature_def": { "serving_default": { "inputs": { "input_1": { "dtype": "DT_INT64", "tensor_shape": { "dim": [ { "size": "-1", "name": "" }, { "size": "31", "name": "" } ], "unknown_rank": false }, "name": "serving_default_input_1:0" } }, "outputs": { "output_1": { "dtype": "DT_FLOAT", "tensor_shape": { "dim": [ { "size": "-1", "name": "" }, { "size": "1", "name": "" } ], "unknown_rank": false }, "name": "StatefulPartitionedCall:0" } }, "method_name": "tensorflow/serving/predict" }, "__saved_model_init_op": { "inputs": {}, "outputs": { "__saved_model_init_op": { "dtype": "DT_INVALID", "tensor_shape": { "dim": [], "unknown_rank": true }, "name": "NoOp" } }, "method_name": "" } } } } }Нам нужно сосредоточиться на приведенной выше информации.
inputsпараметры, которые определяют входные данные для этой моделиkeyзначение (здесьinput_1) , размерность входных данных (здесь(-1, 31)) и тип входных данных (здесьDT_INT64). в ходе выполненияGRPCПри прогнозировании запроса входные данные, указанные в коде, должны совпадать с различной входной информацией, определенной в метаданных, иначе не удастся получить правильный вывод модели. -
Создайте
goпроект кfirst_modelОтправитьGRPCПрогноз запросов. Для получения подробной информации о конкретных проектах см.GithubРеализация и описание выше, здесь указан только код основной функции, а именно:package main import ( "context" "log" apis "tensorflow_serving/apis" "time" "github.com/golang/protobuf/ptypes/wrappers" "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/tensor_go_proto" "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/tensor_shape_go_proto" "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/types_go_proto" "google.golang.org/grpc" ) var ( // TensorFlow serving grpc address. address = "127.0.0.1:8500" ) func main() { // Create a grpc request. request := &apis.PredictRequest{ ModelSpec: &apis.ModelSpec{}, Inputs: make(map[string]*tensor_go_proto.TensorProto), } request.ModelSpec.Name = "first_model" request.ModelSpec.SignatureName = "serving_default" // request.ModelSpec.VersionChoice = &apis.ModelSpec_VersionLabel{VersionLabel: "stable"} request.ModelSpec.VersionChoice = &apis.ModelSpec_Version{Version: &wrappers.Int64Value{Value: 0}} request.Inputs["input_1"] = &tensor_go_proto.TensorProto{ Dtype: types_go_proto.DataType_DT_INT64, TensorShape: &tensor_shape_go_proto.TensorShapeProto{ Dim: []*tensor_shape_go_proto.TensorShapeProto_Dim{ &tensor_shape_go_proto.TensorShapeProto_Dim{ Size: int64(2), }, &tensor_shape_go_proto.TensorShapeProto_Dim{ Size: int64(31), }, }, }, Int64Val: []int64{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, } // Create a grpc connection. conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(10*time.Second)) if err != nil { log.Fatalf("couldn't connect: %s", err.Error()) } defer conn.Close() // Wrap the grpc uri with client. client := apis.NewPredictionServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() // Send the grpc request. response, err := client.Predict(ctx, request) if err != nil { log.Fatalf("couldn't get response: %v", err) } log.Printf("%+v", response) } -
GithubАдрес:https://github.com/AlexanderJLiu/tensorflow-serving-api/tree/master/golang
Java
в созданииjavaСвязанныйAPIфайл кода, нам нужно установитьjavaокружающая среда и некоторыеprotocПлагины, помогающие нам в операциях по созданию файлов. Следующие связанные операцииLinuxСистема завершена.
-
Установить
OpenJDK.# centos yum-config-manager --enable rhel-7-server-optional-rpms yum install java-11-openjdk-devel # ubuntu apt-get install openjdk-11-jdk # test java -version -
Установить
protoc-gen-grpc-java, генерироватьgrpc javaдокумент.wget https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/1.30.2/protoc-gen-grpc-java-1.30.2-linux-x86_64.exe mv protoc-gen-grpc-java-1.30.2-linux-x86_64.exe /usr/local/protoc/bin/protoc-gen-grpc-java -
Переключите исходный код на указанную ветку или тег.
cd tensorflow-serving-api/tensorflow git checkout tags/v2.2.0 cd tensorflow-serving-api/serving git checkout tags/2.2.0 -
использовать
protocсоздание инструментаjavaдокумент.cd tensorflow-serving-api protoc -I=serving -I=tensorflow --plugin=/usr/local/protoc/bin/protoc-gen-grpc-java --grpc-java_out=java --java_out=java serving/tensorflow_serving/*/*.proto protoc -I=serving -I=tensorflow --plugin=/usr/local/protoc/bin/protoc-gen-grpc-java --grpc-java_out=java --java_out=java serving/tensorflow_serving/sources/storage_path/*.protoв
-IуказанныйprotoПуть к файлу для поиска зависимых файлов, который можно указать несколько раз.--pluginуказано для использованияgrpcПуть к плагину.--grpc-java_outуказанныйgrpc javaКаталог, в котором сохранен файл.--java_outуказанныйjavaКаталог, в котором сохранен файл. Последний элемент команды указан как подстановочный знакprotoВходное местоположение файла.так как
TensorFlowОфициально на основеprotoфайл созданTensorFlowизjavaфайл, поэтому нам не нужно генерировать его самостоятельно и использовать непосредственно изmavenСклад может быть импортирован:implementation("org.tensorflow:proto:1.15.0"). -
Создайте
javaпроект кfirst_modelОтправитьGRPCПрогноз запросов. Для получения подробной информации о конкретных проектах см.GithubРеализация и описание выше, здесь указан только код основной функции, а именно:package com.github.alex; import java.util.Arrays; import java.util.concurrent.TimeUnit; import com.google.protobuf.Int64Value; import org.tensorflow.framework.DataType; import org.tensorflow.framework.TensorProto; import org.tensorflow.framework.TensorShapeProto; import org.tensorflow.framework.TensorShapeProto.Dim; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.stub.StreamObserver; import tensorflow.serving.Model.ModelSpec; import tensorflow.serving.Predict.PredictRequest; import tensorflow.serving.Predict.PredictResponse; import tensorflow.serving.PredictionServiceGrpc; import tensorflow.serving.PredictionServiceGrpc.PredictionServiceBlockingStub; import tensorflow.serving.PredictionServiceGrpc.PredictionServiceStub; public class App { public String getGreeting() { return "Hello world."; } public static void main(String[] args) { PredictRequest.Builder requestBuilder = PredictRequest.newBuilder(); ModelSpec.Builder modelSpecBuilder = ModelSpec.newBuilder(); modelSpecBuilder.setSignatureName("serving_default"); modelSpecBuilder.setName("first_model"); modelSpecBuilder.setVersion(Int64Value.newBuilder().setValue(0L)); requestBuilder.setModelSpec(modelSpecBuilder.build()); TensorProto.Builder tensorProtoBuilder = TensorProto.newBuilder(); tensorProtoBuilder.setDtype(DataType.DT_INT64); Dim[] dim = {Dim.newBuilder().setSize(1).build(), Dim.newBuilder().setSize(31).build()}; tensorProtoBuilder .setTensorShape(TensorShapeProto.newBuilder().addAllDim(Arrays.asList(dim))); // tensorProtoBuilder.setTensorShape(TensorShapeProto.newBuilder() // .addDim(Dim.newBuilder().setSize(1)).addDim(Dim.newBuilder().setSize(31))); Long[] inputs = {1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L}; tensorProtoBuilder.addAllInt64Val(Arrays.asList(inputs)); requestBuilder.putInputs("input_1", tensorProtoBuilder.build()); PredictRequest request = requestBuilder.build(); System.out.println(request); String target = "127.0.0.1:8500"; // Create a communication channel to the server, known as a Channel. Channels are // thread-safe and reusable. It is common to create channels at the beginning of your // application and reuse them until the application shuts down. ManagedChannel channel = ManagedChannelBuilder.forTarget(target) // Channels are secure by default (via SSL/TLS). For the example we disable TLS to // avoid needing certificates. .usePlaintext().build(); PredictionServiceBlockingStub stub = PredictionServiceGrpc.newBlockingStub(channel); try { PredictResponse response = stub.predict(request); System.out.println(response); channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } } -
GithubАдрес:https://github.com/AlexanderJLiu/tensorflow-serving-api/tree/master/java
Другие языки
я здесьGithubсоздалtensorflow-serving-apiпроект, который предназначен для созданияProtocol BufferиGRPCвсех поддерживаемых языковTensorFlow Serving APIфайл, а пример использования приведен в виде готового проекта.
Проект постепенно совершенствуется и был реализованGolang,Javaа такжеPythonлингвистическийTensorFlow Serving APIИ примеры проектов, в будущем будет добавлено больше языковых реализаций, и каждый может принять участие и внести свой вклад.
Адрес ссылки на проект:https://github.com/AlexanderJLiu/tensorflow-serving-api