介绍
CNN中有权重共享的概念,是一张图片中的多个区域共享同一个卷积核的参数。与前者不同,这里讨论的是权重共享网络,即有多个不同的输入,经过具有相同参数的一个网络,得到两个不同的结果。
有一类网络叫孪生网络(如MatchNet)就具有权重共享的特性。这种网络可以用来衡量两个样本的相似性,用于判定两个样本是不是同一个类。在人脸识别、签名识别、语言识别任务中有一些应用。
keras实现孪生网络的方式很简单,只要将需要共享的地方组成一个Model。在后续网络调用Model即可。最后整个网络再组成一个Model。相当于整体Model包含共享的Model。。。Model套Model
keras官方文档示例
下面ClassFilerNet1是共享权重的网络,最后summary的参数量是4万多;ClassFilerNet2没有共享权重,summary的参数量是9万多。
共享的部分是conv2d-conv2d-maxpooling2d-flatten
第一个网络将共享的部分组成了vision_model,后续像Layer一样函数式调用即可。
第二个网络重新创建了不同的Layer,没有组成一个Model,所以参数会增加。
import keras
from keras.layers import Conv2D, MaxPooling2D, Input, Dense, Flatten
from keras.models import Model
def ClassiFilerNet1():
# First, define the vision modules
digit_input = Input(shape=(27, 27, 1))
x = Conv2D(64, (3, 3))(digit_input)
x = Conv2D(64, (3, 3))(x)
x = MaxPooling2D((2, 2))(x)
out = Flatten()(x)
vision_model = Model(digit_input, out)
# Then define the tell-digits-apart model
digit_a = Input(shape=(27, 27, 1))
digit_b = Input(shape=(27, 27, 1))
# The vision model will be shared, weights and all
out_a = vision_model(digit_a)
out_b = vision_model(digit_b)
concatenated = keras.layers.concatenate([out_a, out_b])
out = Dense(1, activation='sigmoid')(concatenated)
classification_model = Model([digit_a, digit_b], out)
return classification_model
def ClassiFilerNet2():
digit_a = Input(shape=(27, 27, 1))
x = Conv2D(64, (3, 3))(digit_a)
x = Conv2D(64, (3, 3))(x)
x = MaxPooling2D((2, 2))(x)
out1 = Flatten()(x)
digit_b = Input(shape=(27, 27, 1))
x = Conv2D(64, (3, 3))(digit_b)
x = Conv2D(64, (3, 3))(x)
x = MaxPooling2D((2, 2))(x)
out2 = Flatten()(x)
concatenated = keras.layers.concatenate([out1, out2])
out = Dense(1, activation='sigmoid')(concatenated)
classification_model = Model([digit_a, digit_b], out)
return classification_model
MatchNet 出自这里
代码是直接粘贴过来的,实际上核心用法看keras官方文档最简单也最直观。粘贴过来只是做个记录。
MatchNet包含两块:FeatureExtract,Classification。
FeatureExtract部分,对于多个输入应该采用相同的权重进行处理,需要用到共享权重。
Classification对提取的特征进行分类,判别是不是同一类。
下面第一段代码是非共享权重,参数量为4.8M;第二段是共享权重,参数量为3.4M。
可以放到tensorboard查看网络结构,有一些差异。
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, kernel_size=(3, 3), strides=1, padding='same')(models)
# models = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, padding='valid')(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, 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])
print("1111")
return class_models
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, kernel_size=(3, 3), strides=1, padding='same')(models)
# models = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, padding='valid')(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, padding='valid')(models)
models = Activation('relu')(models)
# models = Conv2D(64, kernel_size=(3, 3), strides=2, padding='valid')(models)
# models = Activation('relu')(models)
# models = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(models)
models = Flatten()(models)
models = Dense(512)(models)
models = Activation('relu')(models)
model = Model(inputs=inp, outputs=models)
return model
def ClassiFilerNet(reuse=True): # add classifier Net
"""生成度量网络和决策网络,其实maychnet是两个网络结构,一个是特征提取层(孪生),一个度量层+匹配层(统称为决策层)"""
if reuse:
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, kernel_size=(3, 3), strides=1, padding='same')(models)
# models = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, padding='valid')(models)
models = Activation('relu')(models)
models = Conv2D(filters=96, kernel_size=(3, 3), strides=1, padding='valid')(models)
models = Activation('relu')(models)
# models = Conv2D(64, kernel_size=(3, 3), strides=2, padding='valid')(models)
# models = Activation('relu')(models)
# models = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(models)
models = Flatten()(models)
models = Dense(512)(models)
models = Activation('relu')(models)
model = Model(inputs=inp, outputs=models)
inp1 = Input(shape=(28, 28, 1)) # 创建输入
inp2 = Input(shape=(28, 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, 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])
print("22222")
return class_models