【问题标题】:Sklearn GridSearch with pre-training带有预训练的 Sklearn GridSearch
【发布时间】:2019-06-02 06:59:25
【问题描述】:

我正在制作一个Sklearn Pipeline,并使用GridSearchCV 进行的参数优化。管道必须为实施 pre-train 然后 fine-tune 方法的几个不同实体获得最佳模型:pre-train 所有实体在一起,微调每个元素并为每个实体返回一个模型。这些是管道的约束:

  • 预训练和微调必须在同一管道中进行,因为这两个模型必须在每个 GridSearchCV 的折叠中具有相同的数据。
  • 预训练模型必须将其权重传递给微调模型。

我已经实现了:

  • 一个 Sklearn 转换器,它采用一个数据帧,其中包含输入中的所有实体并适合自身。
  • 一种 Sklearn 回归器,可将每个实体的数据帧拆分为一个数据帧,并为每个实体拟合 Keras 模型。

我缺少的是如何将 Pre-train 转换器获得的权重从 Pre-train 转换器传递到 Fine-tuning 转换器(考虑到每个 GridSearchCV 折叠具有不同的权重)

代码如下:

import pandas as pd
import numpy as np
import random
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.base import BaseEstimator, RegressorMixin, TransformerMixin
from sklearn.metrics import mean_squared_error
from keras.models import Model
from keras.layers import Dense, Input
import copy

class MyRegressor(BaseEstimator, TransformerMixin):
    def __init__(self, neurons, featInput, featOutput):
        self.neurons = neurons
        self.preTrain = None
        self.featInput = featInput
        self.featOutput = featOutput

    def fit(self, X, y=None):
        X_train = X[self.featInput]
        y_train = X[self.featOutput]

        inputLayer = Input(shape=(len(self.featInput), ), name='INPUT')
        hidden = Dense(self.neurons, name='HIDDEN')(inputLayer)
        outputLayer = Dense(len(self.featOutput), name='OUTPUT')(hidden)

        self.model = Model(inputLayer, outputLayer)
        self.model.compile(loss='mse', optimizer='rmsprop')

        if self.preTrain is not None:
            self.model.loadWeights(self.preTrain)

        self.model.fit(X_train, y_train)

        return self

    def predict(self, X):
        return self.model.predict(X[self.featInput])

    def transform(self, X):
        return X

    def score(self, X, y=None, sample_weight=None):
        y_true = X[self.featOutput]
        y_pred = self.predict(X)
        return mean_squared_error(y_true, y_pred)


class LoopTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, columns, component):
        self.columns = columns
        self.component = component
        self.components = []

    def fit(self, X, y=None):
        for index, idx in X[self.columns].drop_duplicates().iterrows():
            entityDf = X[(X[self.columns] == idx).sum(axis=1) == len(self.columns)].copy()
            self.components.append({'id': idx, 'component': copy.deepcopy(self.component)})
            self.components[-1]['component'].fit(entityDf, y)
        return self

    def predict(self, X):
        results = []
        for comp in self.components:
            entityDf = X[(X[self.columns] == comp['id']).sum(axis=1) == len(self.columns)].copy()
            res = comp['component'].predict(entityDf)
            results.append(res)
        dfRes = pd.concat(results)
        return dfRes

    def score(self, X, y=None, sample_weight=None):
        results = []
        for comp in self.components:
            entityDf = X[(X[self.columns] == comp['id']).sum(axis=1) == len(self.columns)].copy()
            if len(entityDf) > 0:
                results.append(comp['component'].score(entityDf))
        return np.average(results)


#create the input dataframe: 3 entities
dataFrame = pd.DataFrame([], columns=['entityId', 'input', 'output'])
for entity in range(3):
    x = np.arange(random.randint(10, 20))
    y = x * (entity + 1)
    tempDf = pd.DataFrame(np.array([x, y]).T, columns=['input', 'output'])
    tempDf['entityId'] = entity
    dataFrame = pd.concat([dataFrame, tempDf], sort=False)
dataFrame = dataFrame.reset_index(drop=True)

#create the pipeline
neurons = [5, 10]
myPipe = Pipeline([('preTrain',
                    MyRegressor(neurons=neurons[0], featInput=['input'], featOutput=['output'])),
                   ('fineTuning',
                    LoopTransformer(['entityId'],
                                    MyRegressor(
                                        neurons=neurons[0],
                                        featInput=['input'],
                                        featOutput=['output'])))])

#pre-train and fine-tuning has to have always the same number of neurons
params = [{
    'preTrain__neurons': [neurons[0]],
    'fineTuning__component__neurons': [neurons[0]]
}, {
    'preTrain__neurons': [neurons[1]],
    'fineTuning__component__neurons': [neurons[1]]
}]

gs = GridSearchCV(myPipe, params, verbose=1, cv=3)

gs.fit(dataFrame, dataFrame)
score = gs.score(dataFrame, dataFrame)
print(score)

【问题讨论】:

  • 请贴出你目前尝试过的代码
  • @desertnaut 我已经添加了代码。但是,我只是不知道如何将preTrain 权重传递给fineTuning

标签: python machine-learning scikit-learn keras grid-search


【解决方案1】:

我很漂亮 sklearn.Pipeline 不支持这个。但只要您不克隆您的管道(例如,如果您使用GridSearchCV),您可以使用类似以下代码的代码破解您的方式,该代码提供了管道中步骤的实例下一步。您可以在管道中应用相同的原则:

from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
from sklearn.base import BaseEstimator, TransformerMixin


class MyTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, scaler):
        self.scaler = scaler

    def fit(self, X, y=None):
        print("got the means: %s" % self.scaler.mean_)
        return self

    def transform(self, X):
        return X


X, y = load_iris(return_X_y=True)
scaler = StandardScaler()
pipeline = make_pipeline(scaler,
                         MyTransformer(scaler),
                         LogisticRegression(solver='lbfgs',
                                            multi_class='auto'))
pipeline = pipeline.fit(X, y)

X = X - 1
pipeline = pipeline.fit(X, y)

正如预期的那样,这会给你这个输出:

got the means: [5.84333333 3.05733333 3.758      1.19933333]
got the means: [4.84333333 2.05733333 2.758      0.19933333]

【讨论】:

  • 感谢您的建议,但我不是在谈论样本权重,而是在谈论神经网络的实际权重。但是,在这种情况下,您的方法也是可行的(扩展 pandas DataFrame 以包含 Keras 模型),但我正在寻找一个实际的解决方案,而不是解决方法
  • 我明白了,请注意更新后的答案,我想它现在有点回答你的问题了。
  • 是的,我知道,但正如您所说,GridSearchCV 将对缩放器进行两次深层复制(复制管道时复制一次,复制MyTransformer 时复制一次),这样您就可以在MyTransformer中有一个未安装的缩放器
猜你喜欢
  • 2017-08-29
  • 2018-05-07
  • 1970-01-01
  • 1970-01-01
  • 2020-03-27
  • 2021-09-16
  • 2018-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多