part3 正文:
上文說到,tf model server 搭建完成诉探,這時(shí)距離真正的應(yīng)用可以說完事具備只差東風(fēng)日熬,本節(jié)主要講述概要的第四部分,推薦系統(tǒng)sever對(duì)dnn model server的client阵具。本文主要從TFrecords碍遍,數(shù)據(jù)結(jié)構(gòu)定铜,python對(duì)dnn model server的client,以及推薦系統(tǒng)server對(duì)model server的client怕敬,三個(gè)方面來進(jìn)行闡述揣炕。
(1)準(zhǔn)備知識(shí)點(diǎn)之TFrecords。
TensorFlow 提供了一種統(tǒng)一的格式來存儲(chǔ)數(shù)據(jù)东跪,這就是TFrecord畸陡。這樣的好處就是避免了我們自己在trainmodel 和應(yīng)用model時(shí)候使用自己定義的數(shù)據(jù)結(jié)構(gòu)來通信,可維護(hù)性非常差虽填。TFrecord文件中的數(shù)據(jù)都是通過tf.train.Example PB格式存儲(chǔ)的丁恭,具體可以參見git clone --recurse-submodules https://github.com/tensorflow/serving后serving/tensorflow/core/example/example.proto,serving/tensorflow/core/example/feature.proto 這兩個(gè)proto文件里面有Example數(shù)據(jù)結(jié)構(gòu)的定義,以及具體的case斋日。將兩個(gè)文件里的定義merge一下牲览,如下圖1所示。也就是說構(gòu)造一個(gè)Example 實(shí)例只需要構(gòu)造一個(gè)Features恶守,而構(gòu)造Features只需要構(gòu)造一個(gè)key是string第献,value 是Feature的map。而Feature就相對(duì)簡單兔港。就是BytesList,FloatList,Int64List其中之一庸毫,分別對(duì)應(yīng)string類型的特征,float類型的特征,以及int型特征。同樣BytesList,FloatList,Int64List的定義也在serving/tensorflow/core/example/feature.proto中禾酱。每一個(gè)Example就是一個(gè)訓(xùn)練的實(shí)例。大家要對(duì)這個(gè)概念清晰载佳。說到這里可能大家依然不能知道,我用python怎么構(gòu)造一個(gè)Example兑徘,或者我用java如何構(gòu)造一個(gè)Example刚盈。下面會(huì)在講述client時(shí)候直接上代碼。圖2附proto文件中Example的一個(gè)具體例子挂脑,看完之后相信就可以基本明白如何構(gòu)造。featureMap里面value就是訓(xùn)練model時(shí)候每一維特征值欲侮。key就是這個(gè)特征對(duì)應(yīng)的名字崭闲,可以隨便取,只要能和train的時(shí)候?qū)?yīng)好就可以威蕉。
(2)python 對(duì)Dnn model server的client刁俭。
在搭建tf model server的過程中,需要及時(shí)測(cè)一下韧涨,所搭的server是否是ok可用的牍戚,那么就需要client侮繁。為什么首先要講python對(duì)model server的client,因?yàn)樵诖罱╰f serving的時(shí)候如孝,官網(wǎng)給出的tutorial 中宪哩,有一個(gè)簡易的minist數(shù)字識(shí)別的server與client的 testcase。請(qǐng)參考https://www.tensorflow.org/serving/serving_basic第晰。以及下圖3.
在我將model export出锁孟,啟動(dòng)了服務(wù)后,通過/serving/tensorflow_serving/apis/prediction_service.proto, /serving/tensorflow_serving/apis/predict.proto查看到通信的Request需要構(gòu)造茁瘦,第一部分ModelSpec定義在/serving/tensorflow_serving/apis/predict.proto品抽,不再粘貼有三個(gè)成員變量 1是modelname,和export時(shí)候?qū)?yīng)就可以2.是model version可以不指定甜熔,默認(rèn)最新的model version加載。3是signature_name這個(gè)和export時(shí)候一樣就可以腔稀。第二部分key string盆昙,通過注釋可以看到默認(rèn)情況下都是“inputs”,value是TensorProto烧颖。TensorProto的定義在/serving/tensorflow/core/framework/tensor.proto中弱左,這里也不再貼圖而是簡述一下.TensorProto有很多成員變量,但是有一些是不需要的下面只說一些必須的炕淮。1.DataType拆火,需要說明這個(gè)Tensor的數(shù)據(jù)類型,這里用的string涂圆,是將上文介紹的Example序列化成的string们镜。2.tensor_shape,因?yàn)閠ensor其實(shí)可以理解成一個(gè)list,所以這里就是list size润歉,用算法的術(shù)語說就是有多少個(gè)訓(xùn)練實(shí)例模狭。3.從定義的repeated的各種類型中,選取合理的一種類型踩衩,這里選repeated bytes string_val=8. 上述信息填充完整TensorProto就填充完整了嚼鹉。第三部分output_filter 通過看注釋,說的是當(dāng)不定義時(shí)候所有的input tensor 會(huì)被返回驱富,這是符合我們的要求的锚赤。所以這里不用指定。
解讀完這個(gè)之后我們就可以寫代碼了褐鸥。這里特別感謝大神https://github.com/MtDersvan/tf_playground/blob/master/wide_and_deep_tutorial/wide_and_deep_basic_serving.md线脚,在這里簡單寫的model export的方法以及server client如果構(gòu)造輸入的request,還包括如何寫到build文件里,供bazel的編譯浑侥。在從github上看到這個(gè)的時(shí)候突然想到了姚明06年fiba世錦賽評(píng)價(jià)王治郅的話姊舵,“彷佛在沙漠里待了10天后的第一口水”。上面提到的git鏈接里只給出了預(yù)測(cè)一個(gè)實(shí)例的代碼寓落,下面截圖給出多個(gè)實(shí)例預(yù)測(cè)的一個(gè)demo括丁。feature_dict 也就是根據(jù)自己訓(xùn)練模型的時(shí)候使用的特征構(gòu)造的feature。構(gòu)造完就可以編譯bazel build //tensorflow_serving/example:wide_and_deep_client,然后運(yùn)行bazel-bin/tensorflow_serving/example/wide_and_deep_client --model=wide_and_deep --server=ip:port. 如果能返回正常的結(jié)果證明測(cè)試過程已經(jīng)全部走通零如。另外關(guān)于grpc的python client與java client的通信細(xì)節(jié)與使用等這里不做闡述躏将,默認(rèn)都會(huì)。如需參考考蕾,請(qǐng)參考:https://grpc.io/祸憋。
(3)推薦server對(duì)tf model server的client。
由于我們的推薦引擎server是用java書寫的肖卧,所以需要將/serving/目錄下的所有proto文件全部生成java的api文件也就是從*.proto=>*.java, 然后將這些java導(dǎo)入我們的java 工程蚯窥。當(dāng)然還需要利用protoc-gen-grpc-java把 /server/tensorflow_serving/apis/prediction_service.proto 生成一個(gè)java的通信文件。來完成grpc的通信塞帐。具體步驟請(qǐng)參考下面拦赠。
1.由于tf server 是采用的grpc通信,所以需要編譯protobuffer文件產(chǎn)出我們需要的client api葵姥,完成client代碼的編寫與通信荷鼠。
2.因?yàn)樵诓僮鱬rotoc 生成java過程中需要把 serving 目錄下的文件夾文件夾移動(dòng),所以為了不破壞成產(chǎn)環(huán)境榔幸,可以cp 一份serving_bak,專門生成client端api允乐,而且如果你是之前安裝了tensorflow的話,可能這里你不運(yùn)行/server/tensorflow/configure 等安裝步驟削咆,這個(gè)時(shí)候發(fā)現(xiàn) 有兩層tensorflow目錄 /server/tensorflow/tensorflow 直接拷貝出一層就可以牍疏,木啥大問題。
3.cp -r serving serving_bak
4.由于java 很多工程都是在特定的package下拨齐,比如我們的在compay_name.recommend 下鳞陨,所以在運(yùn)行protoc生成api之前,我們需要改變一下.proto 文件的java package.? 所有的proto文件在"tensorflow_serving/apis/", "tensorflow/core/example/", "tensorflow/core/framework/", "tensorflow/core/protobuf/","tensorflow/core/lib/core/", 其中tensorflow_serving/apis/下的所有proto沒有 option java_package = ""這一行瞻惋。所以我們直接添加 option java_package = "compay_name.recommend.tensorflow.serving"厦滤。其余文件夾下的proto原來就有option java_package = ""這一行,所有在原來的基礎(chǔ)上添加上這里的前綴compay_name.recommend就可以了歼狼。自己寫個(gè)腳本就可以馁害,我的腳本就不公布到這里了。這個(gè)過程不是壁壘蹂匹。
5.運(yùn)行一下由proto 生成java的腳本,見圖5.最后將這些文件放倒java項(xiàng)目的目錄結(jié)構(gòu)見圖6
6.運(yùn)行生成通信文件protoc? --plugin=protoc-gen-grpc-java=插件路徑 ? --grpc-java_out=hh --proto_path=. tensorflow_serving/apis/prediction_service.proto
番外介紹一下protoc和protoc-gen-grpc-java的安裝凹蜈,凌晨4點(diǎn)的北京也不是白見的限寞。安裝protobuf忍啸,按照這個(gè)網(wǎng)址https://github.com/google/protobuf/tree/master/src,首先clone下來源碼問題然后一步步操作問題不大履植。安裝的版本是3.3.0
然后是安裝protoc-gen-grpc-java 首先clonehttps://github.com/grpc/grpc-java.git计雌,其次cd? compiler, 然后../gradlew java_pluginExecutable 然后../gradlew test很容易就成功了。但是我在編譯過程中出現(xiàn)了一個(gè)問題/usr/bin/ld: cannot find -lstdc++玫霎,然后搜百度凿滤,google,可能是軟鏈壞了庶近,然后重新ln -s翁脆,重新裝gcc,g++鼻种,寫Helloworld.cpp反番,換機(jī)器重新搞環(huán)境都不行,不知不覺搞了兩個(gè)多小時(shí)叉钥,一看表罢缸。4點(diǎn)了。郁悶的睡了投队,第二天起來之后好好讀了Build文件build.gradle,發(fā)現(xiàn)了是依賴的靜態(tài)libstdc++枫疆。這才抱著試試看的態(tài)度,yum installlibstdc++48-static.x86_64,裝了一下這個(gè)static,發(fā)現(xiàn)ok了敷鸦。
上述所有工作搞完之后就進(jìn)入了代碼的書寫階段息楔,需要在maven項(xiàng)目中引入下圖的一些依賴。這些從grpc的官網(wǎng)上都能看到轧膘。當(dāng)然還有一個(gè)tensorflow的一些基礎(chǔ)包钞螟。
從生成的java api可以看出,每一種數(shù)據(jù)結(jié)構(gòu)谎碍,都是有一個(gè)builder鳞滨。想生成這種數(shù)據(jù)結(jié)構(gòu)需要先生成這個(gè)數(shù)據(jù)結(jié)構(gòu)的builder。然后build一下就生成了相應(yīng)的數(shù)據(jù)結(jié)構(gòu)蟆淀。話不多說拯啦。直接上代碼。下圖中是構(gòu)建request的過程熔任。tensorProto是由許多個(gè)實(shí)例序列化成string夠成的褒链。在圖10中,我們看到docid疑苔,userid 和三個(gè)打了馬賽克的特征是string類型的甫匹。也就是需要embeding的特征。不同的任務(wù)特征需要仔細(xì)篩選這里就不誤導(dǎo)大家了所以打了馬賽克。
參考:
引用1兵迅。https://github.com/MtDersvan/tf_playground/blob/master/wide_and_deep_tutorial/wide_and_deep_basic_serving.md
完成于20170830,如轉(zhuǎn)載請(qǐng)注明出處抢韭。