【问题标题】:Why does pickling a tensorflow Tensor fail?为什么酸洗张量流张量会失败?
【发布时间】:2017-05-03 20:26:22
【问题描述】:

这是一个使用dill 序列化成功的sn-p,但使用pickle 失败。令人惊讶的是,Tensor 对象本身不是可腌制的。这是线程感知张量的基本限制,还是没有实现?

import dill
import pickle
import tensorflow as tf

dill.dumps(tf.zeros((1,1)))
print("Dill succeeded")
pickle.dumps(tf.zeros((1,1)))
print("Pickle succeeded")

输出:

$ python foo.py
Dill succeeded
Traceback (most recent call last):
  File "foo.py", line 7, in <module>
    pickle.dumps(tf.zeros((1,1)))
TypeError: can't pickle _thread.lock objects

【问题讨论】:

标签: python tensorflow serialization pickle dill


【解决方案1】:

为什么dill可以序列化这些对象,却不能pickle?简单的答案是pickle 无法序列化python 中的大多数对象,包括thread.lock 对象。如果您想序列化这些对象之一,请使用高级序列化库,如 dill。至于为什么pickle 不能,我认为最初它源于GIL 的实现和frame 对象呈现一些不可序列化的对象,因此没有驱动以序列化语言中的所有内容。一直有人谈论源于所有 python 对象的序列化的安全问题,但我认为这是一个红鲱鱼。没有完整的语言序列化限制了在并行计算中操作的能力,所以希望pickle 将向dill 学习如何序列化更多对象。

【讨论】:

  • 您没有为带有 dill 库的 tf 张量提供序列化证明。
  • @denfromufa:这不是 OP 所要求的。在您看来,除了 OP 在问题中所做的事情之外,我还应该展示什么?
  • 我现在明白了,很抱歉造成混乱!
【解决方案2】:

我发现我无法重现eqzx's 脚本的输出,并且dillpickle 的序列化都失败了。

虽然这个问题已经有好几年了,但我认为问题不在于 pickle,而是 tensorflow 1.x 中的张量没有立即评估这一事实。相反,当他们的图表被执行时,他们会被评估。 (在 tensorflow 2.0 中,Eager Execution 默认启用,因此您实际上不必处理这种范例)。

使用tf.enable_eager_execution() 或评估tf.Session() 上下文中的张量

以下脚本在使用 Pickle 或 Dill 时不会引发错误:

import tensorflow as tf
tf.enable_eager_execution()
import pickle 
# import dill

n = tf.zeros((1,1))
pickle.dumps(n)
# dill.dumps(n)

print('Success')

使用 Session.run() 的相同脚本不会引发错误:

import tensorflow as tf
import pickle
# import dill

with tf.Session() as sess:
    n = sess.run(tf.zeros((1,1)))
pickle.dumps(n)
# dill.dumps(n)

print('Success')

【讨论】:

  • 如果您查看回溯,很明显Lock 对象没有酸洗。请注意,当您说函数没有立即评估时,这意味着它们被放在执行堆栈上,这意味着我的回答中提到了与 frame 对象的连接。自 OP 发布以来,dillTensor 对象都发生了显着变化。
  • 嗨@MikeMcKerns,虽然我并不完全熟悉tensorflow 的内部工作原理,也不熟悉它如何使用frame 对象,但我是根据tf.Tensor 的文档回答的。构建上下文中的 tf.Tensor 实际上并不包含张量的值,而是处理张量流操作的输出。由于它不是 Python 对象,因此我认为除非对其进行评估,否则将其序列化是没有意义的。
  • 这可能是真的......构成python函数的对象在第一次评估函数之前和之后是不同的。使用惰性求值,python 函数的骨架在构建时就已组合,但直到第一次调用时才处理它的内容。在此之前,函数的内脏被放入执行堆栈(本质上是在frame),以便在调用时检索。另外,请注意,基本上python中的所有东西都是一个对象——一个列表、一个文件句柄......基本上任何有type的东西(即派生自python类)。
  • @MikeMcKerns 我希望您不介意我提出其他问题,因为您似乎非常精通这个主题。在那种情况下,tensorflow ops 在调用时调用 tensorflow C++ api 无关紧要吗?事实上frame 似乎是一个 C++ 结构体。
  • Python 对象通常是包裹在 C 类型对象周围的瘦类——除非您直接调用 ctypes 之一(如果我没记错的话)。所以,我得看看如何调用tensorflow C-type api。
猜你喜欢
  • 2019-03-25
  • 1970-01-01
  • 2017-12-01
  • 2017-11-05
  • 2018-07-20
  • 2020-11-09
  • 2019-08-02
  • 1970-01-01
  • 2018-12-07
相关资源
最近更新 更多