Условный слой модели CNN в Keras

Я пытаюсь построить conditional CNN модель. Модель,

В first stage моей модели я передаю свои данные в Model 1, затем, based on the prediction of Model 1, я хочу train the model to Conditional Cat model or Conditional Dog model и, наконец, выдаю результат из модели условной кошки или модели условной собаки. Как я могу это сделать?

Примечание: Мои усилия,

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')

Как я могу объединить эти 3 модели (model_01, model_02_1, model_02_2) на основе этих условий?

**Условия: **

  1. Подача данных в модель model_01
  2. На основе model_01 данных подачи результатов в model_02_1 or model_02_2
  3. Затем предскажите окончательный результат от model_02_1 or model_02_2

Проверьте этот ответ stackoverflow.com/a/52854474/14161847

Alex K. 25.12.2020 20:48

На всякий случай комментарий был удален, а другой добавлен.

Alex K. 25.12.2020 20:52

Ответ Алекса К. был в правильном направлении. Что именно с ним не так? Вы пытались использовать `keras.backend.equal()`?

Poe Dator 26.12.2020 20:24

@PoeDator Да, у меня проблема с K.switch. Мне не удалось назначить это, а также сравнение тензора слоев. Я застреваю, чтобы сравнить и назначить.

ashraful16 27.12.2020 21:57
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
15
4
2 876
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Чтобы построить condition-based CNN, мы могли бы передать полный пакет входных данных каждой подмодели в Model2 и выбрать желаемые выходные данные из всех выходных данных подмоделей на основе условий (которые модели, которые вы определили в вопросе), или мы можем выберите более быстрый способ, следуя шагу условий (это три условия, которые вы указали)

Пример кода для отображения механизма условия:

# Mimic the test dataset and labels
batch = tf.constant([[1, 2, 3], [2, 3, 1], [3, 1, 2]])
y_all = [tf.one_hot(i, number_of_class, dtype=tf.float32) for i in range(number_of_class)]
# Mimic the outputs of model_01
y_p = tf.constant([[0.9, 0.1], [0.1, 0.9], [0.3, 0.7]])
y_p = tf.one_hot(tf.math.argmax(y_p, axis=1), number_of_class, dtype=tf.float32)
# Mimic the conditions by choose the samples from batch base on if prediction is equal to label wrt each class
for y in y_all:
    condition = tf.reduce_all(tf.math.equal(y_p, y), 1)
    indices = tf.where(condition)
    choosed_inputs = tf.gather_nd(batch, indices)
    print("label:\n{}\ncondition:\n{}\nindices:\n{}\nchoosed_inputs:\n{}\n".format(y, condition, indices, choosed_inputs))

Выходы:

label:
[1. 0.]
condition:
[ True False False]
indices:
[[0]]
choosed_inputs:
[[1 2 3]]

label:
[0. 1.]
condition:
[False  True  True]
indices:
[[1]
 [2]]
choosed_inputs:
[[2 3 1]
 [3 1 2]]

Пример кода, который создает модель condition-based CNN и обучает ее в пользовательском режиме обучения:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import *
from tensorflow.keras.models import *
from tensorflow.keras.utils import *
import numpy as np

img_rows, img_cols, number_of_class, batch_size = 256, 256, 2, 64

#----------- main model (Model 1) ------------------------------------
inputs = Input(shape=(img_rows, img_cols, 3))
conv_01 = Convolution2D(64, 3, 3, activation='relu', name = 'conv_01') (inputs)
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 ------------------------------------ 
inputs_1 = Input(shape=skip_cat.shape[1:])
conv_05 = Convolution2D(64, 3, 3, activation='relu', name = 'conv_05') (inputs_1)
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 ------------------------------------ 
inputs_2 = Input(shape=skip_dog.shape[1:])
conv_06 = Convolution2D(64, 3, 3, activation='relu', name = 'conv_06') (inputs_2)
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 = inputs, outputs = [skip_cat, skip_dog, Output_main_model], name = 'model_main')
model_02_1 = Model(inputs = inputs_1, outputs = Output_cat_model, name = 'Conditional_cat_model')
model_02_2 = Model(inputs = inputs_2, outputs = Output_dog_model, name = 'Conditional_dog_model')

# Get one hot vectors for all the labels
y_all = [tf.one_hot(i, number_of_class, dtype=tf.float32) for i in range(number_of_class)]
sub_models_all = [model_02_1, model_02_2]
sub_models_trainable_variables = [model_01.trainable_variables[:6] + model_02_1.trainable_variables, 
                                  model_01.trainable_variables[:4] + model_02_2.trainable_variables]

cce = keras.losses.CategoricalCrossentropy()
optimizer_01 = keras.optimizers.Adam(learning_rate=1e-3, name='Adam_01')
optimizer_02 = keras.optimizers.Adam(learning_rate=2e-3, name='Adam_02')

@tf.function
def train_step(batch_imgs, labels):
    with tf.GradientTape(persistent=True) as tape:
        model_01_outputs = model_01(batch_imgs)
        y_p_01 = model_01_outputs[-1]
        loss_01 = cce(labels, y_p_01)

        # Convert outputs of model_01 from float in (0, 1) to one hot vectors, no gradients flow back from here
        y_p_01 = tf.one_hot(tf.math.argmax(y_p_01, axis=1), number_of_class, dtype=tf.float32)
        loss_02_all = []
        for i in range(number_of_class):
            condition = tf.reduce_all(tf.math.equal(y_p_01, y_all[i]), 1)
            indices = tf.where(condition)
            choosed_inputs = tf.gather_nd(model_01_outputs[i], indices)
            # Note here the inputs batch size for each sub-model is dynamic
            y_p_02 = sub_models_all[i](choosed_inputs)
            y_t = tf.gather_nd(labels, indices)
            loss_02 = cce(y_t, y_p_02)
            loss_02_all.append(loss_02)

    grads_01 = tape.gradient(loss_01, model_01.trainable_variables)
    optimizer_01.apply_gradients(zip(grads_01, model_01.trainable_variables))

    for i in range(number_of_class):
        grads_02 = tape.gradient(loss_02_all[i], sub_models_trainable_variables[i])
        optimizer_02.apply_gradients(zip(grads_02, sub_models_trainable_variables[i]))

    return loss_01, loss_02_all

def training():
    for j in range(10):
        random_imgs = np.random.rand(batch_size, img_rows, img_cols, 3)
        random_labels = np.eye(number_of_class)[np.random.choice(number_of_class, batch_size)]
        loss_01, loss_02_all = train_step(random_imgs, random_labels)
        print("Step: {}, Loss_01: {}, Loss_02_all: {}".format(j, loss_01, loss_02_all))

Выходы что-то вроде:

Step: 0, Loss_01: 0.6966696977615356, Loss_02_1: 0.0, Loss_02_2: 0.6886894702911377
Step: 1, Loss_01: 0.6912064552307129, Loss_02_1: 0.6968430280685425, Loss_02_2: 0.6911896467208862
Step: 2, Loss_01: 0.6910352110862732, Loss_02_1: 0.698455274105072, Loss_02_2: 0.6935626864433289
Step: 3, Loss_01: 0.6955667734146118, Loss_02_1: 0.6843984127044678, Loss_02_2: 0.6953505277633667
Step: 4, Loss_01: 0.6941269636154175, Loss_02_1: 0.673763632774353, Loss_02_2: 0.6994296908378601
Step: 5, Loss_01: 0.6872361898422241, Loss_02_1: 0.6769005060195923, Loss_02_2: 0.6907837390899658
Step: 6, Loss_01: 0.6931678056716919, Loss_02_1: 0.7674703598022461, Loss_02_2: 0.6935689449310303
Step: 7, Loss_01: 0.6976977586746216, Loss_02_1: 0.7503389120101929, Loss_02_2: 0.7076178789138794
Step: 8, Loss_01: 0.6932153105735779, Loss_02_1: 0.7428234219551086, Loss_02_2: 0.6935019493103027
Step: 9, Loss_01: 0.693305253982544, Loss_02_1: 0.6476342082023621, Loss_02_2: 0.6916818618774414
Ответ принят как подходящий

Проблема с условными операторами в нейронных сетях

Проблема с переключателем или условными операторами (например, 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

Но я не думаю, что вы ищете это. Я думаю, вы хотите включить условные выражения как часть самого графа вычислений.

К сожалению, насколько мне известно, у вас нет прямого способа построить условие «если-то» как часть графа вычислений. keras.switch, который вы видите, позволяет вам работать с тензорными выходами, но не со слоями графа во время обучения. Вот почему вы увидите, что он используется как часть функций потерь, а не в графах вычислений (выдает ошибки ввода).

Возможное решение - пропустить соединения и мягкое переключение

Однако вы можете попытаться построить что-то подобное с помощью skip connections и soft switching.

Соединение с пропуском — это соединение предыдущего уровня с другим уровнем, позволяющее передавать информацию последующим уровням. Это довольно распространено в очень глубоких сетях, где информация из исходных данных впоследствии теряется. Например, проверьте U-net или Resnet, которые используют пропуск соединений между слоями для передачи информации будущим слоям.

Следующим вопросом является вопрос переключения. Вы хотите переключиться между двумя возможными путями на графике. Что вы можете сделать, так это метод мягкого переключения, который я вдохновил этой статьи. Обратите внимание, что для того, чтобы switch между двумя распределениями слов (одно из декодера и другое из ввода), авторы умножают их на p и (1-p), чтобы получить кумулятивное распределение. Это программный переключатель, который позволяет модели выбирать следующее предсказанное слово либо из декодера, либо из самого ввода. (помогает, когда вы хотите, чтобы ваш чат-бот произносил слова, введенные пользователем, как часть ответа на него!)

Поняв эти 2 понятия, давайте попробуем интуитивно построить нашу архитектуру.

  1. Сначала нам нужен граф с одним входом и несколькими выходами, так как мы обучаем 2 модели.

  2. Наша первая модель представляет собой многоклассовую классификацию, которая предсказывает индивидуальные вероятности для Кошки и Собаки по отдельности. Это будет тренироваться с активацией softmax и потерей categorical_crossentropy.

  3. Далее, давайте возьмем логит, который предсказывает вероятность Cat, и умножим на него слой свертки 3. Это можно сделать с помощью слоя Lambda.

  4. И аналогично, давайте возьмем вероятность Собаки и умножим ее на слой свертки 2. Это можно увидеть следующим образом:

    • Если моя первая модель идеально предсказывает кошку, а не собаку, тогда вычисление будет 1*(Conv3) и 0*(Conv2).
    • Если первая модель точно предсказывает собаку, а не кошку, тогда вычисление будет 0*(Conv3) и 1*(Conv2)
    • Вы можете думать об этом либо как soft-switch ИЛИ как forget gate из LSTM. forget gate — это сигмовидный (от 0 до 1) выходной сигнал, который умножает состояние ячейки, чтобы закрыть ее и позволить LSTM забыть или запомнить предыдущие временные шаги. Аналогичная концепция здесь!
  5. Эти Conv3 и Conv2 теперь могут быть дополнительно обработаны, сведены, объединены и переданы на другой плотный слой для окончательного прогноза.

Таким образом, если модель не уверена в отношении собаки или кошки, функции 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

Другие вопросы по теме