Есть ли простой способ расширить существующую функцию активации? Моя пользовательская функция softmax возвращает: у операции есть `None` для градиента - PullRequest
2 голосов
/ 08 марта 2019

Я хочу реализовать попытку ускорить softmax, используя только верхние значения k в векторе.

Для этого я попытался реализовать пользовательскую функцию для использования в модели тензорного потока:

def softmax_top_k(logits, k=10):
    values, indices = tf.nn.top_k(logits, k, sorted=False)
    softmax = tf.nn.softmax(values)
    logits_shape = tf.shape(logits)
    return_value = tf.sparse_to_dense(indices, logits_shape, softmax)
    return_value = tf.convert_to_tensor(return_value, dtype=logits.dtype, name=logits.name)
    return return_value

Я использую fashion mnist для проверки работоспособности этой попытки:

fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

# normalize the data
train_images = train_images / 255.0
test_images = test_images / 255.0

# split the training data into train and validate arrays (will be used later)
train_images, train_images_validate, train_labels, train_labels_validate = train_test_split(
    train_images, train_labels, test_size=0.2, random_state=133742,
)

model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(10, activation=softmax_top_k)
])


model.compile(
    loss='sparse_categorical_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
)

model.fit(
    train_images, train_labels,
    epochs=10,
    validation_data=(train_images_validate, train_labels_validate),
)

model_without_cnn.compile(
    loss='sparse_categorical_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
)

model_without_cnn.fit(
    train_images, train_labels,
    epochs=10,
    validation_data=(train_images_validate, train_labels_validate),
)

Но во время выполнения возникает ошибка:

ValueError: An operation has Нет for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable).

Я нашел this: (Как создать пользовательскую функцию активации) , которая объясняет, как реализовать полностью настраиваемую функцию активации для tenorflow.Но так как при этом используется и расширяется softmax, я подумал, что градиент должен быть таким же.

Это моя первая неделя написания кода с использованием Python и tenorflow, поэтому у меня пока нет хорошего обзора всех внутренних реализаций.

Есть ли более простой способ расширить softmax в новую функцию, чем реализовывать ее с нуля?

Заранее спасибо!

1 Ответ

0 голосов
/ 08 марта 2019

Вместо использования разреженных тензоров для создания тензора со "всеми нулями, кроме значений softmaxed top-K", используйте tf.scatter_nd:

import tensorflow as tf

def softmax_top_k(logits, k=10):
    values, indices = tf.nn.top_k(logits, k, sorted=False)
    softmax = tf.nn.softmax(values)
    logits_shape = tf.shape(logits)
    # Assuming that logits is 2D
    rows = tf.tile(tf.expand_dims(tf.range(logits_shape[0]), 1), [1, k])
    scatter_idx = tf.stack([rows, indices], axis=-1)
    return tf.scatter_nd(scatter_idx, softmax, logits_shape)

РЕДАКТИРОВАТЬ: Вот несколько более сложная версия для тензоров с произвольным числом измерений. Код все еще требует, чтобы число измерений было известно во время построения графа.

import tensorflow as tf

def softmax_top_k(logits, k=10):
    values, indices = tf.nn.top_k(logits, k, sorted=False)
    softmax = tf.nn.softmax(values)
    # Make nd indices
    logits_shape = tf.shape(logits)
    dims = [tf.range(logits_shape[i]) for i in range(logits_shape.shape.num_elements() - 1)]
    grid = tf.meshgrid(*dims, tf.range(k), indexing='ij')
    scatter_idx = tf.stack(grid[:-1] + [indices], axis=-1)
    return tf.scatter_nd(scatter_idx, softmax, logits_shape)
...