【问题标题】:Pickle exception for cv2.Boost when using multiprocessing使用多处理时 cv2.Boost 的 Pickle 异常
【发布时间】:2018-10-24 13:00:10
【问题描述】:

我正在开发名为“Faciel Actions Units Detection”的项目 我正在使用 python2.7 和 opencv 2.4

错误:

pickle.PicklingError: Can't pickle <type 'cv2.Boost'>: it's not the same object as cv2.Boost

部分回溯,转录自a screenshot

Loading classifier for action unit 27
Traceback (most recent call last):
  File "C:\Python27\audetect-master\audetect-interactive.py", line 59, in <module>
    main()
  File "C:\Python27\audetect-master\audetect-interactive.py", line 18, in main
    active_aus = detector.detect()
  File "C:\Python27\audetect-master\detect.py", line 67, in detect
    initial_points = self.ffdetector.locate_features(first)
  File "C:\Python27\audetect-master\detect.py", line 183, in locate_features
    thread.start()
  File "C:\Python27\lib\multiprocessing\process.py", line 130, in start
    self._popen = Popen(self)
  File "C:\Python27\lib\multiprocessing\forking.py", line 227, in __init__
    dump(process_obj, to_child, HIGHEST_PROTOCOL)
  File "C:\Python27\lib\multiprocessing\forking.py", line 199, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Python27\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "C:\Python27\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 425, in save_reduce
    save(state)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 655, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 687, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\multiprocessing\forking.py", line 67, in dispatcher
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 401, in save_reduce
    save(args)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 554, in save_tuple
    save(element)

【问题讨论】:

  • 请包含您尝试运行的 Python 代码的基本概念。
  • 非常感谢您的关注这是函数 def detect(self): """ 返回活动 AU 的元组 """ first = self.sequence[0] last = self.sequence[ -1] initial_points = self.ffdetector.locate_features(first) final_points = self.ffdetector.locate_features(last) if not initial_points or not final_points: sys.stderr.write("Error: could not locate face in provided sequence") sys. stderr.write("\n") return [] aus = self.determine_aus(initial_points, final_points) return aus
  • @ToddPalmer 感谢您关注上述引发错误的函数
  • 请不要使用代码截图和回溯。我们无法复制这些内容,视力障碍者的屏幕阅读器也无法阅读文本。错误信息和代码都是文本,请以文本形式发布。
  • 我注意到回溯截图也不完整

标签: python python-2.7 pickle python-multiprocessing cv2


【解决方案1】:

multiprocessing 模块使用 Pickle 在不同部分之间进行通信,在 programming guidelines 中它解释说,您必须确保在进程之间传递的所有数据都必须与 pickle 兼容:

Picklability:确保代理方法的参数是可picklable。

您正在使用不可提取的数据。

具体来说,问题出在cv2.Boost 类并没有完全说明如何创建更多类的副本。 pickle 存储类和函数的引用,而不是它们的定义,因为这样更有效。这意味着实例只需要存储该实例的数据,而不是所有的类层次结构和方法定义。

为了做到这一点,pickle 获取定义类或函数的模块、对象的名称,以及对类或函数的引用。然后它再次检查它可以使用该名称再次加载相同的类或函数。

cv2.Boost 类的完整性检查失败。您有一个名为 Boost 的类的实例,并且声称来自 cv2 模块,但是当 pickle 然后转到 cv2 模块并查找它找到的该模块的 Boost 属性不同的对象。这意味着您的数据无法解封。

有一些方法可以纠正这个问题;您需要使用copyreg.pickle() functionpickle 模块使用不同的函数再次加载相同的数据;如果cv2.Boost 类存在这样的注册,那么pickle 将不会进行上述检查:

import copyreg
import cv2

def _pickle_boost(boost):
    return cv2.Boost, (
        boost.trainData,
        boost.tflag,
        boost.responses, 
        boost.varIdx,
        boost.sampleIdx,
        boost.varType,
        boost.missingDataMask,
        boost.paramsd,
    )

copyreg.pickle(cv2.Boost().__class__, _pickle_boost)

警告:我并没有实际测试上述是否可行,因为我没有在本地安装 2.4.x 版本的 cv2;我只是参考cv2.Boost() documentation 来猜测这样一个类将具有哪些属性。你可能需要调整它。这个想法是,对于 cv2.Boost().__class__ 类型,调用 _pickle_boost() 函数,返回一个可调用 (cv2.Boost) 以创建一个新实例,以及您要传递给该可调用的参数。

如果上述任何一个值本身是更多cv2类型,表现出同样的问题,那么你需要注册更多的函数。

【讨论】:

  • 您是否有机会添加一个最小的完整工作示例?试图让我的头脑围绕这个。试图了解如何缓存 cv2.ORB() 对象(在 Flask 中)但失败得很惨。感谢所有帮助
  • @jtlz2:对于cv2.Boost 类型,它已经是一个MCVE。正如我在回答中已经说明的那样,我无法使用特定类型对此进行测试,但cv2.ORB() 的一般原则应该相同。创建一个函数,该函数返回构造函数和给定实例的值元组,然后为cv2.ORB() 实例的实际类对象注册该函数。
  • @jtlz2: 当pickle遇到另一个cv2.ORB()实例时,它会在注册表中找到_pickle_orb()函数,用那个实例作为参数调用它,然后返回要存储在 pickle 数据流中的 (cv2.ORB, (....)) 元组。 unpickling 时,pickle 找到 cv2.ORB 引用,并调用 cv2.ORB(....) 以创建具有相同值的新实例。
  • @jtlz2:Flask-Caching 不需要学习任何东西。它只使用pickle,而pickle 使用copyreg 注册表。
  • @jtlz2:然后调用 getter。目标是生成您需要传递给 cv2.ORB() 构造函数以重新创建值的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多