摘要:最值得注意的一點(diǎn)是,整個(gè)圖都是在一個(gè)函數(shù)中定義和構(gòu)造的,那么這即不可讀也不可重復(fù)使用。
在 TensorFlow 中定義你的模型,可能會(huì)導(dǎo)致一個(gè)巨大的代碼量。那么,如何去組織代碼,使得它是一個(gè)高可讀性和高可重用的呢?如果你剛剛開始學(xué)習(xí)代碼架構(gòu),那么這里有一個(gè)例子,不妨學(xué)習(xí)一下。
定義計(jì)算圖
當(dāng)你設(shè)計(jì)一個(gè)模型的時(shí)候,從類出發(fā)是一個(gè)非常好的開始。那么如何來設(shè)計(jì)一個(gè)類的接口呢?通常,我們會(huì)為模型設(shè)計(jì)一些輸入接口和輸出目標(biāo)值,并且提供訓(xùn)練接口,驗(yàn)證接口,測(cè)試接口等等。
class
?
Model
:
? ??
def
?__init__
(
self
,
?data
,
?target
):
? ? ? ? data_size?
=
?
int
(
data
.
get_shape
()[
1
])
? ? ? ? target_size?
=
?
int
(
target
.
get_shape
()[
1
])
? ? ? ? weight?
=
?tf
.
Variable
(
tf
.
truncated_normal
([
data_size
,
?target_size
]))
? ? ? ? bias?
=
?tf
.
Variable
(
tf
.
constant
(
0.1
,
?shape
=[
target_size
]))
? ? ? ? incoming?
=
?tf
.
matmul
(
data
,
?weight
)
?
+
?bias
? ? ? ??
self
.
_prediction?
=
?tf
.
nn
.
softmax
(
incoming
)
? ? ? ? cross_entropy?
=
?
-
tf
.
reduce_sum
(
target
,
?tf
.
log
(
self
.
_prediction
))
? ? ? ??
self
.
_optimize?
=
?tf
.
train
.
RMSPropOptimizer
(
0.03
).
minimize
(
cross_entropy
)
? ? ? ? mistakes?
=
?tf
.
not_equal
(
? ? ? ? ? ? tf
.
argmax
(
target
,
?
1
),
?tf
.
argmax
(
self
.
_prediction
,
?
1
))
? ? ? ??
self
.
_error?
=
?tf
.
reduce_mean
(
tf
.
cast
(
mistakes
,
?tf
.
float32
))
? ??
@property
? ??
def
?prediction
(
self
):
? ? ? ??
return
?
self
.
_prediction
? ??
@property
? ??
def
?optimize
(
self
):
? ? ? ??
return
?
self
.
_optimize
? ??
@property
? ??
def
?error
(
self
):
? ? ? ??
return
?
self
.
_error
基本上,我們都會(huì)使用 TensorFlow 提供的代碼塊來構(gòu)建我們的模型。但是,它也存在一些問題。最值得注意的一點(diǎn)是,整個(gè)圖都是在一個(gè)函數(shù)中定義和構(gòu)造的,那么這即不可讀也不可重復(fù)使用。
使用 @property 裝飾器
如果你不了解裝飾器,那么可以先學(xué)習(xí)這篇文章。
如果我們只是把代碼分割成函數(shù),這肯定是行不通的,因?yàn)槊看握{(diào)用函數(shù)時(shí),圖都會(huì)被新代碼進(jìn)行擴(kuò)展。因此,我們要確保只有當(dāng)函數(shù)第一次被調(diào)用時(shí),這個(gè)操作才會(huì)被添加到圖中。這個(gè)方式就是懶加載(lazy-loading,使用時(shí)才創(chuàng)建)。
class
?
Model
:
? ??
def
?__init__
(
self
,
?data
,
?target
):
? ? ? ??
self
.
data?
=
?data
? ? ? ??
self
.
target?
=
?target
? ? ? ??
self
.
_prediction?
=
?
None
? ? ? ??
self
.
_optimize?
=
?
None
? ? ? ??
self
.
_error?
=
?
None
? ??
@property
? ??
def
?prediction
(
self
):
? ? ? ??
if
?
not
?
self
.
_prediction
:
? ? ? ? ? ? data_size?
=
?
int
(
self
.
data
.
get_shape
()[
1
])
? ? ? ? ? ? target_size?
=
?
int
(
self
.
target
.
get_shape
()[
1
])
? ? ? ? ? ? weight?
=
?tf
.
Variable
(
tf
.
truncated_normal
([
data_size
,
?target_size
]))
? ? ? ? ? ? bias?
=
?tf
.
Variable
(
tf
.
constant
(
0.1
,
?shape
=[
target_size
]))
? ? ? ? ? ? incoming?
=
?tf
.
matmul
(
self
.
data
,
?weight
)
?
+
?bias
? ? ? ? ? ??
self
.
_prediction?
=
?tf
.
nn
.
softmax
(
incoming
)
? ? ? ??
return
?
self
.
_prediction
? ??
@property
? ??
def
?optimize
(
self
):
? ? ? ??
if
?
not
?
self
.
_optimize
:
? ? ? ? ? ? cross_entropy?
=
?
-
tf
.
reduce_sum
(
self
.
target
,
?tf
.
log
(
self
.
prediction
))
? ? ? ? ? ? optimizer?
=
?tf
.
train
.
RMSPropOptimizer
(
0.03
)
? ? ? ? ? ??
self
.
_optimize?
=
?optimizer
.
minimize
(
cross_entropy
)
? ? ? ??
return
?
self
.
_optimize
? ??
@property
? ??
def
?error
(
self
):
? ? ? ??
if
?
not
?
self
.
_error
:
? ? ? ? ? ? mistakes?
=
?tf
.
not_equal
(
? ? ? ? ? ? ? ? tf
.
argmax
(
self
.
target
,
?
1
),
?tf
.
argmax
(
self
.
prediction
,
?
1
))
? ? ? ? ? ??
self
.
_error?
=
?tf
.
reduce_mean
(
tf
.
cast
(
mistakes
,
?tf
.
float32
))
? ? ? ??
return
?
self
.
_error
這個(gè)代碼組織已經(jīng)比第一個(gè)代碼好很多了。你的代碼現(xiàn)在被組織成一個(gè)多帶帶的功能。但是,由于懶加載的邏輯,這個(gè)代碼看起來還是有點(diǎn)臃腫。讓我們來看看如何可以改進(jìn)這個(gè)代碼。
Python 是一種相當(dāng)靈活的語言。所以,讓我告訴你如何去掉剛剛例子中的冗余代碼。我們將一個(gè)像 @property 一樣的裝飾器,但是只評(píng)估一次函數(shù)。它將結(jié)果存儲(chǔ)在一個(gè)以裝飾函數(shù)命名的成員中,并且在隨后的調(diào)用中返回該值。如果你不是很了解這個(gè)裝飾器是什么東西,你可以看看這個(gè)學(xué)習(xí)指南。
import
?functools
def
?lazy_property
(
function
):
? ? attribute?
=
?
"_cache_"
?
+
?
function
.
__name__
? ??
@property
? ??
@functools
.
wraps
(
function
)
? ??
def
?decorator
(
self
):
? ? ? ??
if
?
not
?hasattr
(
self
,
?attribute
):
? ? ? ? ? ? setattr
(
self
,
?attribute
,
?
function
(
self
))
? ? ? ??
return
?getattr
(
self
,
?attribute
)
? ??
return
?decorator
使用這個(gè)裝飾器,我們可以將上面的代碼簡(jiǎn)化如下:
class
?
Model
:
? ??
def
?__init__
(
self
,
?data
,
?target
):
? ? ? ??
self
.
data?
=
?data
? ? ? ??
self
.
target?
=
?target
? ? ? ??
self
.
prediction
? ? ? ??
self
.
optimize
? ? ? ??
self
.
error
? ??
@lazy_property
? ??
def
?prediction
(
self
):
? ? ? ? data_size?
=
?
int
(
self
.
data
.
get_shape
()[
1
])
? ? ? ? target_size?
=
?
int
(
self
.
target
.
get_shape
()[
1
])
? ? ? ? weight?
=
?tf
.
Variable
(
tf
.
truncated_normal
([
data_size
,
?target_size
]))
? ? ? ? bias?
=
?tf
.
Variable
(
tf
.
constant
(
0.1
,
?shape
=[
target_size
]))
? ? ? ? incoming?
=
?tf
.
matmul
(
self
.
data
,
?weight
)
?
+
?bias
? ? ? ??
return
?tf
.
nn
.
softmax
(
incoming
)
? ??
@lazy_property
? ??
def
?optimize
(
self
):
? ? ? ? cross_entropy?
=
?
-
tf
.
reduce_sum
(
self
.
target
,
?tf
.
log
(
self
.
prediction
))
? ? ? ? optimizer?
=
?tf
.
train
.
RMSPropOptimizer
(
0.03
)
? ? ? ??
return
?optimizer
.
minimize
(
cross_entropy
)
? ??
@lazy_property
? ??
def
?error
(
self
):
? ? ? ? mistakes?
=
?tf
.
not_equal
(
? ? ? ? ? ? tf
.
argmax
(
self
.
target
,
?
1
),
?tf
.
argmax
(
self
.
prediction
,
?
1
))
? ? ? ??
return
?tf
.
reduce_mean
(
tf
.
cast
(
mistakes
,
?tf
.
float32
))
請(qǐng)注意,我們?cè)谘b飾器中只是提到了這些屬性。完整的圖還是要我們運(yùn)行 tf.initialize_variables() 來定義的。
使用 scopes 來組織圖
我們現(xiàn)在有一個(gè)簡(jiǎn)單的方法可以來定義我們的模型,但是由此產(chǎn)生的計(jì)算圖仍然是非常擁擠的。如果你想要將圖進(jìn)行可視化,那么它將會(huì)包含很多互相鏈接的小節(jié)點(diǎn)。解決方案是我們對(duì)每一個(gè)函數(shù)(每一個(gè)節(jié)點(diǎn))都起一個(gè)名字,利用 tf.namescope("name") 或者 tf.variablescope("name") 就可以實(shí)現(xiàn)。然后節(jié)點(diǎn)會(huì)在圖中自由組合在一起,我們只需要調(diào)整我們的裝飾器就可以了。
import
?functools
def
?define_scope
(
function
):
? ? attribute?
=
?
"_cache_"
?
+
?
function
.
__name__
? ??
@property
? ??
@functools
.
wraps
(
function
)
? ??
def
?decorator
(
self
):
? ? ? ??
if
?
not
?hasattr
(
self
,
?attribute
):
? ? ? ? ? ??
with
?tf
.
variable_scope
(
function
.
__name
):
? ? ? ? ? ? ? ? setattr
(
self
,
?attribute
,
?
function
(
self
))
? ? ? ??
return
?getattr
(
self
,
?attribute
)
? ??
return
?decorator
我給了裝飾器一個(gè)新的名字,因?yàn)槌宋覀兗拥膽卸杈彺妫€具有特定的 TensorFlow 功能。除此之外,模型看起來和原來的是一樣的。
商業(yè)智能與數(shù)據(jù)分析群
興趣范圍包括各種讓數(shù)據(jù)產(chǎn)生價(jià)值的辦法,實(shí)際應(yīng)用案例分享與討論,分析工具,ETL工具,數(shù)據(jù)倉庫,數(shù)據(jù)挖掘工具,報(bào)表系統(tǒng)等全方位知識(shí)
QQ群:81035754
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/4685.html
摘要:機(jī)器學(xué)習(xí)模型內(nèi)部的組成部分,可以使用進(jìn)行打包和共享。為機(jī)器學(xué)習(xí)開發(fā)者提供庫產(chǎn)生了庫。庫是一個(gè)在中進(jìn)行發(fā)布和重用中機(jī)器學(xué)習(xí)模塊的平臺(tái)。 摘要: 本文對(duì)TensorFlow Hub庫的介紹,并舉例說明其用法。 在軟件開發(fā)中,最常見的失誤就是容易忽視共享代碼庫,而庫則能夠使軟件開發(fā)具有更高的效率。從某種意義上來說,它改變了編程的過程。我們常常使用庫構(gòu)建塊或模塊,并將其連接在一起進(jìn)行編程。 開...
摘要:第一個(gè)深度學(xué)習(xí)框架該怎么選對(duì)于初學(xué)者而言一直是個(gè)頭疼的問題。簡(jiǎn)介和是頗受數(shù)據(jù)科學(xué)家歡迎的深度學(xué)習(xí)開源框架。就訓(xùn)練速度而言,勝過對(duì)比總結(jié)和都是深度學(xué)習(xí)框架初學(xué)者非常棒的選擇。 「第一個(gè)深度學(xué)習(xí)框架該怎么選」對(duì)于初學(xué)者而言一直是個(gè)頭疼的問題。本文中,來自 deepsense.ai 的研究員給出了他們?cè)诟呒?jí)框架上的答案。在 Keras 與 PyTorch 的對(duì)比中,作者還給出了相同神經(jīng)網(wǎng)絡(luò)在不同框...
摘要:共字,讀完需分鐘。下面提出一種可以幫你寫出高可讀的實(shí)踐方法,這個(gè)方法并非原創(chuàng),最早的實(shí)踐來自于這篇文章。本文作者王仕軍,商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 showImg(https://segmentfault.com/img/remote/1460000009341335?w=1240&h=403); 共 1926 字,讀完需 4 分鐘。所有工程師都知道,代碼是編寫...
摘要:是為了大規(guī)模分布式訓(xùn)練和推理而設(shè)計(jì)的,不過它在支持新機(jī)器學(xué)習(xí)模型和系統(tǒng)級(jí)優(yōu)化的實(shí)驗(yàn)中的表現(xiàn)也足夠靈活。本文對(duì)能夠同時(shí)兼具規(guī)模性和靈活性的系統(tǒng)架構(gòu)進(jìn)行了闡述。盡管大多數(shù)訓(xùn)練庫仍然只支持,但確實(shí)能夠支持有效的推理。 TensorFlow 是為了大規(guī)模分布式訓(xùn)練和推理而設(shè)計(jì)的,不過它在支持新機(jī)器學(xué)習(xí)模型和系統(tǒng)級(jí)優(yōu)化的實(shí)驗(yàn)中的表現(xiàn)也足夠靈活。?本文對(duì)能夠同時(shí)兼具規(guī)模性和靈活性的系統(tǒng)架構(gòu)進(jìn)行了闡述。設(shè)...
閱讀 988·2023-04-25 22:57
閱讀 3238·2021-11-23 10:03
閱讀 759·2021-11-22 15:24
閱讀 3322·2021-11-02 14:47
閱讀 3091·2021-09-10 11:23
閱讀 3351·2021-09-06 15:00
閱讀 4129·2019-08-30 15:56
閱讀 3480·2019-08-30 15:52