使用keras實現孿生網路中的權值共享教程
首先宣告,這裡的權值共享指的不是CNN原理中的共享權值,而是如何在構建類似於Siamese Network這樣的多分支網路,且分支結構相同時,如何使用keras使分支的權重共享。
Functional API
為達到上述的目的,建議使用keras中的Functional API,當然Sequential 型別的模型也可以使用,本篇部落格將主要以Functional API為例講述。
keras的多分支權值共享功能實現,官方文件介紹
上面是官方的連結,本篇部落格也是基於上述官方文件,實現的此功能。(插一句,keras雖然有中文文件,但中文文件已停更,且中文文件某些函式介紹不全,建議直接看英文官方文件)
不共享引數的模型
以MatchNet網路結構為例子,為方便顯示,將卷積模組個數減為2個。首先是展示不共享引數的模型,以便觀看完整的網路結構。
整體的網路結構如下所示:
程式碼包含兩部分,第一部分定義了兩個函式,FeatureNetwork()生成特徵提取網路,ClassiFilerNet()生成決策網路或稱度量網路。網路結構的視覺化在部落格末尾。在ClassiFilerNet()函式中,可以看到呼叫了兩次FeatureNetwork()函式,keras.models.Model也被使用的兩次,因此生成的input1和input2是兩個完全獨立的模型分支,引數是不共享的。
from keras.models import Sequential from keras.layers import merge,Conv2D,MaxPool2D,Activation,Dense,concatenate,Flatten from keras.layers import Input from keras.models import Model from keras.utils import np_utils import tensorflow as tf import keras from keras.datasets import mnist import numpy as np from keras.utils import np_utils from keras.callbacks import EarlyStopping,ModelCheckpoint,TensorBoard,ReduceLROnPlateau from keras.utils.vis_utils import plot_model # ---------------------函式功能區------------------------- def FeatureNetwork(): """生成特徵提取網路""" """這是根據,MNIST資料調整的網路結構,下面註釋掉的部分是,原始的Matchnet網路中feature network結構""" inp = Input(shape = (28,28,1),name='FeatureNet_ImageInput') models = Conv2D(filters=24,kernel_size=(3,3),strides=1,padding='same')(inp) models = Activation('relu')(models) models = MaxPool2D(pool_size=(3,3))(models) models = Conv2D(filters=64,padding='same')(models) # models = MaxPool2D(pool_size=(3,strides=(2,2))(models) models = Activation('relu')(models) models = Conv2D(filters=96,padding='valid')(models) models = Activation('relu')(models) models = Conv2D(filters=96,padding='valid')(models) models = Activation('relu')(models) models = Flatten()(models) models = Dense(512)(models) models = Activation('relu')(models) model = Model(inputs=inp,outputs=models) return model def ClassiFilerNet(): # add classifier Net """生成度量網路和決策網路,其實maychnet是兩個網路結構,一個是特徵提取層(孿生),一個度量層+匹配層(統稱為決策層)""" input1 = FeatureNetwork() # 孿生網路中的一個特徵提取 input2 = FeatureNetwork() # 孿生網路中的另一個特徵提取 for layer in input2.layers: # 這個for迴圈一定要加,否則網路重名會出錯。 layer.name = layer.name + str("_2") inp1 = input1.input inp2 = input2.input merge_layers = concatenate([input1.output,input2.output]) # 進行融合,使用的是預設的sum,即簡單的相加 fc1 = Dense(1024,activation='relu')(merge_layers) fc2 = Dense(1024,activation='relu')(fc1) fc3 = Dense(2,activation='softmax')(fc2) class_models = Model(inputs=[inp1,inp2],outputs=[fc3]) return class_models # ---------------------主調區------------------------- matchnet = ClassiFilerNet() matchnet.summary() # 列印網路結構 plot_model(matchnet,to_file='G:/csdn攻略/picture/model.png') # 網路結構輸出成png圖片
共享引數的模型
FeatureNetwork()的功能和上面的功能相同,為方便選擇,在ClassiFilerNet()函式中加入了判斷是否使用共享引數模型功能,令reuse=True,便使用的是共享引數的模型。
關鍵地方就在,只使用的一次Model,也就是說只建立了一次模型,雖然輸入了兩個輸入,但其實使用的是同一個模型,因此權重共享的。
from keras.models import Sequential from keras.layers import merge,ReduceLROnPlateau from keras.utils.vis_utils import plot_model # ----------------函式功能區----------------------- def FeatureNetwork(): """生成特徵提取網路""" """這是根據,MNIST資料調整的網路結構,下面註釋掉的部分是,原始的Matchnet網路中feature network結構""" inp = Input(shape = (28,padding='valid')(models) models = Activation('relu')(models) # models = Conv2D(64,strides=2,padding='valid')(models) # models = Activation('relu')(models) # models = MaxPool2D(pool_size=(3,2))(models) models = Flatten()(models) models = Dense(512)(models) models = Activation('relu')(models) model = Model(inputs=inp,outputs=models) return model def ClassiFilerNet(reuse=False): # add classifier Net """生成度量網路和決策網路,其實maychnet是兩個網路結構,一個是特徵提取層(孿生),一個度量層+匹配層(統稱為決策層)""" if reuse: inp = Input(shape=(28,name='FeatureNet_ImageInput') models = Conv2D(filters=24,padding='same')(inp) models = Activation('relu')(models) models = MaxPool2D(pool_size=(3,3))(models) models = Conv2D(filters=64,padding='same')(models) # models = MaxPool2D(pool_size=(3,2))(models) models = Activation('relu')(models) models = Conv2D(filters=96,padding='valid')(models) models = Activation('relu')(models) models = Conv2D(filters=96,padding='valid')(models) models = Activation('relu')(models) # models = Conv2D(64,padding='valid')(models) # models = Activation('relu')(models) # models = MaxPool2D(pool_size=(3,2))(models) models = Flatten()(models) models = Dense(512)(models) models = Activation('relu')(models) model = Model(inputs=inp,outputs=models) inp1 = Input(shape=(28,1)) # 建立輸入 inp2 = Input(shape=(28,1)) # 建立輸入2 model_1 = model(inp1) # 孿生網路中的一個特徵提取分支 model_2 = model(inp2) # 孿生網路中的另一個特徵提取分支 merge_layers = concatenate([model_1,model_2]) # 進行融合,使用的是預設的sum,即簡單的相加 else: input1 = FeatureNetwork() # 孿生網路中的一個特徵提取 input2 = FeatureNetwork() # 孿生網路中的另一個特徵提取 for layer in input2.layers: # 這個for迴圈一定要加,否則網路重名會出錯。 layer.name = layer.name + str("_2") inp1 = input1.input inp2 = input2.input merge_layers = concatenate([input1.output,outputs=[fc3]) return class_models
如何看是否真的是權值共享呢?直接對比特徵提取部分的網路引數個數!
不共享引數模型的引數數量:
共享引數模型的引數總量
共享引數模型中的特徵提取部分的引數量為:
由於截圖限制,不共享引數模型的特徵提取網路引數數量不再展示。其實經過計算,特徵提取網路部分的引數數量,不共享引數模型是共享引數的兩倍。兩個網路總引數量的差值就是,共享模型中,特徵提取部分的引數的量
網路結構視覺化
不共享權重的網路結構
共享引數的網路結構,其中model_1代表的就是特徵提取部分。
以上這篇使用keras實現孿生網路中的權值共享教程就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。