Keras получает значение узла перед активацией функции

представьте себе полностью связанную нейронную сеть с двумя последними слоями следующей структуры:

[Dense]
    units = 612
    activation = softplus

[Dense]
    units = 1
    activation = sigmoid

выходное значение сети равно 1, но я хотел бы знать, каким был вход x в сигмоидальную функцию (должно быть какое-то большое число, так как sigm(x) здесь равно 1).

опубликовала indraforyou это!--10--> ответ мне удалось получить выходные данные и веса слоев 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 может быть отрицательным числом? В таком случае последнее выход слоев должен быть ближе к 0.0, чем 1.0. Are dense_0_out или dense_1_weights неправильные выходы или Весов?

2 ответов


так как вы используете get_value(), Я предполагаю, что вы используете бэкэнд Theano. Чтобы получить значение узла до активации сигмоида, вы можете пересечь график вычислений.

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

в вашем случае, что вы хотите-это вход x сигмовидной активации op. Выход сигмовидной op is model.output. Складывая их вместе, переменная x is model.output.owner.inputs[0].

если вы распечатаете это значение, вы увидите Elemwise{add,no_inplace}.0, что является элементарным дополнением op. Это можно проверить из исходный код of Dense.call():

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] вместо.


я вижу простой способ просто немного изменить структуру модели. (См. в конце как использовать существующую модель и изменить только окончание).

преимуществами этого метода являются:

  • вам не нужно угадывать, если вы делаете правильные вычисления
  • вам не нужно заботиться о слоях отсева и о том, как реализовать расчет отсева
  • это чистое решение Keras (применяется к любому бэкэнду, либо Theano или Tensorflow).

ниже приведены два возможных решения:

  • Вариант 1-создать новую модель с самого начала с предлагаемой структурой
  • Вариант 2-повторно использовать существующую модель, изменяя только ее окончание

модель

вы могли бы просто иметь последний плотный разделен на два слоя в конце:

[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)

важно, так как вы создали новый плотный слой, чтобы получить вес от старого:

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.