產品環境模型部署,建立簡單Web APP,使用者上傳映像,運行Inception模型,實現映像自動分類。
建置TensorFlow服務開發環境。安裝Docker, 。用設定檔在本機上建立Docker映像,docker build --pull -t $USER/tensorflow-serving-devel 。映像運行容器,docker run -v $HOME:/mnt/home -p 9999:9999 -it $USER/tensorflow-serving-devel ,在home目錄載入到容器/mnt/home路徑,在終端機工作。用IDE或編輯器編輯程式碼,用容器運行建置工具,主機透過9999埠訪問,建置伺服器。 exit命令退出容器終端,停止運作。
TensorFlow服務程式C++寫,使用Google的Bazel建置工具。容器運行Bazel。 Bazel程式碼級管理第三方相依性。 Bazel自動下載建置。專案庫根目錄定義WORKSPACE檔案。 TensorFlow模型庫包含Inception模型程式碼。
TensorFlow服務在專案中作為Git子模組。 mkdir ~/serving_example,cd ~/serving_example,git init,git submodule add ,tf_serving,git submodule update --init --recursive 。
WORKSPACE檔案local_repository規則定義第三方依賴為本機儲存檔案。專案導入tf_workspace規則初始化TensorFlow相依性。
workspace(name = "serving")
local_repository(
name = "tf_serving",
path = __workspace_dir__ + "/tf_serving",#
local_repository(
path = __workspace_dir__ + "/tf_serving/tensorflow path = __workspace_dir__ + "/tf_serving/tensorflow .bzl', 'tf_workspace')
tf_workspace("tf_serving/tensorflow/", "@org_tensorflow")
bind(
# name = "libssl",# sl //:ssl",
)
bind(
name = "zlib",
actual = "@zlib_archive//: #local_repository(
name = "inception_model",
,給產品用。模型資料流程圖,必須從佔位符接收輸入,單步推斷計算輸出。 Inception模型(或一般影像辨識模型),JPEG編碼影像字串輸入,與從TFRecord檔案讀取輸入不同。定義輸入佔位符,呼叫函數轉換佔位符表示外部輸入為原始推斷模型輸入格式,影像字串轉換為各分量位於[0, 1]內像素張量,縮放影像尺寸,符合模型期望寬度高度,像素值轉換到模型要求區間[-1, 1]內。呼叫原始模型推斷方法,依據轉換輸入推斷結果。
推斷方法各參數賦值。從檢查點恢復參數值。週期性保存模型訓練檢查點文件,文件包含學習參數。最後一次儲存訓練檢查點檔案包含最後更新模型參數。下去載預訓練檢查點文件: 。在Docker容器中,cd /tmp, curl -0 , tar -xzf inception-v3-2016-03-01.tar.gz 。
import time
import sys
from tensorflow_serving.session_bundle import exporter##del
##def convert_external_inputs(external_x):image = tf.image.convert_image_dtype(tf.image.decode_jpeg(external_x, channels=3), tf.image.decode_jpeg(external_x, chan3m=3), tf.image.decode_jpeg(external_x, chan3_3), tf.flo~ tf .expand_dims(image, 0), [299, 299])
images = tf.mul(tf.sub(images, 0.5), 2)return return :
logits, _ = inception_model.inference(images, 1001) return logits
saver = tf.train.Saver()
##with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state(sys.argv[1])## pt 和ckpt.model_checkpoint_path:
saver.restore(sess, sys.argv[1] + "/" + ckpt.model_checkpoint_path)
)# # raise SystemExit
scores, class_ids = tf.nn.top_k(y, NUM_CLASSES_TO_RETURN)
classes = tf.contrib.lookup.index_to_string( tf .constant([str(i) for i in range(1001)]))
model_exporter = exporter.Exporter(saver)
簽名= exporter.classification_signature(##sor0, =類,scores_tensor=scores) model_exporter.init(default_graph_signature=signature, init_op=tf.initialize_all_tables())
的 model_exporter. . time()), sess)
一個建置規則BUILD檔。 inception -v3提到的檢查點檔案在/tmp/inception-v3/{currenttimestamp}/建立匯出器。 。 # "export.py",
"export.py",
],
deps = [
"@org_tensorflow //tensorflow:tensorflow_py",
],
)
#("@protobuf//:protobuf.bzl", "cc_proto_library")
#licc name="classification_service_proto",
srcs=["classification_service.proto"],
cc_libs = ["@protobuf//:protobuf"],
)##> [
" server.cc",
],
deps = [
": 選擇 flow:session_bundle_factory",
],
)
定義伺服器介面。TensorFlow服務使用gRPC協定(基於HTTP/2二進位協定)。支援建立伺服器和自動產生客戶端存根各種語言協定。緩衝區定義服務契約,用於gRPC IDL(介面定義語言)和二進位編碼。文字服務可用的可一介面。 Service介面必須實作。 ClassificationRequest {
// 位元組輸入= 1;
float petalWidth = 1;
float petalHeight = 1;
float petalHeight = 2;# float sepalHeight = 4;
};
重複 ClassificationClass 類別 = 1;
};
message ClassificationClass {
string name = 1;
float score = 2;
}
}
實作推斷伺服器。載入導出模型,呼叫推斷方法,實作ClassificationService::Service。匯出模型,建立SessionBundle對象,包含完全載入資料流程圖TF會話對象,定義匯出工具分類簽章元資料。 SessionBundleFactory類別建立SessionBundle對象,配置為pathToExportFiles指定路徑載入匯出模型,傳回建立SessionBundle實例unique指標。定義ClassificationServiceImpl,接收SessionBundle實例參數。
載入分類簽名,GetClassificationSignature函數載入模型匯出元資料ClassificationSignature,簽章指定所接收影像真實名稱的輸入張量邏輯名稱,以及資料流程圖輸出張量邏輯名稱對應推斷結果。將protobuf輸入變換為推斷輸入張量,request參數複製JPEG編碼影像字串到推斷張量。運行推斷,sessionbundle獲得TF會話對象,運行一次,傳入輸入輸出張量推斷。推斷輸出張量變換protobuf輸出,輸出張量結果複製到ClassificationResponse訊息指定形狀response輸出參數格式化。設定gRPC伺服器,SessionBundle物件配置,建立ClassificationServiceImpl實例樣板程式碼。
#include
#include
#include
#include 問題serving;
using namespace grpc;
問題 unique_ptr
SessionBundleFactory: :Create(session_bundle_config, &bundle_factory);
。 # }
class ClassificationServiceImpl final : public ClassificationService::Service {
private:
unique_ptr
Status classify(ServerContext* context, const ClassificationRe* ride {
ClassificationSignature 。 return Status(StatusCode: :INTERNAL, signatureStatus.error_message());
}
tensorflow::Tensor input(tensorflow::DT_STRING, tensorflow::TensorShape()); () = request->input();
vector
const tensorflow::Status inferenceStatus = sessionBundle->session->Run(
{{signature.input().tensor_name(), input}},
&outputs);
if (!inferenceStatus.ok()) {
for (int i = 0; i < outputs[0].NumElements(); ++i) {
ClassificationClass *classificationClass = response->add_classes();
classificationClass->set_name(outputs[0].flat
classificationClass->set_score(outputs[1].flat
}
return Status::OK;
}
};
int main(int argc, char** argv) {
if (argc < 3) {
cerr << "Usage: server
return 1;
}
const string serverAddress(string("0.0.0.0:") + argv[1]);
const string pathToExportFiles(argv[2]);
unique_ptr
ClassificationServiceImpl classificationServiceImpl(move(sessionBundle));
ServerBuilder builder;
builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials());
builder.RegisterService(&classificationServiceImpl);
unique_ptr
cout << "Server listening on " << serverAddress << endl;
server->Wait();
return 0;
}
通过服务器端组件从webapp访问推断服务。运行Python protocol buffer编译器,生成ClassificationService Python protocol buffer客户端:pip install grpcio cython grpcio-tools, python -m grpc.tools.protoc -I. --python_out=. --grpc_python_out=. classification_service.proto。生成包含调用服务stub classification_service_pb2.py 。服务器接到POST请求,解析发送表单,创建ClassificationRequest对象 。分类服务器设置一个channel,请求提交,分类响应渲染HTML,送回用户。容器外部命令python client.py,运行服务器。浏览器导航http://localhost:8080 访问UI。
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import cgi
import classification_service_pb2
from grpc.beta import implementations
class ClientApp(BaseHTTPRequestHandler):
def do_GET(self):
self.respond_form()
def respond_form(self, response=""):
form = """