#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 ()?