如何监控Theano / Keras的张量值?

时间:2016-05-05 22:51:12

标签: callback monitoring theano keras

我知道这个问题已经以各种形式提出,但我找不到任何我能理解和使用的答案。如果这是一个基本问题,请原谅我,因为我是这些工具的新手(theano / keras)

要解决的问题

监控神经网络中的变量 (例如LSTM中的输入/遗忘/输出门值)

我目前正在获得

无论我在哪个阶段获得这些价值观,我都会得到类似的结论:

Elemwise{mul,no_inplace}.0
Elemwise{mul,no_inplace}.0
[for{cpu,scan_fn}.2, Subtensor{int64::}.0, Subtensor{int64::}.0]
[for{cpu,scan_fn}.2, Subtensor{int64::}.0, Subtensor{int64::}.0]
Subtensor{int64}.0
Subtensor{int64}.0

有什么方法我无法监控(例如打印到stdout,写入文件等)吗?

可能的解决方案

似乎像Keras的回调可以完成这项工作,但它对我来说也不起作用。我和上面的东西一样

我的猜测

好像我犯了很简单的错误。

非常感谢大家。

ADDED

具体来说,我正在尝试监视LSTM中的输入/遗忘/输出选通值。 我发现LSTM.step()用于计算这些值:

def step(self, x, states):
    h_tm1 = states[0]   # hidden state of the previous time step
    c_tm1 = states[1]   # cell state from the previous time step
    B_U = states[2]     # dropout matrices for recurrent units?
    B_W = states[3]     # dropout matrices for input units?

    if self.consume_less == 'cpu':                              # just cut x into 4 pieces in columns
        x_i = x[:, :self.output_dim]
        x_f = x[:, self.output_dim: 2 * self.output_dim]
        x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
        x_o = x[:, 3 * self.output_dim:]
    else:
        x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
        x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
        x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
        x_o = K.dot(x * B_W[3], self.W_o) + self.b_o

    i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
    f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
    c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
    o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))

    with open("test_visualization.txt", "a") as myfile:
        myfile.write(str(i)+"\n")

    h = o * self.activation(c)
    return h, [h, c]

就像在上面的代码中一样,我试图将i的值写入文件,但它只给了我这样的值:

Elemwise{mul,no_inplace}.0
[for{cpu,scan_fn}.2, Subtensor{int64::}.0, Subtensor{int64::}.0]
Subtensor{int64}.0

所以我尝试了itemsval()或i.get_value(),但都没有给我价值。

.eval()给了我这个:

theano.gof.fg.MissingInputError: An input of the graph, used to compute Subtensor{::, :int64:}(<TensorType(float32, matrix)>, Constant{10}), was not provided and not given a value.Use the Theano flag exception_verbosity='high',for more information on this error.

和.get_value()给了我这个:

AttributeError: 'TensorVariable' object has no attribute 'get_value'

所以我回溯了那些链(哪一行调用了哪些函数..)并尝试在我找到的每个步骤中获取值但是徒劳。

感觉我有一些基本的陷阱。

3 个答案:

答案 0 :(得分:2)

我使用Keras FAQ中描述的解决方案:

http://keras.io/getting-started/faq/#how-can-i-visualize-the-output-of-an-intermediate-layer

详细说明:

array([[ 3.,  17.]], dtype=float32)

的产率:

model.layers[1].output

但是我想使用功能API,但我似乎无法获得实际的张量,只有符号表示。例如:

<tf.Tensor 'add:0' shape=(?, 2) dtype=float32>

的产率:

{{1}}

我在这里错过了关于Keras和Tensorflow互动的一些内容,但我不确定是什么。任何见解都非常赞赏。

答案 1 :(得分:1)

一种解决方案是创建一个在LSTM层截断的网络版本,在该层上要监视门限值,然后将原始图层替换为修改了stepfunction的自定义图层,不仅仅返回隐藏层值,也是门值。

例如,假设您要访问GRU的门限值。创建一个自定义层GRU2,它继承GRU类中的所有内容,但调整步骤函数,使其返回要监视的状态的串联,然后在计算下一个激活时仅采用包含先前隐藏层激活的部分。即:

def step(self, x, states):

    # get prev hidden layer from input that is concatenation of
    # prev hidden layer + reset gate + update gate
    x = x[:self.output_dim, :]


    ###############################################
    # This is the original code from the GRU layer
    #

    h_tm1 = states[0]  # previous memory
    B_U = states[1]  # dropout matrices for recurrent units
    B_W = states[2]

    if self.consume_less == 'gpu':

        matrix_x = K.dot(x * B_W[0], self.W) + self.b
        matrix_inner = K.dot(h_tm1 * B_U[0], self.U[:, :2 * self.output_dim])

        x_z = matrix_x[:, :self.output_dim]
        x_r = matrix_x[:, self.output_dim: 2 * self.output_dim]
        inner_z = matrix_inner[:, :self.output_dim]
        inner_r = matrix_inner[:, self.output_dim: 2 * self.output_dim]

        z = self.inner_activation(x_z + inner_z)
        r = self.inner_activation(x_r + inner_r)

        x_h = matrix_x[:, 2 * self.output_dim:]
        inner_h = K.dot(r * h_tm1 * B_U[0], self.U[:, 2 * self.output_dim:])
        hh = self.activation(x_h + inner_h)
    else:
        if self.consume_less == 'cpu':
            x_z = x[:, :self.output_dim]
            x_r = x[:, self.output_dim: 2 * self.output_dim]
            x_h = x[:, 2 * self.output_dim:]
        elif self.consume_less == 'mem':
            x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
            x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
            x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
        else:
            raise Exception('Unknown `consume_less` mode.')
        z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
        r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))

        hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
    h = z * h_tm1 + (1 - z) * hh

    #
    # End of original code
    ###########################################################


    # concatenate states you want to monitor, in this case the
    # hidden layer activations and gates z and r
    all = K.concatenate([h, z, r])

    # return everything
    return all, [h]

(请注意,我添加的唯一行是在函数的开头和结尾)。

如果您使用GRU2作为最后一层而不是GRU运行您的网络(GRU2层的return_sequences = True),您只需在网络上调用预测,这将为您提供所有隐藏的图层和门限值。

同样的事情应该适用于LSTM,尽管您可能需要进一步思考如何在一个向量中存储所需的所有输出并在之后再次检索它们。

希望有所帮助!

答案 2 :(得分:0)

您可以使用theano的printing模块在​​执行期间打印 (而不是在定义期间,这是您正在做的事情以及您为什么&#39 ;没有获得价值,而是他们的抽象定义。)

打印

只需使用Print功能即可。 请勿忘记使用Print的输出继续您的图表,否则输出将被断开,并且在优化过程中很可能会删除Print。你什么也看不见。

from keras import backend as K
from theano.printing import Print

def someLossFunction(x, ref):
  loss = K.square(x - ref)
  loss = Print('Loss tensor (before sum)')(loss)
  loss = K.sum(loss)
  loss = Print('Loss scalar (after sum)')(loss)
  return loss

剧情

你可能会享受一点奖励。

Print类有一个global_fn参数,用于覆盖要打印的默认回调。您可以提供自己的功能并直接访问数据,例如构建绘图。

from keras import backend as K
from theano.printing import Print
import matplotlib.pyplot as plt

curve = []

# the callback function
def myPlottingFn(printObj, data):
    global curve
    # Store scalar data
    curve.append(data)

    # Plot it
    fig, ax = plt.subplots()
    ax.plot(curve, label=printObj.message)
    ax.legend(loc='best')
    plt.show()

def someLossFunction(x, ref):
  loss = K.sum(K.square(x - ref))
  # Callback is defined line below
  loss = Print('Loss scalar (after sum)', global_fn=myplottingFn)(loss) 
  return loss

BTW您传递给Print的字符串(&#39; ...&#39;)存储在属性名称message下的打印对象中(请参阅函数myPlottingFn)。这对于自动构建多曲线图非常有用