Отключение softmax в моделях тензор потока - PullRequest
1 голос
/ 24 октября 2019

Все, что я хочу сделать, это загрузить одну из встроенных моделей tenorflow (через керасы), выключить softmax на выходном слое (т.е. заменить его функцией линейной активации), чтобы мои выходные функции были активациями навыходной слой до применения softmax.

Итак, я беру VGG16 как модель и называю его base_model

from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.applications.vgg16 import preprocess_input
base_model = VGG16()

. Я смотрю на последний слой следующим образом:

base_model.get_layer('predictions').get_config()

и получаю:

{'name': 'predictions',
 'trainable': True,
 'dtype': 'float32',
 'units': 1000,
 'activation': 'softmax',
 'use_bias': True,
 'kernel_initializer': {'class_name': 'GlorotUniform',
  'config': {'seed': None, 'dtype': 'float32'}},
 'bias_initializer': {'class_name': 'Zeros', 'config': {'dtype': 'float32'}},
 'kernel_regularizer': None,
 'bias_regularizer': None,
 'activity_regularizer': None,
 'kernel_constraint': None,
 'bias_constraint': None}

Затем я делаю это для переключения функций активации:

base_model.get_layer('predictions').activation=tf.compat.v1.keras.activations.linear

и похоже, что это работает так:

base_model.get_layer('predictions').get_config()

дает:

{'name': 'predictions',
 'trainable': True,
 'dtype': 'float32',
 'units': 1000,
 'activation': 'linear',
 'use_bias': True,
 'kernel_initializer': {'class_name': 'GlorotUniform',
  'config': {'seed': None, 'dtype': 'float32'}},
 'bias_initializer': {'class_name': 'Zeros', 'config': {'dtype': 'float32'}},
 'kernel_regularizer': None,
 'bias_regularizer': None,
 'activity_regularizer': None,
 'kernel_constraint': None,
 'bias_constraint': None}.

Но когда я вставляю картинку, используя:

filename = 'test_data/ILSVRC2012_val_00001218.JPEG'
img = image.load_img(filename, target_size=(224, 224)) # loads image
x = image.img_to_array(img) # convets to a numpy array
x = np.expand_dims(x, axis=0) # batches images
x = preprocess_input(x) # prepare the image for the VGG model

и я делаю прогноз, чтобы получить мои функции:

features = base_model.predict(x)

Функциясумма равна 1, то есть они выглядят так, как будто они были нормализованы с помощью softmax, поскольку

sum(features[0])

равно 1.0000000321741935, что является точно таким же числом, которое я получил, когда сделал это с помощью функции активации softmax на этом слое.

Я также попытался скопировать словарь конфигурации с 'linear' в нем и использовать set_config на выходном слое.

Отключение softmax кажется странным делом в тензорном потоке: в caffeВы можете просто переключить функции активации для предварительно обученной модели, просто изменив одну строку в файле развертывания, поэтому я действительно не понимаю, почему это так сложно в тензорном потоке. Я после переключения моего кода с caffe на тензорный поток, так как я думал, что будет проще использовать tf, чтобы просто получить предварительно обученные модели, но эта проблема заставляет меня пересмотреть.

Я предположил, что мог бы попытаться сорвать слой предсказания и заменить его новым с теми же настройками (и ввести старые веса), но я уверен, что должен быть способ просто отредактироватьслой прогнозирования.

В настоящее время я использую TensorFlow 1.14.0, я планирую обновить его до 2.0, но я не думаю, что проблема в тензорном потоке 1 здесь.

Может кто-нибудь объяснить мне, как отключить softmax, пожалуйста? Это должно быть просто, я потратил на это часы и даже присоединился к переполнению стека, чтобы исправить эту единственную проблему.

Заранее спасибо за любую помощь.

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Как уже упоминалось выше, вы всегда можете повернуть операцию softmax, которая должна быть прямой. Но если вы все еще хотите изменить активацию, вам придется скопировать веса в новый слой.

import tensorflow as tf

model = tf.keras.applications.ResNet50()
assert model.layers[-1].activation == tf.keras.activations.softmax

config = model.layers[-1].get_config()
weights = [x.numpy() for x in model.layers[-1].weights]

config['activation'] = tf.keras.activations.linear
config['name'] = 'logits'

new_layer = tf.keras.layers.Dense(**config)(model.layers[-2].output)
new_model = tf.keras.Model(inputs=[model.input], outputs=[new_layer])
new_model.layers[-1].set_weights(weights)

assert new_model.layers[-1].activation == tf.keras.activations.linear
0 голосов
/ 24 октября 2019

Керас, к сожалению, не предназначен для «сложных» вещей, таких как внесение конкретных изменений в существующие сети. Я полагаю, что возможно получить перед активацией, но это включает обход графика операций и не совсем однозначно. Однажды я попытался сделать это, но нашел, что это слишком сложно, и решил мою проблему по-другому.

Если вы делали свою собственную модель, вы могли бы просто сделать активацию отдельным слоем,и тогда вы можете вытолкнуть слой по желанию. Однако, поскольку вы используете готовую модель, вы не можете сделать это.

В зависимости от вашей конкретной ситуации у меня есть два варианта, которые я вижу:

  1. Если выЕсли вам нужно быстрое хакерское решение, которое не идеально, но может работать достаточно хорошо, вы можете просто рассчитать, каким оно было бы. Softmax - это четко определенное уравнение, поэтому вы можете просто составить обратное уравнение, а затем применить его к выходу softmax. Это не даст вам точный вывод, но должно быть достаточно близко для многих ситуаций.
  2. Если вы хотите стабильное, поддерживаемое решение, просто создайте новый слой без активации и скопируйтевеса. Я согласен, что это странно, но на самом деле это не так сложно, и я не могу придумать ни одной рациональной причины не делать этого.
...