0

Можно ли использовать Keras's scikit-learn API вместе с fit_generator()? Или использовать другой способ получения партий для обучения? Я использую разреженные матрицы SciPy, которые необходимо преобразовать в массивы NumPy перед входом в Keras, но я не могу их преобразовать одновременно из-за большого потребления памяти. Вот моя функция, чтобы получить партии:keras/scikit-learn: using fit_generator() с перекрестной проверкой

def batch_generator(X, y, batch_size): 
    n_splits = len(X) // (batch_size - 1) 
    X = np.array_split(X, n_splits) 
    y = np.array_split(y, n_splits) 

    while True: 
     for i in range(len(X)): 
      X_batch = [] 
      y_batch = [] 
      for ii in range(len(X[i])): 
       X_batch.append(X[i][ii].toarray().astype(np.int8)) # conversion sparse matrix -> np.array 
       y_batch.append(y[i][ii]) 
      yield (np.array(X_batch), np.array(y_batch)) 

и пример кода с перекрестной проверки:

from sklearn.model_selection import StratifiedKFold, GridSearchCV 
from sklearn import datasets 

from keras.models import Sequential 
from keras.layers import Activation, Dense 
from keras.wrappers.scikit_learn import KerasClassifier 

import numpy as np 


def build_model(n_hidden=32): 
    model = Sequential([ 
     Dense(n_hidden, input_dim=4), 
     Activation("relu"), 
     Dense(n_hidden), 
     Activation("relu"), 
     Dense(3), 
     Activation("sigmoid") 
    ]) 
    model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) 
    return model 


iris = datasets.load_iris() 
X = iris["data"] 
y = iris["target"].flatten() 

param_grid = { 
    "n_hidden": np.array([4, 8, 16]), 
    "nb_epoch": np.array(range(50, 61, 5)) 
} 

model = KerasClassifier(build_fn=build_model, verbose=0) 
skf = StratifiedKFold(n_splits=5).split(X, y) # this yields (train_indices, test_indices) 

grid = GridSearchCV(model, param_grid, cv=skf, verbose=2, n_jobs=4) 
grid.fit(X, y) 

print(grid.best_score_) 
print(grid.cv_results_["params"][grid.best_index_]) 

Чтобы объяснить это больше, он использует все возможные комбинации гипер-параметров в param_grid для построения модели , Каждая модель затем обучается и тестируется по одному на расщеплениях данных поездов (сгибов), предоставленных StratifiedKFold. Тогда итоговая оценка для данной модели - средний балл от всех складок.

Так как можно каким-либо образом вставить некоторый препроцессорный подшаблон в код выше, чтобы преобразовать данные (разреженные матрицы) до фактического соответствия?

Я знаю, что могу написать свой собственный генератор перекрестной проверки, но он должен давать индексы, а не реальные данные!

ответ

1

На самом деле вы можете использовать разреженную матрицу в качестве входных данных для Keras с генератором. Вот моя версия, которая работала над предыдущим проектом:

> class KerasClassifier(KerasClassifier): 
>  """ adds sparse matrix handling using batch generator 
>  """ 
>  
>  def fit(self, x, y, **kwargs): 
>   """ adds sparse matrix handling """ 
>   if not issparse(x): 
>    return super().fit(x, y, **kwargs) 
>   
>   ############ adapted from KerasClassifier.fit ###################### 
>   if self.build_fn is None: 
>    self.model = self.__call__(**self.filter_sk_params(self.__call__)) 
>   elif not isinstance(self.build_fn, types.FunctionType): 
>    self.model = self.build_fn(
>     **self.filter_sk_params(self.build_fn.__call__)) 
>   else: 
>    self.model = self.build_fn(**self.filter_sk_params(self.build_fn)) 
> 
>   loss_name = self.model.loss 
>   if hasattr(loss_name, '__name__'): 
>    loss_name = loss_name.__name__ 
>   if loss_name == 'categorical_crossentropy' and len(y.shape) != 2: 
>    y = to_categorical(y) 
>   ### fit => fit_generator 
>   fit_args = copy.deepcopy(self.filter_sk_params(Sequential.fit_generator)) 
>   fit_args.update(kwargs) 
>   ############################################################ 
>   self.model.fit_generator(
>      self.get_batch(x, y, self.sk_params["batch_size"]), 
>           samples_per_epoch=x.shape[0], 
>           **fit_args)      
>   return self        
> 
>  def get_batch(self, x, y=None, batch_size=32): 
>   """ batch generator to enable sparse input """ 
>   index = np.arange(x.shape[0]) 
>   start = 0 
>   while True: 
>    if start == 0 and y is not None: 
>     np.random.shuffle(index) 
>    batch = index[start:start+batch_size] 
>    if y is not None: 
>     yield x[batch].toarray(), y[batch] 
>    else: 
>     yield x[batch].toarray() 
>    start += batch_size 
>    if start >= x.shape[0]: 
>     start = 0 
> 
>  def predict_proba(self, x): 
>   """ adds sparse matrix handling """ 
>   if not issparse(x): 
>    return super().predict_proba(x) 
>    
>   preds = self.model.predict_generator(
>      self.get_batch(x, None, self.sk_params["batch_size"]), 
>            val_samples=x.shape[0]) 
>   return preds 
+0

Это выглядит хорошо - изменение исходного кода Keras также пришло мне в голову, но я хотел этого избежать. Спасибо, я попробую это :) – jirinovo

+0

Так что я немного изменил свой код, и он работает нормально. Есть ли у вас какое-то представление о том, как реализовать обратный вызов Keras [EarlyStopping] (https://keras.io/callbacks/#earlystopping) здесь? – jirinovo

+1

Конечно. Не помещается в комментарии, но вот мои классификаторы для Keras и XGB с ранней остановкой. Работал в прошлом, но отметил, что не прошел всесторонней проверки! https://github.com/simonm3/analysis/blob/master/analysis/classifiers.py – simon

Смежные вопросы