Tuesday, 1 December 2015

XGBoost, python и AttributeError: 'NoneType' object has no attribute 'XGDMatrixFree'

XGBoost - одно из популярнейших средств для data mining в последние полгода-год.
Это нативная библиотека + врапперы для всяких python, R, и даже Java!


В случае python, причем - "Иногда" с ним бывают проблемы, как то:

[2999]  cv-test-rmspe:0.171434+0.067778 cv-train-rmspe:0.038854+0.000129                                                                                                                                           
Exception ignored in: <bound method DMatrix.__del__ of <xgboost.DMatrix object at 0x7f0aedac27f0>>                                                                                                                 
Traceback (most recent call last):                                                                                                                                                                                 
  File "/usr/local/lib/python3.4/dist-packages/xgboost-0.40-py3.4.egg/xgboost.py", line 188, in __del__                                                                                                            
AttributeError: 'NoneType' object has no attribute 'XGDMatrixFree'  


Причем вроде бы все в порядке, и - ошибка "плавающая". То есть иногда, на некоторых данных и в некоторых случаях - падает, а иногда - нет. Почитал я, как народ плачет, и - решил разобраться, как же так. 

Рассказываю! )

Ошибка возникает, если в python есть вызов exit() / sys.exit()

Итак. xgboost - штука многопоточная, написанная на openMP
Внутри все очень красиво.

#pragma omp parallel for shared(a, b, c) private(i)
   for (i = 0; i < 100500; i++)
     c[i] = a[i] + b[i];

Красивые аннотации и все такое. Реализация многопоточности от разработчика скрыта. Вопросы синхронизации - вопрос тот еще. Данные в общей памяти, все красиво и удобно.

Как работает при этом Python exit. Он кидает SystemExit. Ну а дальше понятно - xgboost не закончил, а враппер уже получил exception и - бабах!

Варианты лечения: 

1) Не лечить. Я серьезно.
2) Поставить time.sleep в python
3) Не использовать exit! 

Вообще, конечно, забавно.