keras实现权重共享网络

介绍

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

你可能感兴趣的:(keras实现权重共享网络)