keras始于易匆帚,止于簡熬词。
什么意思呢?多少人是因?yàn)閷eras建模過程的友好程度而上手keras吸重,又有多少人因?yàn)閗eras的高度封裝造成的欠靈活性而開始累覺不愛互拾。
這里介紹一下keras的Lambda層,希望在掌握了這個trick后嚎幸,能多多少少拾回些許使用keras的信心颜矿。
步入正題,Lambda嫉晶,顧名思義骑疆,和python的lambda含義是類似的,這里指的是具有某種功能的layer,
keras源碼里關(guān)于Lambda 的文檔是這樣寫的替废,“wraps arbitrary expression as a ‘Layer’ object”,翻譯成中文, “將任意的表達(dá)式包裝成層對象”箍铭,我認(rèn)為這句話準(zhǔn)確,精煉的闡述了它的含義椎镣,這里的表達(dá)式就可以是你用backend/后端(tensorflow, theano)寫的某個函數(shù)诈火,也可叫做功能模塊吧。
首先状答,我想解釋一下“靈活性”這三個字冷守,怎么理解深度學(xué)習(xí)建模過程中的靈活性, 我的理解是,靈活意味著你能夠自定義你的網(wǎng)絡(luò)層惊科,而Lambda的出現(xiàn)就是為了實(shí)現(xiàn)這個功能的拍摇。
keras常規(guī)建模過程為:
from keras.layers import Input, Dense,Conv2D
from keras.models import Model
# This returns a tensor
inputs = Input(shape=(784,))
# a layer instance is callable on a tensor, and returns a tensor
x = Conv2D(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# This creates a model that includes
# the Input layer and three Dense layers
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(data, labels) # starts training
在這樣一個建模流程中馆截,我們使用的都是Dense ,Conv2D…之類的定義好的layers,如果你想編寫自己的layer就可以使用Lambda的功能了充活,
先給出Lambda的初始化參數(shù):
Lambda(function, output_shape=None, mask=None, arguments=None, **kwargs)
看兩個例子,
- add a x -> x^2 layer
model.add(Lambda(lambda x: x ** 2))
- add a layer that returns the concatenation of the positive part of the input andthe opposite of the negative part
def antirectifier(x):
x -= K.mean(x, axis=1, keepdims=True)
x = K.l2_normalize(x, axis=1)
pos = K.relu(x)
neg = K.relu(-x)
return K.concatenate([pos, neg], axis=1)
def antirectifier_output_shape(input_shape):
shape = list(input_shape)
assert len(shape) == 2 # only valid for 2D tensors
shape[-1] *= 2
return tuple(shape)
model.add(Lambda(antirectifier,output_shape=antirectifier_output_shape))
注意蜡娶,我們可以使用匿名函數(shù)或者是定義一個函數(shù)來作為Lambda的function參數(shù)混卵,Lambda還有一個參數(shù)是out_shape,你可以直接指定一個tuple或者定義一個函數(shù)(輸入為input_shape),我在使用的過程中,也用到過arguments這個參數(shù)翎蹈,它也字典的形式出現(xiàn),keys為function的參數(shù)男公,這樣能豐富你的層的功能荤堪,這里要通過解決實(shí)際問題來加深體會合陵。
說到這里,我們已經(jīng)知道了Lambda 的一些基本使用方法澄阳,知道怎么用還不遠(yuǎn)遠(yuǎn)不夠拥知,做到會用,善用才算是比較好的掌握了碎赢,這里再談?wù)勎业氖褂肔ambda的場景和經(jīng)驗(yàn)吧低剔。
一個是keras相較于tensorflow而言,對于一些新出的層函數(shù)(這里指Conv2D這樣的layers)并沒有很好的支持肮塞,但我們可以使用tensorflw去構(gòu)建層襟齿,然后用Lambda 包裝成keras的layers,下面為yoloV2用到的space_to_depth的代碼:
def space_to_depth_x2(x):
"""Thin wrapper for Tensorflow space_to_depth with block_size=2."""
# Import currently required to make Lambda work.
# See: https://github.com/fchollet/keras/issues/5088#issuecomment-273851273
import tensorflow as tf
return tf.space_to_depth(x, block_size=2)
def space_to_depth_x2_output_shape(input_shape):
"""Determine space_to_depth output shape for block_size=2."""
return (input_shape[0], input_shape[1] // 2, input_shape[2] // 2, 4 *input_shape[3])
if input_shape[1] else (input_shape[0], None, None,4 * input_shape[3])
Lambda(space_to_depth_x2,
output_shape=space_to_depth_x2_output_shape,
name='space_to_depth')(conv21)
另一個使用較多的場景就是我會用Lambda 來構(gòu)建我自己的custom loss-layer,再看看前面寫的keras常規(guī)建模過程,當(dāng)我們完成建模后枕赵,model.compile()就指定了我們的loss-function,如果你想寫出自己loss-function怎么辦猜欺,我這里講一種方法,在模型最后一層輸出后拷窜,你可以再用Lambda 加一層开皿,在這層里,你可以隨意添加你的loss-function,注意篮昧,這里添加了loss-layer后赋荆,你的模型輸出就不再始于測值y_pred了,而直接是loss值了懊昨,所以在訓(xùn)練過程中窄潭,你需要的是直接用優(yōu)化器最小化這個值了,因此疚颊,需要改動一下model.compile(optimizer=’adam’, loss={‘custom_loss’: lambda y_ture, y_pred : y_pred}), 這里的loss的意思是我直接將模型的output(這里的y_pred)作為我的loss,跟前邊模型構(gòu)建過程中添加loss-layer的思路相同狈孔,這樣的構(gòu)建方式在目標(biāo)檢測算法(比如yoloV2)中就會用到,它的loss-function比較復(fù)雜材义,除了分類還要回歸均抽,就可以嘗試這種構(gòu)建方式,還有一個問題其掂,loss={‘custom_loss’: lambda y_ture, y_pred : y_pred}這種寫法牽扯到了另外一個概念油挥,custom loss-function,這也是定制自己loss-function的一種不錯的方法。具體參看:https://github.com/keras-team/keras/issues/4126款熬。
下面給出具體的代碼:
model_loss=Lambda(custom_loss,output_shape=(),name='custom_losss')(model_body.output)
model=Model(model.input,model_loss)
model.compile(optimizer='adam'深寥,loss={'custom_loss': lambda y_true,y_pred : y_pred})
model.fit(x,y=zeros(len(datas)) # y實(shí)際上沒用,就當(dāng)是個占位符
總結(jié)一下贤牛,keras還算是一個比較靈活的框架惋鹅,前提是你也得學(xué)會tensorflow,因?yàn)楫?dāng)你在自定義你的網(wǎng)絡(luò)的時候,你其實(shí)就相當(dāng)于是在使用tensorflow了殉簸,keras和tensorflow聯(lián)合構(gòu)建你自己的深度學(xué)習(xí)模型闰集,是個不錯的選擇沽讹。當(dāng)你在聯(lián)合使用這兩個庫的時候,除了在使用他們提供的的api,你也在聯(lián)合兩種編程邏輯,keras的模塊式嗅回,tensorfow的數(shù)據(jù)流圖。
以上表述為個人理解所得挚瘟,可能存在不清楚的地方,畢竟水平有限饲梭,隨著經(jīng)驗(yàn)的加深乘盖,會有更深的理解,所以還請見諒排拷,共勉侧漓。
references:
allanzelener/YAD2K
https://github.com/allanzelener/YAD2K
keras-team/keras
https://github.com/keras-team/keras/blob/master/keras/layers/core.py