Могу ли я отправить обратный вызов KerasClassifier?
Я хочу, чтобы классификатор работал быстрее и останавливался раньше, если терпение достигает установленного мной числа. В следующем коде он выполняет 10 итераций подгонки модели.
import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.constraints import maxnorm
from keras.optimizers import SGD
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load dataset
dataframe = pandas.read_csv("sonar.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)
calls=[EarlyStopping(monitor='acc', patience=10), ModelCheckpoint('C:/Users/Nick/Data Science/model', monitor='acc', save_best_only=True, mode='auto', period=1)]
def create_baseline():
# create model
model = Sequential()
model.add(Dropout(0.2, input_shape=(33,)))
model.add(Dense(33, init='normal', activation='relu', W_constraint=maxnorm(3)))
model.add(Dense(16, init='normal', activation='relu', W_constraint=maxnorm(3)))
model.add(Dense(122, init='normal', activation='softmax'))
# Compile model
sgd = SGD(lr=0.1, momentum=0.8, decay=0.0, nesterov=False)
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
return model
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
здесь ошибка-
RuntimeError: Cannot clone object <keras.wrappers.scikit_learn.KerasClassifier object at 0x000000001D691438>, as the constructor does not seem to set parameter callbacks
Я изменил cross_val_score в следующем-
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'callbacks':calls})
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
и теперь я получаю эту ошибку-
ValueError: need more than 1 value to unpack
этот код взят отсюда. Код, безусловно, самый точный, который я использовал до сих пор. Проблема что нет model.fit()
в любом месте в коде. Это также занимает вечность, чтобы соответствовать. The fit()
операция происходит в results = cross_val_score(...)
и нет параметров, чтобы бросить обратный вызов там.
как мне это сделать? Кроме того, как запустить модель, обученную тестовому набору?
мне нужно сохранить обученную модель для последующего использования...
3 ответов
чтение отсюда, который является исходным кодом KerasClassifier, вы можете передать ему аргументы fit, и они должны быть использованы. У меня нет вашего набора данных, поэтому я не могу его проверить, но вы можете сказать мне, работает ли это, а если нет, я попытаюсь адаптировать решение. Измените эту строку :
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=[...your_callbacks...])))
небольшое объяснение того, что происходит : KerasClassifier принимает все возможные аргументы для fit
, predict
, score
и использует их соответственно при каждой вызывается метод. Они создали функцию, которая фильтрует аргументы, которые должны идти к каждой из вышеперечисленных функций, которые могут быть вызваны в конвейере.
Я думаю, есть несколько fit
и predict
звонки внутри StratifiedKFold
шаг, чтобы тренироваться на разных шпагатах каждый раз.
причина, по которой требуется вечность, чтобы соответствовать, и он подходит 10 раз, потому что один подходит делает 300 эпох, как вы просили. Поэтому KFold повторяет этот шаг за разных складок :
- звонки
fit
со всеми параметрами, заданнымиKerasClassifier
(300 эпох и размер партии = 16). Это обучение на 9/10 ваших данных и использование 1/10 в качестве проверки.
EDIT:
Ok, поэтому я потратил время, чтобы загрузить набор данных и попробовать ваш код... Прежде всего, вам нужно исправить "несколько" вещей в вашей сети:
-
ваш вход имеет 60 функций. Вы четко показываете это в своих данных prep:
X = dataset[:,:60].astype(float)
так зачем вам это:
model.add(Dropout(0.2, input_shape=(33,)))
пожалуйста, измените на :
model.add(Dropout(0.2, input_shape=(60,)))
-
о ваших целях / ярлыках. Вы изменили цель с исходного кода (
binary_crossentropy
) кcategorical_crossentropy
. Но вы не изменили свой массив Y. Поэтому либо сделайте это при подготовке данных:from keras.utils.np_utils import to_categorical encoded_Y = to_categorical(encoder.transform(Y))
или измените свою цель на
binary_crossentropy
. -
теперь размер выхода сети : 122 на последний плотный слой? ваш набор данных, очевидно, имеет 2 категории, так почему вы пытаетесь вывести 122 класса? он не будет соответствовать цели. Пожалуйста, измените свой последний слой на:
model.add(Dense(2, init='normal', activation='softmax'))
если вы используете
categorical_crossentropy
илиmodel.add(Dense(1, init='normal', activation='sigmoid'))
если вы вернетесь в
binary_crossentropy
.
Итак, теперь, что ваша сеть будет компилироваться, я мог начать troubleshout.
вот ваше решение
так что теперь я мог бы получить реальное сообщение об ошибке. Оказывается, когда кормишь fit_params=whatever
на cross_val_score()
функция, вы подаете эти параметры в трубопровод. Чтобы узнать, в какую часть конвейера вы хотите отправить эти параметры, вы должны указать его следующим образом:
fit_params={'mlp__callbacks':calls}
ваша ошибка заключалась в том, что процесс не мог распаковать 'callbacks'.split('__', 1)
в 2 значения. На самом деле он искал название шага трубопровода, чтобы применить это.
он должен работать сейчас :)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'mlp__callbacks':calls})
но, вы должны знать, что здесь происходит... перекрестная проверка фактически вызывает create_baseline()
функция для воссоздания модели с нуля 10 раз тренирует ее 10 раз на разных частях набора данных. Так что это не делает эпохи, как вы говорили, это делает 300 эпох 10 раз.
Что также происходит в результате использования этого инструмента: поскольку модели всегда отличаются, это означает fit()
метод приложен 10 раз на различных моделях, поэтому обратные вызовы также применяются 10 раз и файлы, сохраненные ModelCheckpoint()
получить переопределен, и вы окажетесь только с лучшей моделью последнего запуска.
это присуще инструментам, которые вы используете, я не вижу никакого способа обойти это. Это происходит как следствие использования различных общих инструментов, которые не особенно считались используемыми вместе со всеми возможными конфигурациями.
попробуй:
estimators.append(('mlp',
KerasClassifier(build_fn=create_model2,
nb_epoch=300,
batch_size=16,
verbose=0,
callbacks=[list_of_callbacks])))
здесь list_of_callbacks
список вызовов, которые вы хотите применить. Вы можете найти детали здесь. Там упоминается, что параметры подаются в KerasClassifier
могут быть законными параметрами установки.
также стоит упомянуть, что если вы используете несколько запусков с графическими процессорами, может возникнуть проблема из-за нескольких сообщений об утечках памяти, особенно при использовании theano. Я также заметил, что запуск нескольких fits следовательно может показать результаты которые кажутся не независимыми при использовании sklearn
API-интерфейс.
Edit:
попробуйте также:
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params = {'mlp__callbacks': calls})
вместо того, чтобы помещать список обратных вызовов в экземпляр оболочки.
вот что я сделал
results = cross_val_score(estimator, X, Y, cv=kfold,
fit_params = {'callbacks': [checkpointer,plateau]})
и до сих пор работал