Keras学习之:如何写多模型神经网络

文章目录

1. 单个模型的神经网络

  • 以 CNN 网络为例
def cnn(input_shape,classes):
    model = Sequential()
    model.add(Conv2D(input_shape=input_shape,filters=25,kernel_size=(3,3),padding='same',activation='relu')) 
    model.add(MaxPool2D())
    model.add(Dropout(rate=0.3,name='student_feature1'))
    model.add(Flatten())
    model.add(Dense(32,activation='relu',name='student_feature2'))
    model.add((Dense(classes,activation='softmax')))
    return model

model = cnn(input_shape=(28,28,1),classes=10)

这是一个非常简单的 CNN 网络,里面包含了:

  • 一个卷积层
  • 一个pooling 层
  • 一个dropout 层
  • 一个flatten 层
  • 一个全连接层

那么,如果我们需要构建一个模型,里面同时集成多个这样的 CNN 模型,该怎么写呢?、

2. 包含多个模型的神经网络创建

  • 假设我的神经网络里面包含 3 个上述 CNN 模型,我们想把他们的输入都为 (28,28,1) 的维度,输出我想利用他们三个的共同输出的平均值作为输出,那么该如何实现呢。
  • 其实对于构建一个神经网络来说,只需要关注三个部分:
    • 输入
    • 输出
    • 中间层的连接结构

在如下的实例中,我写了一个简单的多模型集成的神经网络,来实现自己想要的小功能

from keras.layers import Input,MaxPooling2D,Lambda,Dropout,Flatten,Dense,Activation
from keras.models import Model,Sequential

def cnn(input_shape,classes):
    model = Sequential()
    model.add(Conv2D(input_shape=input_shape,filters=25,kernel_size=(3,3),padding='same',activation='relu')) 
    model.add(MaxPooling2D())
    model.add(Dropout(rate=0.3,name='student_feature1'))
    model.add(Flatten())
    model.add(Dense(32,activation='relu',name='student_feature2'))
    model.add((Dense(classes,activation='softmax')))
    return model

cnn1 = cnn((28,28,1),10)
cnn2 = cnn((28,28,1),10)
cnn3 = cnn((28,28,1),10)

def mean(data):
    return (data[0] + data[1] + data[2])/3

def multi_model_net():
    inputs = Input((28,28,1))

    result1 = cnn1(inputs)
    result2 = cnn2(inputs)
    result3 = cnn3(inputs)

    outputs = Lambda(mean,output_shape=(10,))([result1,result2,result3])
    model = Model(inputs,outputs)
    return model


mod = multi_model_net()
print(mod.summary())

Keras学习之:如何写多模型神经网络

  • 首先定义 CNN 网络

  • 然后创建 3 个 CNN 网络

  • 第一个需要注意的点:使用 cnn1(inputs) 这种形式,是因为当你创建了一个 CNN 网络之后,这个网络可以被用作函数一样,把 inputs 输进去,输出来一组预测的概率值。

  • 第二个需要注意的点:使用 Lambda 来进行最终的融合操作,在神经网络的搭建过程中,所有的动作都必须在 layer 里面完成,比如你要对 layer 进行加和或者是一些运算,只要是不产生额外的参数,所有的额外操作都使用 Lambda 层来完成。就比如我们这段代码中,只是对 3 个子网络的结果进行加和求平均,并没有产生额外的训练参数。如果产生了额外训练的参数,这个时候需要额外自定义一个 layer 来完成这个工作。

  • 第三个需要注意的点:如果要创建的神经网络内部比较复杂,有多个分支,组合,处理的步骤,要使用 keras.models.Model 来建立模型,而不是简单的使用 Sequential 模型。这里也是为了给大家一个对比。在这个网络中有 3 个分支,最后又融合,使用 Sequential 模型是无法完成这个工作的。

  • 第四个需要注意的点:建立模型,输入和输出之间一定要贯通,不贯通的部分不会出现在模型里面。我们用下面的例子来解释这句话。

    
    def mean(data):
        return (data[0] + data[1])/2
        
    def multi_model_net():
        inputs = Input((28,28,1))
    
        result1 = cnn1(inputs)
        result2 = cnn2(inputs)
        result3 = cnn3(inputs)
    
        outputs = Lambda(mean,output_shape=(10,))([result1,result2])
        model = Model(inputs,outputs)
        return model
    
    mod = multi_model_net()
    print(mod.summary())
    

    Keras学习之:如何写多模型神经网络

    • 看这里的例子,直接没有第 3 个模型出现了,就是因为我们在 lambda 层没有用到第 3 个模型,而第三个模型也没有通过其他的方式贯通到输出层,所以第 3 个模型就被舍弃掉了。
  • 下面我们再通过一个例子,将第 3 个模型来贯通到输出层,使它可以重新作用于模型内部。

    def mean(data):
        return (data[0] + data[1])/2
        
    def multi_model_net():
        inputs = Input((28,28,1))
    
        result1 = cnn1(inputs)
        result2 = cnn2(inputs)
        result3 = cnn3(inputs)
    
        outputs = Lambda(mean,output_shape=(10,))([result1,result2])
        model = Model(inputs,[outputs,result3])
        return model
    
    mod = multi_model_net()
    print(mod.summary())
    

    Keras学习之:如何写多模型神经网络

    • 通过这个例子,我们将第 3 个模型的输出直接并到这个模型的总输出里面。所以对于整个模型来说,现在有:
      • 一个输入 (28,28,1)
      • 两个输出:output1 --> lambda 的输出,维度是 (None,10)output2 --> cnn3 的输出,维度是 (None,10)

3. 多模型神经网络的训练

还是先来看看单个模型的神经网络的训练

cnn1.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adam(0.001),metrics=['accuracy'])
history = cnn1.fit(x_train,y_train,batch_size=64,epochs=10,shuffle=True)

我们看这段代码,应该知道为什么在 fit 里面是 x_trainy_train

  • x_train 输入到模型里面,根据模型中的各种操作和步骤,最后会在输出层产生一个结果,这个结果在 10 分类任务中维度是 (10,)

  • 因此,我们为了对模型进行训练,我们要使用 y_train 作为 groundtruth 来不断地引导神经网络输出的结果。所以我们得到了一个 结论:模型有多少个输出,我们就应该给在 fit 中设置几个 groundtruth

  • 例如我们在 第二部分 提到的例子,我们拿过来看一下:

    def mean(data):
        return (data[0] + data[1])/2
        
    def multi_model_net():
        inputs = Input((28,28,1))
    
        result1 = cnn1(inputs)
        result2 = cnn2(inputs)
        result3 = cnn3(inputs)
    
        outputs = Lambda(mean,output_shape=(10,))([result1,result2])
        model = Model(inputs,[outputs,result3])
        return model
    
    mod = multi_model_net()
    print(mod.summary())
    
  • 我们整个模型的输出有两个部分构成:

    • lambda 层的输出
    • result3 直接作为输出
  • 所以显而易见,我们在训练这个模型的时候,应该设置 两个 groundtruth 来引导训练。

    mod.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adam(0.001),metrics=['accuracy'])
    history = mod.fit(x_train,[y_train,y_train],batch_size=64,epochs=10,shuffle=True)
    
  • 当然,如果你使用了更复杂的模型集成方法,例如你的网络中的 3 个子网络每个用的都是不同的数据集,你最后的 groundtruth 就要根据自己的需要来设定,而不是简单的都用 y_train

  • 对于 多输入的模型 ,只需要在训练的时候把输入的训练集写在方括号里,比如我随便制造一个 两个输入,一个输出的模型:

    
    def mean(data):
        return (data[0] + data[1] + data[2])/3
        
    def multi_model_net():
        input1 = Input((28,28,1))
        input2 = Input((28,28,1))
    
        result1 = cnn1(input1)
        result2 = cnn2(input1)
        result3 = cnn3(input2)
    
        outputs = Lambda(mean,output_shape=(10,))([result1,result2,result3])
        model = Model([input1,input2],outputs)
        return model
    
    mod = multi_model_net()
    print(mod.summary())
    
  • 在训练的时候你就可以随机应变:

    mod.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adam(0.001),metrics=['accuracy'])
    history = mod.fit([x_train,x_train],y_train,batch_size=64,epochs=10,shuffle=True)
    

相信聪明的你对于 多个输入和多个输出 的模型,也会训练了

上一篇:神经网络代码


下一篇:【Azure DevOps系列】使ASP.NET Core应用程序托管到Azure Web App Service