我正在尝试构建一个条件CNN
模型。这个模型是这样的,
在我的模型的第一阶段
,我将数据输入到模型1
,然后,基于模型1的预测
,我想训练模型为条件猫模型或条件狗模型
,最后,从条件猫模型或条件狗模型中输出结果。我该如何实现这一点?
注意:我的努力是,
import kerasfrom keras.layers import *from keras.models import *from keras.utils import *img_rows,img_cols,number_of_class = 256,256,2input = Input(shape=(img_rows,img_cols,3))#----------- 主模型(模型1) ------------------------------------conv_01 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_01') (input)conv_02 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_02') (conv_01)skip_dog = conv_02conv_03 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_03') (conv_02)skip_cat = conv_03conv_04 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_04') (conv_03)flatten_main_model = Flatten() (conv_04)Output_main_model = Dense(units = number_of_class , activation = 'softmax', name = "Output_layer")(flatten_main_model)#----------- 条件猫模型 ------------------------------------ conv_05 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_05') (skip_cat)flatten_cat_model = Flatten() (conv_05)Output_cat_model = Dense(units = number_of_class , activation = 'softmax', name = "Output_layer_cat")(flatten_cat_model)#----------- 条件狗模型 ------------------------------------ conv_06 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_06') (skip_dog)flatten_dog_model = Flatten() (conv_06)Output_dog_model = Dense(units = number_of_class , activation = 'softmax', name = "Output_layer_dog")(flatten_dog_model)#----------------------------- 我的三个独立模型 --------------------------------model_01 = Model(inputs = input , outputs = Output_main_model,name = 'model_main')model_02_1 = Model(inputs = input , outputs = Output_cat_model ,name = 'Conditional_cat_model')model_02_2 = Model(inputs = input , outputs = Output_dog_model ,name = 'Conditional_dog_model')
我如何根据这些条件合并这三个模型(model_01, model_02_1, model_02_2
)?
**条件如下: **
- 将数据输入到模型
model_01
- 根据
model_01
的结果,将数据输入到model_02_1或model_02_2
- 接下来,从
model_02_1或model_02_2
预测最终输出
回答:
神经网络中的条件问题
在神经网络中使用切换或条件(如if-then-else)的问题在于,条件在某些地方不是可微分的。因此,自动微分方法将无法直接工作,解决这个问题非常复杂。请查看这里以获取更多详情。
一个捷径是,你可以独立训练三个模型,然后在推理时使用条件控制流程从中推断。
#训练 - model1 = model.fit(all images, P(cat/dog))model2 = model.fit(all images, P(cat))model3 = model.fit(all images, P(dog))final prediction = argmax(model2, model3)#推理 - if model1.predict == Cat: model2.predictelse: model3.predict
但我认为你并不在寻找这个方法。我认为你希望将条件作为计算图的一部分来包含。
遗憾的是,根据我的了解,没有直接的方法在计算图中构建if-then条件。你看到的keras.switch
允许你处理张量输出,但在训练过程中不能用于图层的层。这就是为什么你会看到它被用作损失函数的一部分,而不是在计算图中使用(会抛出输入错误)。
可能的解决方案 – 跳跃连接与软切换
然而,你可以尝试使用跳跃连接
和软切换
构建类似的东西。
跳跃连接是从前一层到另一层的连接,允许你将信息传递给后续层。这在非常深的网络中很常见,原始数据的信息会逐渐丢失。例如,查看U-net或Resnet,它们在层之间使用跳跃连接将信息传递给未来的层。
接下来的问题是切换问题。你想在图中切换两个可能的路径。你可以使用一种软切换方法,这是我从这篇论文中获得的灵感。注意,为了切换
两个词的分布(一个来自解码器,另一个来自输入),作者将它们分别乘以p
和(1-p)
以获得累积分布。这是一种软切换,允许模型从解码器或输入本身中选择下一个预测的词。(当你希望你的聊天机器人能在响应中说出用户输入的词时,这很有帮助!)
了解了这两个概念后,让我们尝试直观地构建我们的架构。
-
首先,我们需要一个单输入多输出的图,因为我们在训练两个模型
-
我们的第一个模型是多类分类,分别预测猫和狗的个别概率。这将使用
softmax
激活和categorical_crossentropy
损失进行训练。 -
接下来,我们取预测猫的概率的logit,并将其与卷积层3相乘。这可以通过
Lambda
层来完成。 -
同样,我们取狗的概率并将其与卷积层2相乘。这可以看作是以下情况 –
- 如果我的第一个模型完美地预测出猫而不是狗,那么计算将是
1*(Conv3)
和0*(Conv2)
。 - 如果第一个模型完美地预测出狗而不是猫,那么计算将是
0*(Conv3)
和1*(Conv2)
- 你可以将这视为
软切换
或遗忘门
来自LSTM。遗忘门
是一个sigmoid(0到1)输出,它乘以单元状态以对其进行门控,允许LSTM忘记或记住之前的时间步。类似的概念在这里!
- 如果我的第一个模型完美地预测出猫而不是狗,那么计算将是
-
这些Conv3和Conv2现在可以进一步处理、扁平化、连接,并传递给另一个Dense层以进行最终预测。
这样,如果模型对狗或猫不确定,conv2和conv3的特征都会参与到第二个模型的预测中。这是你如何使用跳跃连接
和软切换
启发的机制,为你的网络添加一些条件控制流程的方法。
查看我下面的计算图实现。
from tensorflow.keras import layers, Model, utilsimport numpy as npX = np.random.random((10,500,500,3))y = np.random.random((10,2))#Modelinp = layers.Input((500,500,3))x = layers.Conv2D(6, 3, name='conv1')(inp)x = layers.MaxPooling2D(3)(x)c2 = layers.Conv2D(9, 3, name='conv2')(x)c2 = layers.MaxPooling2D(3)(c2)c3 = layers.Conv2D(12, 3, name='conv3')(c2)c3 = layers.MaxPooling2D(3)(c3)x = layers.Conv2D(15, 3, name='conv4')(c3)x = layers.MaxPooling2D(3)(x)x = layers.Flatten()(x)out1 = layers.Dense(2, activation='softmax', name='first')(x)c = layers.Lambda(lambda x: x[:,:1])(out1)d = layers.Lambda(lambda x: x[:,1:])(out1)c = layers.Multiply()([c3, c])d = layers.Multiply()([c2, d])c = layers.Conv2D(15, 3, name='conv5')(c)c = layers.MaxPooling2D(3)(c)c = layers.Flatten()(c)d = layers.Conv2D(12, 3, name='conv6')(d)d = layers.MaxPooling2D(3)(d)d = layers.Conv2D(15, 3, name='conv7')(d)d = layers.MaxPooling2D(3)(d)d = layers.Flatten()(d)x = layers.concatenate([c,d])x = layers.Dense(32)(x)out2 = layers.Dense(2, activation='softmax',name='second')(x)model = Model(inp, [out1, out2])model.compile(optimizer='adam', loss='categorical_crossentropy', loss_weights=[0.5, 0.5])model.fit(X, [y, y], epochs=5)utils.plot_model(model, show_layer_names=False, show_shapes=True)
Epoch 1/51/1 [==============================] - 1s 1s/step - loss: 0.6819 - first_loss: 0.7424 - second_loss: 0.6214Epoch 2/51/1 [==============================] - 0s 423ms/step - loss: 0.6381 - first_loss: 0.6361 - second_loss: 0.6400Epoch 3/51/1 [==============================] - 0s 442ms/step - loss: 0.6137 - first_loss: 0.6126 - second_loss: 0.6147Epoch 4/51/1 [==============================] - 0s 434ms/step - loss: 0.6214 - first_loss: 0.6159 - second_loss: 0.6268Epoch 5/51/1 [==============================] - 0s 427ms/step - loss: 0.6248 - first_loss: 0.6184 - second_loss: 0.6311