Интегрировать Keras в SKLearn Pipeline? - PullRequest
1 голос
/ 02 мая 2019

У меня есть конвейер sklearn, выполняющий разработку функций для разнородных типов данных (булевы, категориальные, числовые, текстовые), и я хотел использовать нейронную сеть в качестве алгоритма обучения, соответствующего модели. Я сталкиваюсь с некоторыми проблемами с формой входных данных.

Мне интересно, возможно ли то, что я пытаюсь сделать, или мне стоит попробовать другой подход?

Я пробовал несколько разных способов, но получаю следующие ошибки:

  1. Error when checking input: expected dense_22_input to have shape (11,) but got array with shape (30513,) => У меня 11 входных функций ... поэтому я попытался преобразовать мои X и y в массивы и теперь получаю эту ошибку

  2. ValueError: Specifying the columns using strings is only supported for pandas DataFrames => Я думаю, это из-за ColumnTransformer(), где я указываю имена столбцов

print(X_train_OS.shape)
print(y_train_OS.shape)

(22354, 11)
(22354,)
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils import to_categorical # OHE

X_train_predictors = df_train_OS.drop("label", axis=1)
X_train_predictors = X_train_predictors.values
y_train_target = to_categorical(df_train_OS["label"])

y_test_predictors = test_set.drop("label", axis=1)
y_test_predictors = y_test_predictors.values
y_test_target = to_categorical(test_set["label"])

print(X_train_predictors.shape)
print(y_train_target.shape)

(22354, 11)
(22354, 2)
def keras_classifier_wrapper():
    clf = Sequential()
    clf.add(Dense(32, input_dim=11, activation='relu'))
    clf.add(Dense(2, activation='softmax'))
    clf.compile(loss='categorical_crossentropy', optimizer='adam', metrics=["accuracy"])
    return clf

TOKENS_ALPHANUMERIC_HYPHEN = "[A-Za-z0-9\-]+(?=\\s+)"

boolTransformer = Pipeline(steps=[
    ('bool', PandasDataFrameSelector(BOOL_FEATURES))])

catTransformer = Pipeline(steps=[
    ('cat_imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('cat_ohe', OneHotEncoder(handle_unknown='ignore'))])

numTransformer = Pipeline(steps=[
    ('num_imputer', SimpleImputer(strategy='constant', fill_value=0)),
    ('num_scaler', StandardScaler())])

textTransformer_0 = Pipeline(steps=[
    ('text_bow', CountVectorizer(lowercase=True,\
                                 token_pattern=TOKENS_ALPHANUMERIC_HYPHEN,\
                                 stop_words=stopwords))])

textTransformer_1 = Pipeline(steps=[
    ('text_bow', CountVectorizer(lowercase=True,\
                                 token_pattern=TOKENS_ALPHANUMERIC_HYPHEN,\
                                 stop_words=stopwords))])

FE = ColumnTransformer(
    transformers=[
        ('bool', boolTransformer, BOOL_FEATURES),
        ('cat', catTransformer, CAT_FEATURES),
        ('num', numTransformer, NUM_FEATURES),
        ('text0', textTransformer_0, TEXT_FEATURES[0]),
        ('text1', textTransformer_1, TEXT_FEATURES[1])])

clf = KerasClassifier(keras_classifier_wrapper, epochs=100, batch_size=500, verbose=0)

PL = Pipeline(steps=[('feature_engineer', FE),
                     ('keras_clf', clf)])

PL.fit(X_train_predictors, y_train_target)
#PL.fit(X_train_OS, y_train_OS)

Мне кажется, я понимаю проблему здесь, но не знаю, как ее решить. Если невозможно интегрировать sklearn ColumnTransformer + Pipeline в модель Keras, есть ли у Keras хороший способ для работы с фиксированными типами данных для разработки функций? Спасибо!

Ответы [ 2 ]

1 голос
/ 03 мая 2019

Я думаю, что использование Sklearn Pipelines и Keras sklearnWrappers является стандартным способом решения вашей проблемы, а ColumnDataTransformer позволяет вам управлять каждой функцией по-разному (будь то булево, числовое или категориальное),

Для отладки вашего кода я бы предложил провести модульное тестирование на каждом из этапов вашего конвейера, особенно textTransformer_0 и textTransformer_1

Например,

textTransformer_0.fit_transform(X_train_predictors).shape # shape[1]
textTransformer_1.fit_transform(X_train_predictors).shape # shape[1]

И так один за одним.горячий кодер, чтобы понять, каким будет ваше окончательное измерение элемента.

Поскольку стандарты для Sklearn Pipelines предназначены для 2D np.ndarray, то CountVectorizer создаст группу столбцов, в зависимости от данных,И это значение должно быть введено как input_dim в keras.Dense слоях

1 голос
/ 03 мая 2019

Похоже, что вы передаете свои 11 столбцов исходных данных через различные преобразователи столбцов, и число измерений увеличивается до 30 513 (после подсчета векторизации вашего текста, одного горячего кодирования и т. Д.).Ваша архитектура нейронной сети настроена на прием только 11 входных функций, но передается вашим (теперь преобразованным) 30 513 функциям, что объясняет ошибка 1.

Поэтому вам необходимо изменить input_dim вашегонейронная сеть, соответствующая числу объектов, создаваемых в конвейере извлечения объектов.

Одна вещь, которую вы можете сделать, это добавить промежуточный шаг между ними с помощью чего-то вроде SelectKBest и установить для него что-то вроде20000, чтобы вы точно знали, сколько функций в конечном итоге будет передано классификатору.

Это хорошее руководство и блок-схема на веб-сайте машинного обучения Google - ссылка - посмотрите блок-схему - здесь вы можете увидеть, что у них есть шаг «Выбрать топ k функций» вконвейер перед обучением модели.

Итак, попробуйте обновить следующие части вашего кода:

def keras_classifier_wrapper():
    clf = Sequential()
    clf.add(Dense(32, input_dim=20000, activation='relu'))
    clf.add(Dense(2, activation='softmax'))
    clf.compile(loss='categorical_crossentropy', optimizer='adam', metrics=["accuracy"])
    return clf

и

from sklearn.feature_selection import SelectKBest
select_best_features = SelectKBest(k=20000)

PL = Pipeline(steps=[('feature_engineer', FE),
                     ('select_k_best', select_best_features),
                     ('keras_clf', clf)])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...