Сигмоида тензорного потока / Кераса на одном выходе плотного слоя

#python #tensorflow #keras

Вопрос:

У меня есть простая модель CNN в tensorflow, которая принимает изображение и предсказывает вектор меток из 6 элементов. Таким образом, последний слой моего режима является Плотным(6). Метка[0] должна быть двоичной, в то время как метка[1:6] имеет непрерывное значение. Поэтому я хочу применить активацию сигмоиды к выходному слою только на первом узле вывода, оставив остальные 5 выходов как есть. Как мне это сделать с tensorflow.keras? Для простоты мой код построения модели в настоящее время выглядит примерно так:

 model = tf.keras.models.Sequential() model.add(Reshape((image_size, image_size, 1), input_shape = (image_size, image_size)) model.add(Conv2D(8, **parameters)) model.add(BatchNormalization()) model.add(Activation('relu') Model.add(MaxPool2D()) model.add(Flatten()) model.add(Dense(6))  

Как я могу добавить к этому, чтобы использовать активацию сигмоиды на первом индексе последнего слоя?

Ответ №1:

Вы можете определить простой пользовательский Lambda слой и делать именно то, что хотите. Вот пример, изначально не имеющий функции активации. Обратите внимание на результат:

 import tensorflow as tf tf.random.set_seed(2)  def custom_layer(tensor):  activated_node = tf.nn.sigmoid(tensor[:, :1])  return tf.concat([activated_node, tensor[:, 1:]], axis=1)  model = tf.keras.Sequential() model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(6))  model(tf.random.uniform((2, 5)))  
 lt;tf.Tensor: shape=(2, 6), dtype=float32, numpy= array([[-1.1554979 , 0.29463094, 0.57452184, 0.40530735, -0.15730543,  0.16329125],  [-1.1518296 , 1.2684885 , 0.50156784, 1.2273686 , 0.13656075,  -0.7025717 ]], dtype=float32)gt;  

А теперь перейдем к пользовательскому Lambda слою, который применяет функцию активации к первому узлу в вашем тензоре:

 import tensorflow as tf tf.random.set_seed(2)  def custom_layer(tensor):  activated_node = tf.nn.sigmoid(tensor[:, :1])  return tf.concat([activated_node, tensor[:, 1:]], axis=1)  model = tf.keras.Sequential() model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(6)) model.add(tf.keras.layers.Lambda(custom_layer, name="activation_layer"))  model(tf.random.uniform((2, 5)))  
 lt;tf.Tensor: shape=(2, 6), dtype=float32, numpy= array([[ 0.23948632, 0.29463094, 0.57452184, 0.40530735, -0.15730543,  0.16329125],  [ 0.24015504, 1.2684885 , 0.50156784, 1.2273686 , 0.13656075,  -0.7025717 ]], dtype=float32)gt;  

Вы можете ясно видеть, как первый элемент каждого образца (я использую batch_size=2) сжимается между 0 и 1.

Ответ №2:

Предположим, что мы получаем результат вашей модели в виде pred, тогда pred будет тензором формы(1, 6), поэтому для достижения вашей цели вы можете сделать что-то вроде этого:

 sigmoid_input = pred.numpy()[0][0] sigmoid_output = tf.keras.activations.sigmoid(sigmoid_input)  

Поэтому сначала вам нужно преобразовать тензор в Numpy ndarray, а затем получить доступ только к первому элементу вашего тензора. После этого мы передаем новую переменную sigmoid_input, содержащую это значение, в сигмоид, как и планировалось.

Комментарии:

1. Спасибо. Я на самом деле хотел, чтобы сигмоида была частью обучаемой модели, чтобы она обучалась с выводом в диапазоне [0,1], а не [-inf, inf]. Могу ли я как-то сделать это с помощью model.add ()?