[Keras] 使用Keras編寫自訂網路層(layer)_DeepLearning

來源:互聯網
上載者:User

Keras提供眾多常見的已編寫好的層對象,例如常見的卷積層、池化層等,我們可以直接通過以下代碼調用:

# 調用一個Conv2D層from keras import layersconv2D = keras.layers.convolutional.Conv2D(filters,\kernel_size, \strides=(1, 1), \padding='valid', \...)

但是在實際應用中,我們經常需要自己構建一些層對象,已滿足某些自訂網路的特殊需求。
幸運的是,Keras對自訂層提供了良好的支援。

下面對常用方法進行總結。 方法1:keras.core.lambda()

如果我們的自訂層中不包含可訓練的權重,而只是對上一層輸出做一些函數變換,那麼我們可以直接使用keras.core模組(該模組包含常見的基礎層,如Dense、Activation等)下的lambda函數:

keras.layers.core.Lambda(function, output_shape=None, mask=None, arguments=None)

參數說明:
function:要實現的函數,該函數僅接受一個變數,即上一層的輸出
output_shape:函數應該返回的值的shape,可以是一個tuple,也可以是一個根據輸入shape計算輸出shape的函數
mask: 掩膜
arguments:可選,字典,用來記錄向函數中傳遞的其他關鍵字參數

但是多數情況下,我們需要定義的是一個全新的、擁有可訓練權重的層,這個時候我們就需要使用下面的方法。 方法2: 編寫Layer繼承類

keras.engine.topology中包含了Layer的父類,我們可以通過繼承來實現自己的層。
要定製自己的層,需要實現下面三個方法

build(input_shape):這是定義權重的方法,可訓練的權應該在這裡被加入列表self.trainable_weights中。其他的屬性還包括self.non_trainabe_weights(列表)和self.updates(需要更新的形如(tensor,new_tensor)的tuple的列表)。這個方法必須設定self.built = True,可通過調用super([layer],self).build()實現。

call(x):這是定義層功能的方法,除非你希望你寫的層支援masking,否則你只需要關心call的第一個參數:輸入張量。

compute_output_shape(input_shape):如果你的層修改了輸入資料的shape,你應該在這裡指定shape變化的方法,這個函數使得Keras可以做自動shape推斷。

一個比較好的學習方法是閱讀Keras已編寫好的類的原始碼,嘗試理解其中的邏輯。

下面,我們將通過一個實際的例子,編寫一個自訂層。
出於學習的目的,在該例子中,會添加一些的注釋文字,用以解釋一些函數功能。

該層結構來源自DenseNet,代碼參考Github。

from keras.layers.core import Layerfrom keras.engine import InputSpecfrom keras import backend as Ktry:    from keras import initializationsexcept ImportError:    from keras import initializers as initializations# 繼承父類Layerclass Scale(Layer):    '''    該層功能:        通過向量元素依次相乘(Element wise multiplication)調整上層輸出的形狀。        out = in * gamma + beta,        gamma代表權重weights,beta代表偏置bias    參數列表:        axis: int型,代表需要做scale的軸方向,axis=-1 代表選取預設方向(橫行)。        momentum: 對資料方差和標準差做指數平均時的動量.        weights: 初始權重,是一個包含兩個numpy array的list, shapes:[(input_shape,), (input_shape,)]        beta_init: 偏置量的初始化方法名。(參考Keras.initializers.只有weights未傳參時才會使用.        gamma_init: 權重量的初始化方法名。(參考Keras.initializers.只有weights未傳參時才會使用.    '''    def __init__(self, weights=None, axis=-1, beta_init = 'zero', gamma_init = 'one', momentum = 0.9, **kwargs):        # 參數**kwargs代表按字典方式繼承父類        self.momentum = momentum        self.axis = axis        self.beta_init = initializers.Zeros()        self.gamma_init = initializers.Ones()        self.initial_weights = weights        super(Scale, self).__init__(**kwargs)    def build(self, input_shape):        self.input_spec = [InputSpec(shape=input_shape)]        # 1:InputSpec(dtype=None, shape=None, ndim=None, max_ndim=None, min_ndim=None, axes=None)        #Docstring:             #Specifies the ndim, dtype and shape of every input to a layer.        #Every layer should expose (if appropriate) an `input_spec` attribute:a list of instances of InputSpec (one per input tensor).        #A None entry in a shape is compatible with any dimension        #A None shape is compatible with any shape.        # 2:self.input_spec: List of InputSpec class instances        # each entry describes one required input:        #     - ndim        #     - dtype        # A layer with `n` input tensors must have        # an `input_spec` of length `n`.        shape = (int(input_shape[self.axis]),)        # Compatibility with TensorFlow >= 1.0.0        self.gamma = K.variable(self.gamma_init(shape), name='{}_gamma'.format(self.name))        self.beta = K.variable(self.beta_init(shape), name='{}_beta'.format(self.name))        self.trainable_weights = [self.gamma, self.beta]        if self.initial_weights is not None:            self.set_weights(self.initial_weights)            del self.initial_weights    def call(self, x, mask=None):        input_shape = self.input_spec[0].shape        broadcast_shape = [1] * len(input_shape)        broadcast_shape[self.axis] = input_shape[self.axis]        out = K.reshape(self.gamma, broadcast_shape) * x + K.reshape(self.beta, broadcast_shape)        return out    def get_config(self):        config = {"momentum": self.momentum, "axis": self.axis}        base_config = super(Scale, self).get_config()        return dict(list(base_config.items()) + list(config.items()))

以上就是編寫自訂層的執行個體,可以直接添加到自己的model中。
編寫好的layer自動存放在custom_layers中,通過import調用。

from custom_layers import Scaledef myNet(growth_rate=32, \nb_filter=64, \reduction=0.0, \dropout_rate=0.0, weight_decay=1e-4,...)...x = "last_layer_name"x = Scale(axis=concat_axis, name='scale')(x)...model = Model(input, x, name='myNet')return model

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.