【问题标题】:scikit - random forest regressor - AttributeError: 'Thread' object has no attribute '_children'scikit - 随机森林回归器 - AttributeError:'Thread'对象没有属性'_children'
【发布时间】:2015-12-28 21:42:49
【问题描述】:

在为随机森林回归器设置n_jobs 参数> 1 时出现以下错误。如果我设置n_jobs=1,一切正常。

AttributeError: 'Thread' object has no attribute '_children'

我正在烧瓶服务中运行此代码。有趣的是,在烧瓶服务之外运行时不会发生这种情况。我只在一个新安装的 Ubuntu 机器上复制了这个。在我的 Mac 上它工作得很好。

这是一个讨论过这个问题的线程,但似乎没有解决任何问题: 'Thread' object has no attribute '_children' - django + scikit-learn

对此有什么想法吗?

这是我的测试代码:

@test.route('/testfun') def testfun(): 从 sklearn.ensemble 导入 RandomForestRegressor 将 numpy 导入为 np train_data = np.array([[1,2,3], [2,1,3]]) target_data = np.array([1,1]) 模型 = RandomForestRegressor(n_jobs=2) model.fit(train_data, target_data) 返回“是”

堆栈跟踪:

回溯(最近一次通话最后): __call__ 中的文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1836 行 return self.wsgi_app(environ, start_response) wsgi_app 中的文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1820 行 响应 = self.make_response(self.handle_exception(e)) 文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1403 行,在 handle_exception 中 reraise(exc_type, exc_value, tb) wsgi_app 中的文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1817 行 响应 = self.full_dispatch_request() 文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1477 行,在 full_dispatch_request rv = self.handle_user_exception(e) 文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1381 行,在 handle_user_exception reraise(exc_type, exc_value, tb) 文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1475 行,在 full_dispatch_request rv = self.dispatch_request() 文件“/usr/local/lib/python2.7/dist-packages/flask/app.py”,第 1461 行,在 dispatch_request 中 return self.view_functions[rule.endpoint](**req.view_args) 文件“/home/vagrant/flask.global-relevance-engine/global_relevance_engine/routes/test.py”,第 47 行,在 testfun model.fit(train_data, target_data) 文件“/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/forest.py”,第 273 行,适合 for i, t in enumerate(trees)) __call__ 中的文件“/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py”,第 574 行 self._pool = ThreadPool(n_jobs) __init__ 中的文件“/usr/lib/python2.7/multiprocessing/pool.py”,第 685 行 Pool.__init__(self, processes, initializer, initargs) __init__ 中的文件“/usr/lib/python2.7/multiprocessing/pool.py”,第 136 行 self._repopulate_pool() _repopulate_pool 中的文件“/usr/lib/python2.7/multiprocessing/pool.py”,第 199 行 w.start() 文件“/usr/lib/python2.7/multiprocessing/dummy/__init__.py”,第 73 行,开始 self._parent._children[self] = 无

【问题讨论】:

  • 我没有解决方案,但我只会写我注意到的东西。看起来真的很奇怪——错误之前的那一行专门测试了_children:if hasattr(self._parent, '_children'): self._parent._children[self] = None。当您说它在烧瓶之外工作时,是否具有完全相同的环境(解释器、库、操作系统、机器等)?我问是因为在我的系统中,第 73 行是条件,但在您的系统中,它是分配。我认为您的烧瓶环境使用的是旧版本的 python,其中 this bug 不固定。

标签: python flask scikit-learn


【解决方案1】:

问题

这可能是由于在 python 2.7.5 和 3.3.2 之前存在的 multiprocessing.dummy(参见 herehere)中的一个错误。

解决方案 A - 升级 Python

查看 cmets 以确认更新的版本适用于 OP。

解决方案 B - 修改 dummy

如果您无法升级但可以访问.../py/Lib/multiprocessing/dummy/__init__.py,请编辑DummyProcess 类中的start 方法,如下所示(应为~第73 行):

if hasattr(self._parent, '_children'):  # add this line
    self._parent._children[self] = None  # indent this existing line

解决方案 C - 猴子补丁

DummyProcess 是这个 bug 所在的位置。让我们看看它在您导入的代码中存在的位置,以确保我们在正确的位置对其进行修补。

  • RandomForestRegressor
  • 继承:ForestRegressor
  • 继承:BaseForest
  • 创建于:sklearn.ensemble.forest
  • 其中导入:平行来自 sklearn.externals.joblib
  • 从 multiprocessing.pool 导入 ThreadPool
  • 从 multiprocessing.dummy 导入和存储 Process
  • 已分配给:DummyProcess 也在 multiprocessing.dummy 中

DummyProcess 在该链中的存在保证它在导入RandomForestRegressor 之后已经被导入。 此外,我认为我们可以在创建任何实例之前访问 DummyProcess 类。 因此,我们可以对类进行一次修补,而无需寻找实例来修补。

# Let's make it available in our namespace:
from sklearn.ensemble import RandomForestRegressor
from multiprocessing import dummy as __mp_dummy

# Now we can define a replacement and patch DummyProcess:
def __DummyProcess_start_patch(self):  # pulled from an updated version of Python
    assert self._parent is __mp_dummy.current_process()  # modified to avoid further imports
    self._start_called = True
    if hasattr(self._parent, '_children'):
        self._parent._children[self] = None
    __mp_dummy.threading.Thread.start(self)  # modified to avoid further imports
__mp_dummy.DummyProcess.start = __DummyProcess_start_patch

除非我错过了什么,从现在开始,所有创建的 DummyProcess 实例都将被修补,因此不会发生该错误。

对于更广泛使用 sklearn 的任何人,我认为您可以反过来完成此操作,并使其适用于所有 sklearn,而不是专注于一个模块。 在执行任何 sklearn 导入之前,您需要导入 DummyProcess 并按上述方式对其进行修补。 然后 sklearn 将从一开始就使用已修补的类。


原答案:

当我写评论时,我意识到我可能发现了你的问题 - 我认为你的烧瓶环境使用的是旧版本的 python。

原因是在最新版本的 python 多处理中,您收到该错误的行受条件保护:

if hasattr(self._parent, '_children'):
    self._parent._children[self] = None

看起来this bug 在 python 2.7 期间已修复(我认为从 2.7.5 修复)。也许您的烧瓶是较旧的 2.7 或 2.6?

你能检查一下你的环境吗?如果您无法更新解释器,也许我们可以找到一种方法来猴子修补多处理以防止它崩溃。

【讨论】:

  • 感谢您的信息!我用 2.7.6 尝试了一个新的虚拟机,你是对的,它有效。
  • *在下面添加,因为我无法在上面编辑。我最初的环境使用的是 2.7.3。我对使用的 Python 版本没有太多控制权。但是,我对测试进行了基准测试,使用单线程不会有害。我只需要每天运行一次,并且运行时间
  • @HappyCamper 这是个好消息。我很高兴它有效。赞成和解决方案标记将不胜感激,并将帮助未来的用户走上正确的道路。至于猴子补丁,我将不得不努力,因为我还没有看到一种超级安全的方法来做到这一点。我可能会问另一个关于 SO 的问题以获得它,但我最终会这样做。
  • @HappyCamper 你能告诉我你的导入链可以访问RandomForestRegressor吗?例如。 from sklearn import ensemble 后跟 ... ensemble.RandomForestRegressor 。或者from sklearn.ensemble import RandomForestRegressor
  • 我认为所有内容都正确标记(仍然习惯在这里发帖)。再次感谢您观看这一切!我在上面的代码块中有 import 语句。如果这不正确,请告诉我。从 sklearn.ensemble 导入 RandomForestRegressor
猜你喜欢
  • 2021-01-22
  • 2015-07-03
  • 2019-12-06
  • 2023-03-14
  • 2015-06-04
  • 1970-01-01
  • 2020-03-12
  • 2018-06-24
  • 2016-04-24
相关资源
最近更新 更多