轉發(fā):TensorFlow saved_model 模塊

版權聲明:本文為博主原創(chuàng)文章事哭,未經(jīng)博主允許不得轉載抠艾。 https://blog.csdn.net/thriving_fcl/article/details/75213361

saved_model模塊主要用于TensorFlow Serving。TF Serving是一個將訓練好的模型部署至生產(chǎn)環(huán)境的系統(tǒng)捌浩,主要的優(yōu)點在于可以保持Server端與API不變的情況下快集,部署新的算法或進行試驗,同時還有很高的性能葵袭。

保持Server端與API不變有什么好處呢涵妥?有很多好處,我只從我體會的一個方面舉例子說明一下坡锡,比如我們需要部署一個文本分類模型蓬网,那么輸入和輸出是可以確定的,輸入文本鹉勒,輸出各類別的概率或類別標簽帆锋。為了得到較好的效果,我們可能想嘗試很多不同的模型禽额,CNN锯厢,RNN,RCNN等脯倒,這些模型訓練好保存下來以后实辑,在inference階段需要重新載入這些模型,我們希望的是inference的代碼有一份就好盔憨,也就是使用新模型的時候不需要針對新模型來修改inference的代碼徙菠。這應該如何實現(xiàn)呢?

在TensorFlow 模型保存/載入的兩種方法中總結過郁岩。

1. 僅用Saver來保存/載入變量婿奔。這個方法顯然不行,僅保存變量就必須在inference的時候重新定義Graph(定義模型)问慎,這樣不同的模型代碼肯定要修改萍摊。即使同一種模型,參數(shù)變化了如叼,也需要在代碼中有所體現(xiàn)冰木,至少需要一個配置文件來同步,這樣就很繁瑣了笼恰。

2. 使用tf.train.import_meta_graph導入graph信息并創(chuàng)建Saver踊沸, 再使用Saver restore變量。相比第一種社证,不需要重新定義模型逼龟,但是為了從graph中找到輸入輸出的tensor,還是得用graph.get_tensor_by_name()來獲取追葡,也就是還需要知道在定義模型階段所賦予這些tensor的名字腺律。如果創(chuàng)建各模型的代碼都是同一個人完成的奕短,還相對好控制,強制這些輸入輸出的命名都一致即可匀钧。如果是不同的開發(fā)者翎碑,要在創(chuàng)建模型階段就強制tensor的命名一致就比較困難了。這樣就不得不再維護一個配置文件之斯,將需要獲取的tensor名稱寫入日杈,然后從配置文件中讀取該參數(shù)。

經(jīng)過上面的分析發(fā)現(xiàn)吊圾,要實現(xiàn)inference的代碼統(tǒng)一达椰,使用原來的方法也是可以的,只不過TensorFlow官方提供了更好的方法项乒,并且這個方法不僅僅是解決這個問題啰劲,所以還是得學習使用saved_model這個模塊。

saved_model 保存/載入模型

先列出會用到的API

class tf.saved_model.builder.SavedModelBuilder

# 初始化方法

__init__(export_dir)

# 導入graph與變量信息

add_meta_graph_and_variables(

? ? sess,

? ? tags,

? ? signature_def_map=None,

? ? assets_collection=None,

? ? legacy_init_op=None,

? ? clear_devices=False,

? ? main_op=None

)

# 載入保存好的模型

tf.saved_model.loader.load(

? ? sess,

? ? tags,

? ? export_dir,

? ? **saver_kwargs

)


(1) 最簡單的場景檀何,只是保存/載入模型

保存

要保存一個已經(jīng)訓練好的模型蝇裤,使用下面三行代碼就可以了。

builder = tf.saved_model.builder.SavedModelBuilder(saved_model_dir)

builder.add_meta_graph_and_variables(sess, ['tag_string'])

builder.save()


首先構造SavedModelBuilder對象频鉴,初始化方法只需要傳入用于保存模型的目錄名栓辜,目錄不用預先創(chuàng)建。

add_meta_graph_and_variables方法導入graph的信息以及變量垛孔,這個方法假設變量都已經(jīng)初始化好了藕甩,對于每個SavedModelBuilder這個方法一定要執(zhí)行一次用于導入第一個meta graph。

第一個參數(shù)傳入當前的session周荐,包含了graph的結構與所有變量狭莱。

第二個參數(shù)是給當前需要保存的meta graph一個標簽,標簽名可以自定義概作,在之后載入模型的時候腋妙,需要根據(jù)這個標簽名去查找對應的MetaGraphDef,找不到就會報如RuntimeError: MetaGraphDef associated with tags 'foo' could not be found in SavedModel這樣的錯讯榕。標簽也可以選用系統(tǒng)定義好的參數(shù)骤素,如tf.saved_model.tag_constants.SERVING與tf.saved_model.tag_constants.TRAINING。

save方法就是將模型序列化到指定目錄底下愚屁。

保存好以后到saved_model_dir目錄下济竹,會有一個saved_model.pb文件以及variables文件夾。顧名思義霎槐,variables保存所有變量送浊,saved_model.pb用于保存模型結構等信息。

載入

使用tf.saved_model.loader.load方法就可以載入模型栽燕。如

meta_graph_def = tf.saved_model.loader.load(sess, ['tag_string'], saved_model_dir)

1

第一個參數(shù)就是當前的session罕袋,第二個參數(shù)是在保存的時候定義的meta graph的標簽,標簽一致才能找到對應的meta graph碍岔。第三個參數(shù)就是模型保存的目錄浴讯。

load完以后,也是從sess對應的graph中獲取需要的tensor來inference蔼啦。如

x = sess.graph.get_tensor_by_name('input_x:0')

y = sess.graph.get_tensor_by_name('predict_y:0')

# 實際的待inference的樣本

_x = ...

sess.run(y, feed_dict={x: _x})


這樣和之前的第二種方法一樣榆纽,也是要知道tensor的name。那么如何可以在不知道tensor name的情況下使用呢捏肢? 那就需要給add_meta_graph_and_variables方法傳入第三個參數(shù)奈籽,signature_def_map。

(2) 使用SignatureDef

關于SignatureDef我的理解是鸵赫,它定義了一些協(xié)議衣屏,對我們所需的信息進行封裝,我們根據(jù)這套協(xié)議來獲取信息辩棒,從而實現(xiàn)創(chuàng)建與使用模型的解耦狼忱。SignatureDef的結構以及相關詳細的文檔在:https://github.com/tensorflow/serving/blob/master/tensorflow_serving/g3doc/signature_defs.md

相關API

# 構建signature

tf.saved_model.signature_def_utils.build_signature_def(

? ? inputs=None,

? ? outputs=None,

? ? method_name=None

)

# 構建tensor info

tf.saved_model.utils.build_tensor_info(tensor)


SignatureDef,將輸入輸出tensor的信息都進行了封裝一睁,并且給他們一個自定義的別名钻弄,所以在構建模型的階段,可以隨便給tensor命名者吁,只要在保存訓練好的模型的時候窘俺,在SignatureDef中給出統(tǒng)一的別名即可。

TensorFlow的關于這部分的例子中用到了不少signature_constants复凳,這些constants的用處主要是提供了一個方便統(tǒng)一的命名瘤泪。在我們自己理解SignatureDef的作用的時候,可以先不用管這些染坯,遇到需要命名的時候均芽,想怎么寫怎么寫。

保存

假設定義模型輸入的別名為“input_x”单鹿,輸出的別名為“output” 掀宋,使用SignatureDef的代碼如下

builder = tf.saved_model.builder.SavedModelBuilder(saved_model_dir)

# x 為輸入tensor, keep_prob為dropout的prob tensor

inputs = {'input_x': tf.saved_model.utils.build_tensor_info(x),

? ? ? ? ? ? 'keep_prob': tf.saved_model.utils.build_tensor_info(keep_prob)}

# y 為最終需要的輸出結果tensor

outputs = {'output' : tf.saved_model.utils.build_tensor_info(y)}

signature = tf.saved_model.signature_def_utils.build_signature_def(inputs, outputs, 'test_sig_name')

builder.add_meta_graph_and_variables(sess, ['test_saved_model'], {'test_signature':signature})

builder.save()


上述inputs增加一個keep_prob是為了說明inputs可以有多個, build_tensor_info方法將tensor相關的信息序列化為TensorInfo protocol buffer仲锄。

inputs劲妙,outputs都是dict,key是我們約定的輸入輸出別名儒喊,value就是對具體tensor包裝得到的TensorInfo镣奋。

然后使用build_signature_def方法構建SignatureDef,第三個參數(shù)method_name暫時先隨便給一個怀愧。

創(chuàng)建好的SignatureDef是用在add_meta_graph_and_variables的第三個參數(shù)signature_def_map中侨颈,但不是直接傳入SignatureDef對象余赢。事實上signature_def_map接收的是一個dict,key是我們自己命名的signature名稱哈垢,value是SignatureDef對象妻柒。

載入

載入與使用的代碼如下

## 略去構建sess的代碼

signature_key = 'test_signature'

input_key = 'input_x'

output_key = 'output'

meta_graph_def = tf.saved_model.loader.load(sess, ['test_saved_model'], saved_model_dir)

# 從meta_graph_def中取出SignatureDef對象

signature = meta_graph_def.signature_def

# 從signature中找出具體輸入輸出的tensor name

x_tensor_name = signature[signature_key].inputs[input_key].name

y_tensor_name = signature[signature_key].outputs[output_key].name

# 獲取tensor 并inference

x = sess.graph.get_tensor_by_name(x_tensor_name)

y = sess.graph.get_tensor_by_name(y_tensor_name)

# _x 實際輸入待inference的data

sess.run(y, feed_dict={x:_x})


從上面兩段代碼可以知道,我們只需要約定好輸入輸出的別名耘分,在保存模型的時候使用這些別名創(chuàng)建signature举塔,輸入輸出tensor的具體名稱已經(jīng)完全隱藏,這就實現(xiàn)創(chuàng)建模型與使用模型的解耦求泰。

---------------------

作者:thriving_fcl

來源:CSDN

原文:https://blog.csdn.net/thriving_fcl/article/details/75213361

版權聲明:本文為博主原創(chuàng)文章央渣,轉載請附上博文鏈接!

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渴频,一起剝皮案震驚了整個濱河市芽丹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枉氮,老刑警劉巖志衍,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異聊替,居然都是意外死亡楼肪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門惹悄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來春叫,“玉大人,你說我怎么就攤上這事泣港≡葜常” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵当纱,是天一觀的道長呛每。 經(jīng)常有香客問我,道長坡氯,這世上最難降的妖魔是什么晨横? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮箫柳,結果婚禮上手形,老公的妹妹穿的比我還像新娘。我一直安慰自己悯恍,他們只是感情好库糠,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涮毫,像睡著了一般瞬欧。 火紅的嫁衣襯著肌膚如雪贷屎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天艘虎,我揣著相機與錄音豫尽,去河邊找鬼。 笑死顷帖,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的渤滞。 我是一名探鬼主播贬墩,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妄呕!你這毒婦竟也來了陶舞?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤绪励,失蹤者是張志新(化名)和其女友劉穎肿孵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疏魏,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡停做,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了大莫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛉腌。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖只厘,靈堂內(nèi)的尸體忽然破棺而出烙丛,到底是詐尸還是另有隱情,我是刑警寧澤羔味,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布河咽,位于F島的核電站,受9級特大地震影響赋元,放射性物質(zhì)發(fā)生泄漏忘蟹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一们陆、第九天 我趴在偏房一處隱蔽的房頂上張望寒瓦。 院中可真熱鬧,春花似錦坪仇、人聲如沸杂腰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喂很。三九已至惜颇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間少辣,已是汗流浹背凌摄。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漓帅,地道東北人锨亏。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像忙干,于是被迫代替她去往敵國和親器予。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 該文章為轉載文章捐迫,作者簡介:汪劍乾翔,現(xiàn)在在出門問問負責推薦與個性化。曾在微軟雅虎工作施戴,從事過搜索和推薦相關工作反浓。 T...
    名字真的不重要閱讀 5,208評論 0 3
  • 在這篇tensorflow教程中,我會解釋: 1) Tensorflow的模型(model)長什么樣子赞哗? 2) 如...
    JunsorPeng閱讀 3,402評論 1 6
  • 這篇文章是針對有tensorflow基礎但是記不住復雜變量函數(shù)的讀者雷则,文章列舉了從輸入變量到前向傳播,反向優(yōu)化肪笋,數(shù)...
    horsetif閱讀 1,160評論 0 1
  • 這兩天又走在十字路口巧婶,每次面臨十字路口都會有無數(shù)的疑問,讓我摸不著頭腦涂乌,可是這種問題又無法能有一個準確的結果艺栈。 唯...
    不期而遇的故事閱讀 562評論 6 0
  • 你想成為什么樣的人,需要尊重那樣的人湾盒,才有可能成為那樣的人湿右。 《維摩詰經(jīng)》中有一則小故事,維摩詰居士生病罚勾,諸佛去居...
    楊繼昌心理咨詢師閱讀 547評論 0 1