Keras中的CNN模型条件层
我正在尝试建立一个conditional CNN模型。模型是,
在first stage我的模型中,我将我的数据提供给Model 1然后,based on the prediction of Model 1我想train the model to Conditional Cat model or Conditional Dog model最后给出来自 Conditional Cat 模型或 Conditional Dog 模型的输出。我怎样才能做到这一点?
注意:
我的努力是,
import keras
from keras.layers import *
from keras.models import *
from keras.utils import *
img_rows,img_cols,number_of_class = 256,256,2
input = Input(shape=(img_rows,img_cols,3))
#----------- main model (Model 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_02
conv_03 = Convolution2D(64, 3, 3, activation='relu',name = 'conv_03') (conv_02)
skip_cat = conv_03
conv_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)
#----------- Conditional Cat 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)
#----------- Conditional Dog 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)
#----------------------------- My discrete 3 models --------------------------------
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根据这些条件合并这 3 个模型 ( )?
**条件是:**
- 向模型馈送数据
model_01 - 基于
model_01结果提要数据model_02_1 or model_02_2 - 接下来,预测最终输出
model_02_1 or model_02_2
回答
神经网络中的条件问题
作为神经网络一部分的开关或条件(如 if-then-else)的问题在于条件在任何地方都不可微。因此,自动微分方法不会直接起作用,解决这个问题非常复杂。检查这个以获取更多详细信息。
一个捷径是您最终可以独立训练 3 个单独的模型,然后在推理过程中使用条件控制流从它们中进行推理。
#Training -
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)
#Inference -
if model1.predict == Cat:
model2.predict
else:
model3.predict
但我不认为你在寻找那个。我认为您希望将条件作为计算图本身的一部分。
可悲的是,根据我的知识,没有直接的方法可以将 if-then 条件构建为计算图的一部分。在keras.switch你看到让你与张量输出工作,但不与训练中的图形层。这就是为什么你会看到它被用作损失函数的一部分而不是在计算图中(抛出输入错误)。
一种可能的解决方案 - 跳过连接和软切换
但是,您可以尝试使用skip connections和构建类似的东西soft switching。
跳过连接是从前一层到另一层的连接,它允许您将信息传递到后续层。这在非常深的网络中很常见,其中来自原始数据的信息随后丢失。例如,检查U-net或Resnet,它使用层之间的跳过连接将信息传递给未来的层。
下一个问题是切换的问题。您想在图中的 2 条可能路径之间切换。你可以做的是一种软切换方法,我从这篇论文中汲取了灵感。请注意,为了switch在 2 个单词分布之间(一个来自解码器,另一个来自输入),作者将它们与p和相乘(1-p)以获得累积分布。这是一个软开关,允许模型从解码器或输入本身中选择下一个预测词。(当您希望聊天机器人说出用户输入的单词作为其响应的一部分时会有所帮助!)
理解了这两个概念后,让我们尝试直观地构建我们的架构。
-
首先我们需要一个单输入多输出图,因为我们正在训练 2 个模型
-
我们的第一个模型是一个多类分类,分别预测猫和狗的个体概率。这将通过激活
softmax和categorical_crossentropy损失进行训练。 -
接下来,让我们取预测 Cat 概率的 logit,并将其与卷积层 3 相乘。这可以通过
Lambda层来完成。 -
同样,让我们取 Dog 的概率并将其与卷积层 2 相乘。 这可以看作是以下内容 -
- 如果我的第一个模型预测的是猫而不是狗,那么完美的计算将是
1*(Conv3)和0*(Conv2)。 - 如果第一个模型预测一只狗,而不是猫,完美,那么计算会
0*(Conv3)和1*(Conv2) - 您可以将其视为来自LSTM的
soft-switchOR a 。这是一个 sigmoid(0 到 1)输出,它乘以单元状态以对其进行门控,并允许 LSTM 忘记或记住之前的时间步长。类似的概念在这里!forget gateforget gate
- 如果我的第一个模型预测的是猫而不是狗,那么完美的计算将是
-
这些 Conv3 和 Conv2 现在可以进一步处理、展平、连接并传递到另一个 Dense 层以进行最终预测。
这样,如果模型不确定是狗还是猫,conv2 和 conv3 特征都会参与第二个模型的预测。这就是您可以使用skip connections和soft switch启发机制向网络添加一定数量的条件控制流的方式。
检查我对下面计算图的实现。
from tensorflow.keras import layers, Model, utils
import numpy as np
X = np.random.random((10,500,500,3))
y = np.random.random((10,2))
#Model
inp = 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/5
1/1 [==============================] - 1s 1s/step - loss: 0.6819 - first_loss: 0.7424 - second_loss: 0.6214
Epoch 2/5
1/1 [==============================] - 0s 423ms/step - loss: 0.6381 - first_loss: 0.6361 - second_loss: 0.6400
Epoch 3/5
1/1 [==============================] - 0s 442ms/step - loss: 0.6137 - first_loss: 0.6126 - second_loss: 0.6147
Epoch 4/5
1/1 [==============================] - 0s 434ms/step - loss: 0.6214 - first_loss: 0.6159 - second_loss: 0.6268
Epoch 5/5
1/1 [==============================] - 0s 427ms/step - loss: 0.6248 - first_loss: 0.6184 - second_loss: 0.6311