【问题标题】:Tensor is not an element of this graph张量不是该图的元素
【发布时间】:2018-04-17 09:02:12
【问题描述】:

我收到了这个错误

'ValueError: Tensor Tensor("Placeholder:0", shape=(1, 1), dtype=int32) 不是此图表的元素。'

没有with tf.Graph(). as_default():,代码运行得非常好。但是我需要多次调用M.sample(...),并且每次在session.close() 之后内存都不会空闲。可能有内存泄漏,但不确定在哪里。

我想恢复一个预训练的神经网络,将其设置为默认图,并在默认图上对其进行多次测试(如 10000 次),而不是每次都变大。

代码是:

def SessionOpener(save):
    grph = tf.get_default_graph()
    sess = tf.Session(graph=grph)
    ckpt = tf.train.get_checkpoint_state(save)
    saver = tf.train.import_meta_graph('./predictor/save/model.ckpt.meta')
    if ckpt and ckpt.model_checkpoint_path:
        saver.restore(sess, ckpt.model_checkpoint_path)
        tf.global_variables_initializer().run(session=sess)
    return sess

def LoadPredictor(save):
    with open(os.path.join(save, 'config.pkl'), 'rb') as f:
        saved_args = cPickle.load(f)
    with open(os.path.join(save, 'words_vocab.pkl'), 'rb') as f:
        words, vocab = cPickle.load(f)
    model = Model(saved_args, True)
    return model, words, vocab

if __name__ == '__main__':
    Save = './save'
    M, W, V = LoadPredictor(Save)
    Sess = SessionOpener(Save)
    word = M.sample(Sess, W, V, 1, str(123), 2, 1, 4)
    Sess.close()

模型是:

class Model():
    def __init__(self, args, infer=False):
        with tf.Graph().as_default():
            self.args = args
            if infer:
                args.batch_size = 1
                args.seq_length = 1

            if args.model == 'rnn':
                cell_fn = rnn.BasicRNNCell
            elif args.model == 'gru':
                cell_fn = rnn.GRUCell
            elif args.model == 'lstm':
                cell_fn = rnn.BasicLSTMCell
            else:
                raise Exception("model type not supported: {}".format(args.model))

            cells = []
            for _ in range(args.num_layers):
                cell = cell_fn(args.rnn_size)
                cells.append(cell)

            self.cell = cell = rnn.MultiRNNCell(cells)

            self.input_data = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])
            self.targets = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])
            self.initial_state = cell.zero_state(args.batch_size, tf.float32)
            self.batch_pointer = tf.Variable(0, name="batch_pointer", trainable=False, dtype=tf.int32)
            self.inc_batch_pointer_op = tf.assign(self.batch_pointer, self.batch_pointer + 1)
            self.epoch_pointer = tf.Variable(0, name="epoch_pointer", trainable=False)
            self.batch_time = tf.Variable(0.0, name="batch_time", trainable=False)
            tf.summary.scalar("time_batch", self.batch_time)

            def variable_summaries(var):
            """Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
                with tf.name_scope('summaries'):
                    mean = tf.reduce_mean(var)
                    tf.summary.scalar('mean', mean)
                    tf.summary.scalar('max', tf.reduce_max(var))
                    tf.summary.scalar('min', tf.reduce_min(var))


            with tf.variable_scope('rnnlm'):
                softmax_w = tf.get_variable("softmax_w", [args.rnn_size, args.vocab_size])
                variable_summaries(softmax_w)
                softmax_b = tf.get_variable("softmax_b", [args.vocab_size])
                variable_summaries(softmax_b)
                with tf.device("/cpu:0"):
                    embedding = tf.get_variable("embedding", [args.vocab_size, args.rnn_size])
                    inputs = tf.split(tf.nn.embedding_lookup(embedding, self.input_data), args.seq_length, 1)
                    inputs = [tf.squeeze(input_, [1]) for input_ in inputs]

            def loop(prev, _):
                prev = tf.matmul(prev, softmax_w) + softmax_b
                prev_symbol = tf.stop_gradient(tf.argmax(prev, 1))
                return tf.nn.embedding_lookup(embedding, prev_symbol)

            outputs, last_state = legacy_seq2seq.rnn_decoder(inputs, self.initial_state, cell, loop_function=loop if infer else None, scope='rnnlm')
            output = tf.reshape(tf.concat(outputs, 1), [-1, args.rnn_size])
            self.logits = tf.matmul(output, softmax_w) + softmax_b
            self.probs = tf.nn.softmax(self.logits)
            loss = legacy_seq2seq.sequence_loss_by_example([self.logits],
                    [tf.reshape(self.targets, [-1])],
                    [tf.ones([args.batch_size * args.seq_length])],
                    args.vocab_size)
            self.cost = tf.reduce_sum(loss) / args.batch_size / args.seq_length
            tf.summary.scalar("cost", self.cost)
            self.final_state = last_state
            self.lr = tf.Variable(0.0, trainable=False)
            tvars = tf.trainable_variables()
            grads, _ = tf.clip_by_global_norm(tf.gradients(self.cost, tvars),
                args.grad_clip)
            optimizer = tf.train.AdamOptimizer(self.lr)
            self.train_op = optimizer.apply_gradients(zip(grads, tvars))

    def sample(self, sess, words, vocab, num=200, prime='first all', sampling_type=1, pick=0, width=4):
        def weighted_pick(weights):
            t = np.cumsum(weights)
            s = np.sum(weights)
            return(int(np.searchsorted(t, np.random.rand(1)*s)))

        ret = ''
        if pick == 1:
            state = sess.run(self.cell.zero_state(1, tf.float32))

            if not len(prime) or prime == ' ':
                prime  = random.choice(list(vocab.keys()))
            for word in prime.split()[:-1]:
                x = np.zeros((1, 1))
                x[0, 0] = vocab.get(word,0)
                feed = {self.input_data: x, self.initial_state:state}
                [state] = sess.run([self.final_state], feed)

            ret = prime
            word = prime.split()[-1]
            for n in range(num):
                x = np.zeros((1, 1))
                x[0, 0] = vocab.get(word, 0)
                feed = {self.input_data: x, self.initial_state:state}
                [probs, state] = sess.run([self.probs, self.final_state], feed)
                p = probs[0]

                if sampling_type == 0:
                    sample = np.argmax(p)
                elif sampling_type == 2:
                    if word == '\n':
                        sample = weighted_pick(p)
                    else:
                        sample = np.argmax(p)
                else: # sampling_type == 1 default:
                    sample = weighted_pick(p)

                ret = words[sample]
        return ret

输出是:

Traceback (most recent call last):
  File "/rcg/software/Linux/Ubuntu/16.04/amd64/TOOLS/TENSORFLOW/1.2.1-GPU-PY352/lib/python3.5/site-packages/tensorflow/python/client/session.py", line 942, in _run
    allow_operation=False)
  File "/rcg/software/Linux/Ubuntu/16.04/amd64/TOOLS/TENSORFLOW/1.2.1-GPU-PY352/lib/python3.5/site-packages/tensorflow/python/framework/ops.py", line 2584, in as_graph_element
    return self._as_graph_element_locked(obj, allow_tensor, allow_operation)
  File "/rcg/software/Linux/Ubuntu/16.04/amd64/TOOLS/TENSORFLOW/1.2.1-GPU-PY352/lib/python3.5/site-packages/tensorflow/python/framework/ops.py", line 2663, in _as_graph_element_locked
    raise ValueError("Tensor %s is not an element of this graph." % obj)
ValueError: Tensor Tensor("Placeholder:0", shape=(1, 1), dtype=int32) is not an element of this graph.

【问题讨论】:

    标签: python machine-learning tensorflow memory-leaks neural-network


    【解决方案1】:

    先试试:

    import tensorflow as tf
    graph = tf.get_default_graph()
    

    那么,当你需要使用预测时:

    with graph.as_default():
         y = model.predict(X)
    

    【讨论】:

    【解决方案2】:

    当您创建Model 时,会话尚未恢复。在Model.__init__ 中定义的所有占位符、变量和操作都放置在一个新图 中,这使得它自己成为with 块内的默认图。这是关键行:

    with tf.Graph().as_default():
      ...
    

    这意味着tf.Graph() 的这个实例等于with 块内的tf.get_default_graph() 实例,但不是在它之前或之后。从这一刻起,存在两个不同的图表。

    当您稍后创建会话并将图表恢复到其中时,您无法在该会话中访问 tf.Graph() 的先前实例。这是一个简短的例子:

    with tf.Graph().as_default() as graph:
      var = tf.get_variable("var", shape=[3], initializer=tf.zeros_initializer)
    
    # This works
    with tf.Session(graph=graph) as sess:
      sess.run(tf.global_variables_initializer())
      print(sess.run(var))  # ok because `sess.graph == graph`
    
    # This fails
    saver = tf.train.import_meta_graph('/tmp/model.ckpt.meta')
    with tf.Session() as sess:
      saver.restore(sess, "/tmp/model.ckpt")
      print(sess.run(var))   # var is from `graph`, not `sess.graph`!
    

    解决这个问题的最佳方法是为所有节点命名,例如'input''target' 等,保存模型,然后在 restored 图中按名称查找节点,如下所示:

    saver = tf.train.import_meta_graph('/tmp/model.ckpt.meta')
    with tf.Session() as sess:
      saver.restore(sess, "/tmp/model.ckpt")      
      input_data = sess.graph.get_tensor_by_name('input')
      target = sess.graph.get_tensor_by_name('target')
    

    此方法保证所有节点都来自会话中的图表。

    【讨论】:

    • 谢谢马克西姆。显然我还不能评价你的回答。
    • 嗨,我在预测时遇到了同样的错误。这个github.com/tensorflow/tensorflow/issues/… 解决了我的问题。我将 clear_session() 放在 predict 方法中的 return 语句之前。
    • 感谢您的明确解释。就我而言,尽管 tf.graph 具有相同的占位符名称,但它仍然会失败。使用sess.graph 有效。
    【解决方案3】:

    如果您正在调用从外部模块调用 Tensorflow 的 python 函数,请确保您的模型没有作为全局变量加载,否则可能无法及时加载以供使用。这发生在我从 Flask 服务器调用 Tensorflow 模型时。

    【讨论】:

    • 我在 Flask 中遇到了同样的问题。你是怎么处理的?不作为全局变量加载意味着:每个使用 Tensorflow 的函数都应该在函数内部导入?你是这样的吗?
    • @Ceyhun 我将模型加载移到被调用的函数中,因为这是唯一使用它的函数。如果您将模型用于多个函数并且仅用于函数,则可以将模型从函数传递到函数想加载一次。我使用的模型相对较小,但如果它是一个大模型,您可能不想继续加载它,特别是如果您正在进行任何主动学习。
    • 我得到了你的解决方案,但这并没有解决我的问题。我使用线程来分离进程,这也没有解决我的解决方案。我阅读了更多关于此的内容,Tensorflow 进程不会孤立地工作,只是按顺序运行并相互干扰。所以我使用子进程模块为每个函数进程调用python脚本解决了我的解决方案。我知道这是一个糟糕的解决方案,但我现在有这个。无论如何谢谢@colby-ham。
    • @Ceyhun 很高兴了解 Tensorflow 和线程。可能是一个愚蠢的问题,但您是否尝试过使用多处理?这是一个比显式生成子进程更清洁的解决方案。由于您现在让我感到好奇,我将深入研究文档以进行个人学习。
    • 不,我没有使用多处理,但是我使用了 threading.Lock。它也没有解决我的问题。我想在我的问题中,我应该把 Lock 放在我的代码中。如果我把锁放在训练部分,它与顺序单线程没有什么不同。可能是我错了,但我是这么想的。
    【解决方案4】:

    在制作模型之前使用此行:

    keras.backend.clear_session()
    

    这将创建一个用于新模型的新图表。

    【讨论】:

    • 我正在使用 tf 1.x,当我清除会话时,它对我有用。但是对于 TF 2.x,这个问题不会出现。
    【解决方案5】:

    对我来说,这个问题是通过使用 Keras 的 API 来保存和加载模型来解决的。在我的代码中训练了多个模型,我必须使用特定模型在某种条件下进行预测。

    所以我在模型训练后将整个模型保存到了 HDF5 文件中

    # The '.h5' extension indicates that the model should be saved to HDF5.
    model.save('my_model.h5')
    

    然后在预测时重新创建/重新加载保存的模型

    my_model = tf.keras.models.load_model('my_model.h5')
    

    这帮助我摆脱了

    *Tensor not an element of this graph*
    

    错误。

    【讨论】:

      【解决方案6】:

      里面 def LoadPredictor(save):
      加载模型后,添加model._make_predict_function()
      所以函数变成:

      def LoadPredictor(save):
          with open(os.path.join(save, 'config.pkl'), 'rb') as f:
              saved_args = cPickle.load(f)
          with open(os.path.join(save, 'words_vocab.pkl'), 'rb') as f:
              words, vocab = cPickle.load(f)
          model = Model(saved_args, True)
          model._make_predict_function()
          return model, words, vocab
      

      【讨论】:

      • 为您的答案添加更多解释
      【解决方案7】:

      我在尝试使用另一个使用 keras 创建模型的类创建模型时遇到了这个问题。我通过执行以下操作解决了这个问题

      import nn_classifierclass as cls
      from keras import backend
      for repeat in range(repeats):
          backend.clear_session() ##NOTICE THIS
          neural_net = cls.Classifier(.....)
          neural_net.keras_fcn_classifier()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-24
        • 1970-01-01
        • 1970-01-01
        • 2017-06-18
        • 2020-09-02
        相关资源
        最近更新 更多