想象一个完全连接的神经网络,其最后两层具有以下结构:
.table-row-cell .table-cell {
-fx-font-weight: normal;
}
.table-row-cell:warning .table-cell {
-fx-font-weight: bold;
}
网络的输出值是1,但是我想知道sigmoidal函数的输入x是什么(必须是一些高数字,因为sigm(x)在这里是1)。
以下indraforyou's回答我设法检索了Keras图层的输出和权重:
[Dense]
units = 612
activation = softplus
[Dense]
units = 1
activation = sigmoid
x如何成为负数?在这种情况下,最后一层输出应该是一个接近0.0而不是1.0的数字。 outputs = [layer.output for layer in model.layers[-2:]]
functors = [K.function( [model.input]+[K.learning_phase()], [out] ) for out in outputs]
test_input = np.array(...)
layer_outs = [func([test_input, 0.]) for func in functors]
print layer_outs[-1][0] # -> array([[ 1.]])
dense_0_out = layer_outs[-2][0] # shape (612, 1)
dense_1_weights = model.layers[-1].weights[0].get_value() # shape (1, 612)
dense_1_bias = model.layers[-1].weights[1].get_value()
x = np.dot(dense_0_out, dense_1_weights) + dense_1_bias
print x # -> -11.7
或dense_0_out
输出或权重是否错误?
答案 0 :(得分:7)
由于您正在使用get_value()
,因此我假设您正在使用Theano后端。要在sigmoid激活之前获取节点的值,您可以traverse the computation graph。
可以使用owner字段从输出(某些计算的结果)开始遍历到其输入。
在您的情况下,您想要的是sigmoid激活操作的输入x
。 sigmoid op的输出为model.output
。将这些变量放在一起,变量x
为model.output.owner.inputs[0]
。
如果您打印出此值,则会看到Elemwise{add,no_inplace}.0
,这是一个按元素添加的操作。可以通过Dense.call()
的{{3}}验证:
def call(self, inputs):
output = K.dot(inputs, self.kernel)
if self.use_bias:
output = K.bias_add(output, self.bias)
if self.activation is not None:
output = self.activation(output)
return output
激活功能的输入是K.bias_add()
的输出。
通过对代码进行少量修改,您可以在激活之前获取节点的值:
x = model.output.owner.inputs[0]
func = K.function([model.input] + [K.learning_phase()], [x])
print func([test_input, 0.])
对于使用TensorFlow后端的任何人:请改用x = model.output.op.inputs[0]
。
答案 1 :(得分:4)
我可以看到一个简单的方法只是改变一点模型结构。 (最后请参见如何使用现有模型并仅更改结尾)。
这种方法的优点是:
下面有两种可能的解决方案:
模型结构
你最后可以将最后一个密集分成两层:
[Dense]
units = 612
activation = softplus
[Dense]
units = 1
#no activation
[Activation]
activation = sigmoid
然后你只需得到最后一个密集层的输出。
我会说你应该创建两个模型,一个用于训练,另一个用于检查这个值。
选项1 - 从头开始构建模型:
from keras.models import Model
#build the initial part of the model the same way you would
#add the Dense layer without an activation:
#if using the functional Model API
denseOut = Dense(1)(outputFromThePreviousLayer)
sigmoidOut = Activation('sigmoid')(denseOut)
#if using the sequential model - will need the functional API
model.add(Dense(1))
sigmoidOut = Activation('sigmoid')(model.output)
从中创建两个模型,一个用于训练,一个用于检查密集输出:
#if using the functional API
checkingModel = Model(yourInputs, denseOut)
#if using the sequential model:
checkingModel = model
trainingModel = Model(checkingModel.inputs, sigmoidOut)
正常使用trianingModel
进行培训。这两个模型共享权重,因此训练一个是训练另一个。
使用checkingModel
仅使用checkingModel.predict(X)
选项2 - 从现有模型中构建:
from keras.models import Model
#find the softplus dense layer and get its output:
softplusOut = oldModel.layers[indexForSoftplusLayer].output
#or should this be the output from the dropout? Whichever comes immediately after the last Dense(1)
#recreate the dense layer
outDense = Dense(1, name='newDense', ...)(softPlusOut)
#create the new model
checkingModel = Model(oldModel.inputs,outDense)
重要的是,因为您创建了一个新的Dense图层,以便从旧图层中获取权重:
wgts = oldModel.layers[indexForDense].get_weights()
checkingModel.get_layer('newDense').set_weights(wgts)
在这种情况下,训练旧模型不会更新新模型中的最后一个密集层,因此,让我们创建一个trainingModel:
outSigmoid = Activation('sigmoid')(checkingModel.output)
trainingModel = Model(checkingModel.inputs,outSigmoid)
使用checkingModel
通过checkingModel.predict(X)
检查所需的值。并训练trainingModel
。
答案 2 :(得分:2)
这对其他Google员工来说,自发布可接受的答案以来,keras API的工作已发生了显着变化。在激活之前(针对tensorflow后端)提取层输出的工作代码为:
model = Your_Keras_Model()
the_tensor_you_need = model.output.op.inputs[0] #<- this is indexable, if there are multiple inputs to this node then you can find it with indexing.
在我的情况下,最后一层是激活为softmax
的致密层,因此我需要的张量输出为<tf.Tensor 'predictions/BiasAdd:0' shape=(?, 1000) dtype=float32>
。
答案 3 :(得分:0)
(TF后端) 转换层的解决方案。
我有同样的问题,并且重写模型的配置不是一种选择。 简单的技巧是手动执行调用功能。它可以控制激活。
从Keras source复制粘贴,其中self
更改为layer
。您可以对任何其他图层执行相同操作。
def conv_no_activation(layer, inputs, activation=False):
if layer.rank == 1:
outputs = K.conv1d(
inputs,
layer.kernel,
strides=layer.strides[0],
padding=layer.padding,
data_format=layer.data_format,
dilation_rate=layer.dilation_rate[0])
if layer.rank == 2:
outputs = K.conv2d(
inputs,
layer.kernel,
strides=layer.strides,
padding=layer.padding,
data_format=layer.data_format,
dilation_rate=layer.dilation_rate)
if layer.rank == 3:
outputs = K.conv3d(
inputs,
layer.kernel,
strides=layer.strides,
padding=layer.padding,
data_format=layer.data_format,
dilation_rate=layer.dilation_rate)
if layer.use_bias:
outputs = K.bias_add(
outputs,
layer.bias,
data_format=layer.data_format)
if activation and layer.activation is not None:
outputs = layer.activation(outputs)
return outputs
现在我们需要对main函数进行一些修改。首先,通过名称来标识图层。然后从上一层检索激活。最后,计算目标层的输出。
def get_output_activation_control(model, images, layername, activation=False):
"""Get activations for the input from specified layer"""
inp = model.input
layer_id, layer = [(n, l) for n, l in enumerate(model.layers) if l.name == layername][0]
prev_layer = model.layers[layer_id - 1]
conv_out = conv_no_activation(layer, prev_layer.output, activation=activation)
functor = K.function([inp] + [K.learning_phase()], [conv_out])
return functor([images])
这是一个小小的测试。我正在使用VGG16模型。
a_relu = get_output_activation_control(vgg_model, img, 'block4_conv1', activation=True)[0]
a_no_relu = get_output_activation_control(vgg_model, img, 'block4_conv1', activation=False)[0]
print(np.sum(a_no_relu < 0))
> 245293
将所有负数设置为零,以与嵌入VGG16 ReLu操作后检索到的结果进行比较。
a_no_relu[a_no_relu < 0] = 0
print(np.allclose(a_relu, a_no_relu))
> True
答案 4 :(得分:0)
使用新的激活功能定义新层的简便方法:
def change_layer_activation(layer):
if isinstance(layer, keras.layers.Conv2D):
config = layer.get_config()
config["activation"] = "linear"
new = keras.layers.Conv2D.from_config(config)
elif isinstance(layer, keras.layers.Dense):
config = layer.get_config()
config["activation"] = "linear"
new = keras.layers.Dense.from_config(config)
weights = [x.numpy() for x in layer.weights]
return new, weights