2017-08-03 26 views
13

考慮具有以下結構的其最後的兩層的完全連接的神經網絡:Keras激活函數之前檢索節點的值

[Dense] 
    units = 612 
    activation = softplus 

[Dense] 
    units = 1 
    activation = sigmoid 

淨的輸出值是1,但我想知道sigmoidal函數的輸入x是什麼(必須是一些很高的數字,因爲sigm(x)在這裏是1)。

Folllowing indraforyou's答案我設法獲取Keras層的輸出和重量:

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 

怎麼能X是負數?在這種情況下,最後一層的輸出應該是一個比1.0更接近0.0的數字。 dense_0_outdense_1_weights錯誤的輸出或權重?

+1

它不應該是'x = np.dot(dense_0_out,dense_1_weights)+ dense_1_bias'嗎? –

+0

@MarcinMożejko你是對的,我糾正了它。由於偏見被訓練到0.0,所以沒有任何改變。 – johk95

+0

但是這個層的輸出被送到softmax--你獲得的值被壓縮到[0,1]間隔。 –

回答

5

由於您使用的是get_value(),我假設您使用的是Theano後端。要在sigmoid激活之前獲取節點的值,可以使用traverse the computation graph

該圖可以從輸出(某些計算的結果)開始遍歷到使用所有者字段的輸入。

在你的情況,你想要的是sigmoid激活op的輸入x。 sigmoid op的輸出是model.output。把它們放在一起,變量xmodel.output.owner.inputs[0]

如果你打印出這個值,你會看到Elemwise{add,no_inplace}.0,這是一個元素明智的加法操作。它可以從Dense.call()source code進行驗證:

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]代替。

+0

謝謝你的答案!我很清楚你的方法更適合,但是你能否簡單地評論一下我的原始代碼......這是否會計算出錯誤?爲什麼? – johk95

+0

你有沒有嘗試過這種方法,它仍然給你一個負面的'x'?我試過你的代碼,它給出了與這種方法完全相同的結果(一個* positive *'x',大約在600),所以我不太確定問題出在你的代碼中。 –

+0

順便說一句,我從程序中看到'dense_0_out.shape'等於'(1,612)'和'dense_1_weights.shape'等於'(612,1)',這與您發佈的內容不同。你能提供你使用的'test_input'和Keras和TF的版本嗎? –

4

我可以看到一個簡單的方法,只是改變一點模型結構。 (最後查看如何使用現有模型並只更改結尾)。

這種方法的優點是:

  • 你不必去猜測,如果你做了正確的計算
  • 你不需要關心輟學層,以及如何實現退出計算
  • 這是一個純粹的Keras解決方案(適用於任何後端,Theano或Tensorflow)。

有以下兩種可能的解決方案:

  • 選項1 - 與提出的結構
  • 選項2創建一個從開始一個新的模型 - 重複使用現有的模型只改變其結束

模型結構

你可以ju st在最後兩層中有最後一個密集分隔:

[Dense] 
    units = 612 
    activation = softplus 

[Dense] 
    units = 1 
    #no activation 

[Activation] 
    activation = sigmoid 

然後你只需得到最後一個密集層的輸出。

我想說你應該創建兩個模型,一個用於訓練,另一個用於檢查這個值。

選項1 - 從一開始就構建模型:

#if using the functional API 
    checkingModel = Model(yourInputs, denseOut) 

#if using the sequential model: 
    checkingModel = model 

trainingModel = Model(checkingModel.inputs, sigmoidOut) 

使用trianingModel

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) 

檢查的密集輸出創建一個從兩個模型,一個是培訓,一個正常訓練。這兩個模型分享權重,所以訓練一個就是訓練另一個。

使用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) 

是很重要的,因爲你創造了一個新的密集層,以獲得來自舊的權重:

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