在 tensorflow 模型中关闭 softmax

Ell*_*ale 2 python predict keras tensorflow transfer-learning

我想要做的就是下载 tensorflow 的内置模型之一(通过 keras),关闭输出层的 softmax(即用线性激活函数替换它),以便我的输出特征是输出层之前的激活应用了 softmax。

所以,我把 VGG16 作为模型,并称之为 base_model

from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.applications.vgg16 import preprocess_input
base_model = VGG16()
Run Code Online (Sandbox Code Playgroud)

我看看最后一层是这样的:

base_model.get_layer('predictions').get_config()
Run Code Online (Sandbox Code Playgroud)

并得到:

{'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}
Run Code Online (Sandbox Code Playgroud)

然后,我这样做是为了切换激活功能:

base_model.get_layer('predictions').activation=tf.compat.v1.keras.activations.linear
Run Code Online (Sandbox Code Playgroud)

它看起来像这样:

base_model.get_layer('predictions').get_config()
Run Code Online (Sandbox Code Playgroud)

给出:

{'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}.
Run Code Online (Sandbox Code Playgroud)

但是当我放入一张图片时,使用:

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
Run Code Online (Sandbox Code Playgroud)

我对它做了一个预测,以获得我的功能:

features = base_model.predict(x)
Run Code Online (Sandbox Code Playgroud)

特征总和仍为 1,即它们看起来像是被 softmax 归一化为

sum(features[0])
Run Code Online (Sandbox Code Playgroud)

是 1.0000000321741935,这与我在该层上使用 softmax 激活函数执行此操作时得到的数字完全相同。

我还尝试复制其中包含“线性”的配置字典,并在输出层上使用 set_config。

在 tensorflow 中关闭 softmax 似乎非常困难:在 caffe 中,您只需更改部署文件中的一行即可为预训练模型切换激活函数,所以我真的不明白为什么这如此困难在张量流中。我在将我的代码从 caffe 切换到 tensorflow 之后,因为我认为使用 tf 来获取预先训练的模型会更容易,但这个问题让我重新考虑。

我想我可以尝试撕掉预测层并用一个具有所有相同设置的全新层替换它(并放入旧的权重),但我相信一定有办法只编辑预测层。

我目前正在使用 TensorFlow 1.14.0,我打算升级到 2.0,但我认为使用 tensorflow 1 不是这里的问题。

谁能向我解释一下如何关闭softmax?这应该是一件简单的事情,我已经花了几个小时,甚至加入了堆栈溢出只是为了解决这个单一的问题。

在此先感谢您的帮助。

Sri*_*adi 6

正如上面已经提到的,您总是可以反转应该直接进行的 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
Run Code Online (Sandbox Code Playgroud)