Как сохранить собственноручно написанную модель XGBoost?

Нужно написать класс XGBoost и сохранить обученную модель в файл:

class XGBoost():
    

    def __init__(self, n_estimators=100, learning_rate=0.2, max_depth=3, random_state=17, n_samples = 15, min_size = 5):
            
        self.n_estimators = n_estimators
        self.max_depth = max_depth
        self.learning_rate = learning_rate
        self.initialization = lambda y: np.mean(y) * np.ones([y.shape[0]])
        self.min_size = min_size
        self.loss_by_iter = []
        self.trees_ = []
        self.loss_by_iter_test = []
        self.n_samples = n_samples

        self.add_to_max_depth = 1
        self.init_mse_board = 1.5
    
    def fit(self, X, y):
        self.X = X
        self.y = y
        b = self.initialization(y)
        
        prediction = b.copy()
        
        for t in tqdm_notebook(range(self.n_estimators)):
                        
            if t == 0:
                resid = y
            else:
                resid = (y - prediction)
                if (mse(temp_resid,resid) < self.init_mse_board):
                    self.init_mse_board /= 1.5
                    self.add_to_max_depth += 1
                    self.learning_rate /= 1.1
            
            tree = Bagging(max_depth=self.max_depth+self.add_to_max_depth,
                                         min_size = self.min_size)
            resid = -resid
                
            tree.fit(X, resid)
            b = tree.predict(X).reshape([X.shape[0]])
            self.trees_.append(tree)
            prediction += self.learning_rate * b
            temp_resid = resid

        return self
    
    def predict(self, X):
        
        pred = np.ones([X.shape[0]]) * np.mean(self.y)
        for t in range(self.n_estimators):
            pred += self.learning_rate * self.trees_[t].predict(X).reshape([X.shape[0]])    
        return (pred>0.5).astype('int')

    def predict_proba(self, X):
        
        pred = np.ones([X.shape[0]]) * np.mean(self.y)
        for t in range(self.n_estimators):
            pred += self.learning_rate * self.trees_[t].predict(X).reshape([X.shape[0]])  
        pred = [[1-i, i] for i in pred] 
        return np.array(pred)
    
    def __getstate__(self) -> dict:

        state = {}
        state['y'] = self.y
        state['n_estimators'] = self.n_estimators
        state['learning_rate'] = self.learning_rate
        state['max_depth'] = self.max_depth
        state['random_state'] = 17
        state['n_samples'] = self.n_samples
        state['min_size'] = self.min_size
        state['trees_'] = self.trees_
        state['initialization'] = self.initialization
        state['loss_by_iter'] = self.loss_by_iter
        state['loss_by_iter_test'] = self.loss_by_iter_test

        return state

    def __setstate__(self, state: dict):

        self.y = state['y'] 
        self.n_estimators = state['n_estimators']
        self.learning_rate = state['learning_rate']
        self.max_depth = state['max_depth'] 
        self.random_state = state['random_state'] 
        self.n_samples = state['n_samples']
        self.min_size = state['min_size']
        self.trees_ = state['trees_']
        self.initialization = state['initialization']
        self.loss_by_iter = state['loss_by_iter']
        self.loss_by_iter_test = state['loss_by_iter_test']

Обучаю и сохраняю модель через pickle:


dataset = numpy.loadtxt('pima-indians-diabetes.csv', delimiter=",")
X = dataset[:,0:8]
Y = dataset[:,8]

seed = 7
test_size = 0.33
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)
model = XGBoost()
model.fit(X_train, y_train)

with open('model.pkl','wb') as f:
    pickle.dump(model,f)

Выдает ошибку:

AttributeError: Can't pickle local object 'XGBoost.__init__.<locals>.<lambda>'

В ЧЕМ проблема может кто объяснить?


Ответы (2 шт):

Автор решения: CrazyElf
AttributeError: Can't pickle local object 'XGBoost.__init__.<locals>.<lambda>'

Ну, судя по всему, ругается на эту строчку в __init__:

self.initialization = lambda y: np.mean(y) * np.ones([y.shape[0]])

Опишите обычную функцию в классе, вычисляющую это всё, вам ведь не принципиальна lambda здесь? Можете даже и с lambda, но отдельно от инициализации класса чтобы это было. pickle не понимает, как потом инициализировать объект, у которого в __init__ есть lambda.

→ Ссылка
Автор решения: Max Pyankov

Нашел еще решение: Вместо модуля pickle можно использовать dill, он не ругается на лямбда функции

    with open('model.pkl','wb') as f:
        dill.dump(model,f)
→ Ссылка