AutoML Pipelines: извлечение меток из входных данных и выборка в Neuraxle или SKLearn Pipelines
Я работаю над проектом, который ищет простую реализацию конвейера Python AutoML. Согласно определению проекта, данные, поступающие в конвейер, находятся в формате сериализованных бизнес-объектов, например (искусственный пример):
property.json:
{
"area": "124",
"swimming_pool": "False",
"rooms" : [
... some information on individual rooms ...
]
}
Цели машинного обучения (например, прогнозирование наличия у свойства плавательного бассейна на основе других атрибутов) хранятся в бизнес-объекте, а не доставляются в отдельном векторе меток, а бизнес-объекты могут содержать наблюдения, которые не должны использоваться для обучения.
Что я ищу
Мне нужен механизм конвейера, который поддерживает начальные (или более поздние) этапы конвейера, которые i) динамически изменяют цели в задаче машинного обучения (например, извлекают из входных данных, пороговые реальные значения) и ii) повторно дискретизируют входные данные (например, повышающая дискретизация, понижающая дискретизация классов, фильтрация наблюдений).
В идеале конвейер должен выглядеть следующим образом (псевдокод):
swimming_pool_pipeline = Pipeline([
("label_extractor", SwimmingPoolExtractor()), # skipped in prediction mode
("sampler", DataSampler()), # skipped in prediction mode
("featurizer", SomeFeaturization()),
("my_model", FitSomeModel())
])
swimming_pool_pipeline.fit(training_data) # not passing in any labels
preds = swimming_pool_pipeline.predict(test_data)
Механизм выполнения конвейера должен выполнять / разрешать следующее:
- Во время обучения модели (
.fit()
)SwimmingPoolExtractor
извлекает целевые метки из входных обучающих данных и передает метки (наряду с независимыми переменными); - В тренировочном режиме
DataSampler()
использует метки цели, извлеченные на предыдущем шаге, для выборки наблюдений (например, может выполнять повышающую дискретизацию меньшинства или фильтровать наблюдения); - В режиме прогнозирования
SwimmingPoolExtractor()
ничего не делает и просто передает входные данные; - В режиме прогнозирования
DataSampler()
ничего не делает и просто передает входные данные;
пример
Например, предположим, что данные выглядят следующим образом:
property.json:
"properties" = [
{ "id_": "1",
"swimming_pool": "False",
...,
},
{ "id_": "2",
"swimming_pool": "True",
...,
},
{ "id_": "3",
# swimming_pool key missing
...,
}
]
Применение SwimmingPoolExtractor()
извлечет что-то вроде:
"labels": [
{"id_": "1", "label": "0"},
{"id_": "2", "label": "1"},
{"id_": "3", "label": "-1"}
]
из входных данных и передать их, установив их как "цели" конвейера машинного обучения.
Применение DataSampler()
может, например, дополнительно включать логику, которая удаляет любой обучающий экземпляр из всего набора обучающих данных, который не содержит никаких swimming_pool
-ключ (label = -1
).
Последующие шаги должны использовать измененные данные обучения (отфильтрованные, не включая наблюдение с id_=3
), чтобы соответствовать модели. Как указано выше, в режиме прогнозированияDataSampler
а также SwimmingPoolExtractor
будет просто передавать входные данные
Как
Насколько мне известно, ни neuraxle
ни sklearn
(для последнего я уверен) предлагают шаги конвейера, которые соответствуют требуемой функциональности (из того, что я собрал до сих пор neuraxle
должен, по крайней мере, иметь поддержку нарезки данных, учитывая, что он реализует метаоценки перекрестной проверки).
Мне что-то не хватает, или есть способ реализовать такую функциональность в любой из моделей конвейера? Если нет, существуют ли альтернативы перечисленным библиотекам в экосистеме Python, которые являются достаточно зрелыми и поддерживают такие варианты использования (не говоря уже о проблемах, которые могут возникнуть при проектировании конвейеров таким образом)?
1 ответ
"Я что-то упускаю или есть способ реализовать такую функциональность"
Да, все, что вы хотите, с Neuraxle можно легко сделать:
- Вам не хватает обработчиков вывода для преобразования выходных данных! С этим вы можете отправить несколько
x
вy
внутри конвейера (таким образом, фактически не передавая никаких меток вfit
как хочешь сделать). - Вы также упускаете TrainOnlyWrapper для преобразования данных только во время поезда! Это полезно для деактивации любого шага конвейера во время тестирования (а также во время проверки). Обратите внимание, что таким образом он не будет выполнять фильтрацию данных или повторную выборку при оценке показателей проверки.
- Вы также можете использовать объект AutoML для выполнения цикла обучения.
При условии, что ваши входные данные, переданные в "fit", являются итерацией чего-либо (например: не передавайте сразу весь json, по крайней мере, сделайте что-то, что можно повторить). В худшем случае передайте список идентификаторов и выполните шаг, который преобразует идентификаторы во что-то еще, используя объект, который может взять json сам по себе, чтобы делать все, что ему нужно, с переданными идентификаторами, например.
Вот ваш обновленный код:
from neuraxle.pipeline import Pipeline
class SwimmingPoolExtractor(NonFittableMixin, InputAndOutputTransformerMixin, BaseStep): # Note here: you may need to delete the NonFittableMixin from the list here if you encounter problems, and define "fit" yourself rather than having it provided here by default using the mixin class.
def transform(self, data_inputs):
# Here, the InputAndOutputTransformerMixin will pass
# a tuple of (x, y) rather than just x.
x, _ = data_inputs
# Please note that you should pre-split your json into
# lists before the pipeline so as to have this assert pass:
assert hasattr(x, "__iter__"), "input data must be iterable at least."
x, y = self._do_my_extraction(x) # TODO: implement this as you wish!
# Note that InputAndOutputTransformerMixin expects you
# to return a (x, y) tuple, not only x.
outputs = (x, y)
return outputs
class DataSampler(NonFittableMixin, BaseStep):
def transform(self, data_inputs):
# TODO: implement this as you wish!
data_inputs = self._do_my_sampling(data_inputs)
assert hasattr(x, "__iter__"), "data must stay iterable at least."
return data_inputs
swimming_pool_pipeline = Pipeline([
TrainOnlyWrapper(SwimmingPoolExtractor()), # skipped in `.predict(...)` call
TrainOnlyWrapper(DataSampler()), # skipped in `.predict(...)` call
SomeFeaturization(),
FitSomeModel()
])
swimming_pool_pipeline.fit(training_data) # not passing in any labels!
preds = swimming_pool_pipeline.predict(test_data)
Обратите внимание, что вы также можете сделать следующее, чтобы заменить вызов fit
:
auto_ml = AutoML(
swimming_pool_pipeline,
validation_splitter=ValidationSplitter(0.20), # You can create your own splitter class if needed to replace this one. Dig in the source code of Neuraxle an see how it's done to create your own replacement.
refit_trial=True,
n_trials=10,
epochs=1,
cache_folder_when_no_handle=str(tmpdir),
scoring_callback=ScoringCallback(mean_squared_error, higher_score_is_better=False) # mean_squared_error from sklearn
hyperparams_repository=InMemoryHyperparamsRepository(cache_folder=str(tmpdir))
)
best_swimming_pool_pipeline = auto_ml.fit(training_data).get_best_model()
preds = best_swimming_pool_pipeline.predict(test_data)
Боковое примечание, если вы хотите использовать расширенные функции кэширования данных
Если вы хотите использовать кеширование, вы не должны определять никаких transform
методы, и вместо этого вы должны определить handle_transform
методы (или связанные методы), чтобы сохранить порядок "ID" данных при повторной выборке данных. Neuraxle создан для обработки повторяемых данных, и поэтому я сделал несколько утверждений выше, чтобы убедиться, что ваш json уже предварительно обработан, так что это своего рода список чего-то.