为什么酸洗张量流张量会失败?

Why does pickling a tensorflow Tensor fail?

这是一个片段,它可以用 dill 成功序列化,但用 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

为什么dill可以序列化这些对象,而pickle却不能?简单的答案是 pickle 无法序列化 python 中的大多数对象,包括 thread.lock 对象。如果要序列化这些对象之一,请使用像 dill 这样的高级序列化库。至于为什么 pickle 不能,我认为它最初源于 GIL 的实现和 frame 对象渲染一些对象不可序列化,因此没有驱动来序列化语言中的所有内容。一直有关于所有 python 对象序列化引起的安全问题的讨论,但我认为这是转移注意力的问题。没有完整的语言序列化限制了在并行计算中运行的能力,因此希望 pickle 将学习 dill 如何序列化更多对象。

我发现我无法重现 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')