文章目录
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())
-
首先定义 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())
- 看这里的例子,直接没有第 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())
- 通过这个例子,我们将第 3 个模型的输出直接并到这个模型的总输出里面。所以对于整个模型来说,现在有:
- 一个输入
(28,28,1)
, - 两个输出:
output1
--> lambda 的输出,维度是(None,10)
;output2
--> cnn3 的输出,维度是(None,10)
- 一个输入
- 通过这个例子,我们将第 3 个模型的输出直接并到这个模型的总输出里面。所以对于整个模型来说,现在有:
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_train
和 y_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)
相信聪明的你对于 多个输入和多个输出 的模型,也会训练了