作者丨蘇劍林 單位丨追一科技 研究方向丨NLP,神經(jīng)網(wǎng)絡(luò) 個(gè)人主頁(yè)丨kexue.fm 今天我們繼續(xù)來(lái)深挖 Keras,再次體驗(yàn) Keras 那無(wú)與倫比的優(yōu)雅設(shè)計(jì)。這一次我們的焦點(diǎn)是“重用”,主要是層與模型的重復(fù)使用。 所謂重用,一般就是奔著兩個(gè)目標(biāo)去:一是為了共享權(quán)重,也就是說(shuō)要兩個(gè)層不僅作用一樣,還要共享權(quán)重,同步更新;二是避免重寫代碼,比如我們已經(jīng)搭建好了一個(gè)模型,然后我們想拆解這個(gè)模型,構(gòu)建一些子模型等。 基礎(chǔ)事實(shí)上,Keras 已經(jīng)為我們考慮好了很多,所以很多情況下,掌握好基本用法,就已經(jīng)能滿足我們很多需求了。 層的重用 層的重用是最簡(jiǎn)單的,將層初始化好,存起來(lái),然后反復(fù)調(diào)用即可: x_in = Input(shape=(784,)) 要注意的是,必須先初始化好一個(gè)層,存為一個(gè)變量好再調(diào)用,才能保證重復(fù)調(diào)用的層是共享權(quán)重的。反之,如果是下述形式的代碼,則是非共享權(quán)重的:
模型重用 Keras 的模型有著類似層的表現(xiàn),在調(diào)用時(shí)可以用跟層一樣的方式,比如: x_in = Input(shape=(784,)) 讀過(guò) Keras 源碼的朋友就會(huì)明白,之所以可以將模型當(dāng)層那樣用,是因?yàn)?Model 本身就是繼承 Layer 類來(lái)寫的,所以模型自然也包含了層的一些相同特性。 模型克隆 模型克隆跟模型重用類似,只不過(guò)得到的新模型跟原模型不共享權(quán)重了,也就是說(shuō),僅僅保留完全一樣的模型結(jié)構(gòu),兩個(gè)模型之間的更新是獨(dú)立的。Keras 提供了模型可用專用的函數(shù),直接調(diào)用即可:
注意,clone_model 完全復(fù)制了原模型模型的結(jié)構(gòu),并重新構(gòu)建了一個(gè)模型,但沒(méi)有復(fù)制原模型的權(quán)重的值。也就是說(shuō),對(duì)于同樣的輸入,model1.predict 和 model2.predict 的結(jié)果是不一樣的。 如果要把權(quán)重也搬過(guò)來(lái),需要手動(dòng) set_weights 一下: model2.set_weights(K.batch_get_value(model1.weights)) 進(jìn)階上述談到的是原封不等的調(diào)用原來(lái)的層或模型,所以比較簡(jiǎn)單,Keras 都準(zhǔn)備好了。下面介紹一些復(fù)雜一些的例子。 交叉引用 這里的交叉引用是指在定義一個(gè)新層的時(shí)候,沿用已有的某個(gè)層的權(quán)重,注意這個(gè)自定義層可能跟舊層的功能完全不一樣,它們之間純粹是共享了某個(gè)權(quán)重而已。比如,Bert 在訓(xùn)練 MLM 的時(shí)候,最后預(yù)測(cè)字詞概率的全連接層,權(quán)重就是跟 Embedding 層共享的。 參考寫法如下:
提取中間層 有時(shí)候我們需要從搭建好的模型中提取中間層的特征,并且構(gòu)建一個(gè)新模型,在 Keras 中這同樣是很簡(jiǎn)單的操作: from keras.applications.resnet50 import ResNet50 從中間拆開(kāi) 最后,來(lái)到本文最有難度的地方了,我們要將模型從中間拆開(kāi),搞懂之后也可以實(shí)現(xiàn)往已有模型插入或替換新層的操作。這個(gè)需求看上去比較奇葩,但是還別說(shuō),stackoverflow 上面還有人提問(wèn)過(guò),說(shuō)明這確實(shí)是有價(jià)值的。 https:///questions/49492255/how-to-replace-or-insert-intermediate-layer-in-keras-model 假設(shè)我們有一個(gè)現(xiàn)成的模型,它可以分解為: 那可能我們需要將 h2 替換成一個(gè)新的輸入,然后接上后面的層,來(lái)構(gòu)建一個(gè)新模型,即新模型的功能是: 如果是 Sequential 類模型,那比較簡(jiǎn)單,直接把 model.layers 都遍歷一邊,就可以構(gòu)建新模型了:
但是,如果模型是比較復(fù)雜的結(jié)構(gòu),比如殘差結(jié)構(gòu)這種不是一條路走到底的,就沒(méi)有這么簡(jiǎn)單了。事實(shí)上,這個(gè)需求本來(lái)沒(méi)什么難度,該寫的 Keras 本身已經(jīng)寫好了,只不過(guò)沒(méi)有提供現(xiàn)成的接口罷了。為什么這么說(shuō),因?yàn)槲覀兺ㄟ^(guò) model(x) 這樣的代碼調(diào)用已有模型的時(shí)候, 實(shí)際上 Keras 就相當(dāng)于把這個(gè)已有的這個(gè) model 從頭到尾重新搭建了一遍,既然可以重建整個(gè)模型,那搭建“半個(gè)”模型原則上也是沒(méi)有任技術(shù)難度的,只不過(guò)沒(méi)有現(xiàn)成的接口。具體可以參考 Keras 源碼的 keras/engine/network.py 的 run_internal_graph 函數(shù): 完整重建一個(gè)模型的邏輯在 run_internal_graph 函數(shù)里邊,并且可以看到它還不算簡(jiǎn)單,所以如無(wú)必要我們最好不要重寫這個(gè)代碼。但如果不重寫這個(gè)代碼,又想調(diào)用這個(gè)代碼,實(shí)現(xiàn)從中間層拆解模型的功能,唯一的辦法是“移花接木”了:通過(guò)修改已有模型的一些屬性,欺騙一下 run_internal_graph 函數(shù),使得它以為模型的輸入層是中間層,而不是原始的輸入層。有了這個(gè)思想,再認(rèn)真讀讀 run_internal_graph 函數(shù)的代碼,就不難得到下述參考代碼: def get_outputs_of(model, start_tensors, input_layers=None): 用法:
代碼有點(diǎn)長(zhǎng),但其實(shí)邏輯很簡(jiǎn)單,真正核心的代碼只有三行: model.inputs = start_tensors 也就是覆蓋模型的 model.inputs 和 model._input_layers 就可以實(shí)現(xiàn)欺騙模型從中間層開(kāi)始構(gòu)建的效果了,其余的多數(shù)是適配工作,不是技術(shù)上的,而 model._layers = layers 這一句是只保留了從中間層開(kāi)始所用到的層,只是為了統(tǒng)計(jì)模型參數(shù)量的準(zhǔn)確性,如果去掉這一部分,模型的參數(shù)量依然是原來(lái)整個(gè) model 那么多。 小結(jié)Keras 是最讓人賞心悅目的深度學(xué)習(xí)框架,至少到目前為止,就模型代碼的可讀性而言,沒(méi)有之一。可能讀者會(huì)提到 PyTorch,誠(chéng)然 PyTorch 也有不少可取之處,但就可讀性而言,我認(rèn)為是比不上 Keras 的。 在深究 Keras 的過(guò)程中,我不僅驚嘆于 Keras 作者們的深厚而優(yōu)雅的編程功底,甚至感覺(jué)自己的編程技能也提高了不少。不錯(cuò),我的很多 Python 編程技巧,都是從讀 Keras 源碼中學(xué)習(xí)到的。 點(diǎn)擊以下標(biāo)題查看作者其他文章: #投 稿 通 道# 讓你的論文被更多人看到 如何才能讓更多的優(yōu)質(zhì)內(nèi)容以更短路徑到達(dá)讀者群體,縮短讀者尋找優(yōu)質(zhì)內(nèi)容的成本呢?答案就是:你不認(rèn)識(shí)的人。 總有一些你不認(rèn)識(shí)的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋梁,促使不同背景、不同方向的學(xué)者和學(xué)術(shù)靈感相互碰撞,迸發(fā)出更多的可能性。 PaperWeekly 鼓勵(lì)高校實(shí)驗(yàn)室或個(gè)人,在我們的平臺(tái)上分享各類優(yōu)質(zhì)內(nèi)容,可以是最新論文解讀,也可以是學(xué)習(xí)心得或技術(shù)干貨。我們的目的只有一個(gè),讓知識(shí)真正流動(dòng)起來(lái)。 ?? 來(lái)稿標(biāo)準(zhǔn): · 稿件確系個(gè)人原創(chuàng)作品,來(lái)稿需注明作者個(gè)人信息(姓名+學(xué)校/工作單位+學(xué)歷/職位+研究方向) · 如果文章并非首發(fā),請(qǐng)?jiān)谕陡鍟r(shí)提醒并附上所有已發(fā)布鏈接 · PaperWeekly 默認(rèn)每篇文章都是首發(fā),均會(huì)添加“原創(chuàng)”標(biāo)志 |
|
來(lái)自: LibraryPKU > 《機(jī)器學(xué)習(xí)》