Python 黑箱模型中返回最大输出的最优输入组合的求解

Python 黑箱模型中返回最大输出的最优输入组合的求解,python,machine-learning,neural-network,regression,supervised-learning,Python,Machine Learning,Neural Network,Regression,Supervised Learning,在我的工作中将ANN应用于回归任务时,我一直面临的一个挑战是,为了找到给定输入范围的最佳结果,我必须向模型提供多维网格,然后简单地选择最高值。然而,总体而言,这是一个计算成本非常高的解决方案。下面这段文字的长度可能很吓人,但这只是我试图更好地解释它 让我用其他的话来解释。假设我的ANN有9个输入,然后我想检查哪些特征值的组合返回的结果最高。我目前正在克服这个问题,只需创建一个9D网格,简单地预测每个样本的值,然后确定最佳行。然而,这需要花费大量的时间来完成。因此,如果可能的话,我正在寻找一种能够

在我的工作中将ANN应用于回归任务时,我一直面临的一个挑战是,为了找到给定输入范围的最佳结果,我必须向模型提供多维网格,然后简单地选择最高值。然而,总体而言,这是一个计算成本非常高的解决方案。下面这段文字的长度可能很吓人,但这只是我试图更好地解释它

让我用其他的话来解释。假设我的ANN有9个输入,然后我想检查哪些特征值的组合返回的结果最高。我目前正在克服这个问题,只需创建一个9D网格,简单地预测每个样本的值,然后确定最佳行。然而,这需要花费大量的时间来完成。因此,如果可能的话,我正在寻找一种能够更有效地达到这个最佳输出值的方法

在代码中,它看起来是这样的:(只是一个简单的虚构示例,在python中并不真实):

设置一个黑盒模型,在这种情况下,是一个神经网络

x_scaler = MinMaxScaler()
y_scaler = MinMaxScaler()
X_scaled = x_scaler.fit_transform(X)
y_scaled = y_scaler.fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_scaled, test_size=0.2, random_state=0)

model = Sequential()
model.add(Dense(100, input_dim = 2, activation = 'relu'))
model.add(Dense(100, activation='relu'))
model.add(Dense(100, activation='relu'))
model.add(Dense(1, activation = 'relu'))
model.compile(optimizer = 'Adam', loss = 'mean_squared_error')
epochs_hist = model.fit(X_train, y_train, epochs = 100, batch_size = 50, validation_split = 0.2)

现在,我已经适应了我的模型,我将在几个时间间隔内使用网格网格,以便在指定范围内找到最佳值:

x1_pred = np.linspace(0,20,21) 
x2_pred = np.linspace(0,20,21)
X_pred = pd.DataFrame((product(*[x1_pred,x2_pred])))
X_pred_test = x_scaler.fit_transform(X_pred)
y_pred = model.predict(X_pred_test)
y_pred = y_scaler.inverse_transform(y_pred)

所以,假设我做了一些类似的事情来达到最优,但是在这个例子中有9个输入,那么很明显,这个计算在强制性上是不可行的。因此,我的问题是如何找到输入的最佳组合,以返回黑盒模型(如ANN)的最大输出。

以下是如何从模型中获得“最佳结果”的示例。重要的部分是
优化
获取(u simplex)
调用(u call)模型
。通过这样做,您可以减少模型所需的调用量

from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
from scipy.optimize import minimize
from copy import copy


class Example:

    def __init__(self):
        self.X = np.random.random((10000, 9))
        self.y = self.get_y()
        self.clf = GradientBoostingRegressor()
        self.fit()

    def get_y(self):
        # sum of squares, is minimum at x = [0, 0, 0, 0, 0 ... ]
        return np.array([[self._func(i)] for i in self.X])

    def _func(self, i):
        return sum(i * i)

    def fit(self):
        self.clf.fit(self.X, self.y)

    def optimize(self):
        x0 = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
        initial_simplex = self._get_simplex(x0, 0.1)
        result = minimize(fun=self._call_model,
                          x0=np.array(x0),
                          method='Nelder-Mead',
                          options={'xatol': 0.1,
                                   'initial_simplex': np.array(initial_simplex)})
        return result

    def _get_simplex(self, x0, step):
        simplex = []
        for i in range(len(x0)):
            point = copy(x0)
            point[i] -= step
            simplex.append(point)

        point2 = copy(x0)
        point2[-1] += step
        simplex.append(point2)
        return simplex

    def _call_model(self, x):
        prediction = self.clf.predict([x])
        return prediction[0]

example = Example()
result = example.optimize()
print(result)

当然,如果你想最大化而不是最小化,你可以返回<代码>预测[0 ] < /代码>而不是<代码>预测[0 ] < /代码>欺骗SpPy。< /P>你会考虑遗传算法吗?我不知道评估一个可能的输入组合的代价有多大。我不确定我是否理解你在尝试做什么,但如果你想找到最小值/最大值,你应该看看

scipy.optimize
,它实现了几个算法,可以帮上忙you@MayowaAyodele这是一种可能性。但是,我不确定在这种情况下我将如何使用它。@Nathan不幸的是,由于我们正在使用blackbox模型,因此无法使用scipy.optimize。因此,没有明确的方程来优化并找到最小值和最大值。难道你不能将模型包装成一个函数并将其传递给scipy吗?有趣的解决方案,然而,对于像ANN这样的黑盒模型,这种优化是如何工作的?至少从我目前的理解来看,既然你找不到一个显式函数,就不可能用极小值应用一个优化器。你不需要nelder mead的显式函数,有多种方法可以优化黑盒模型。你所需要的取决于你的计算能力、时间、局部极小值的存在以及结果的不稳定性。您可以查看可能感兴趣的可用模型列表在本例中,我正在优化的问题也是一个黑盒模型。我完全不知道什么是
gradientboostingressor
does@Nathan我也有同样的问题,但有一些限制。我尝试了SLSQP,但它总是返回初始猜测的值。可能需要梯度信息,我无法给出。Nelder mead不支持约束。你有什么建议?
from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
from scipy.optimize import minimize
from copy import copy


class Example:

    def __init__(self):
        self.X = np.random.random((10000, 9))
        self.y = self.get_y()
        self.clf = GradientBoostingRegressor()
        self.fit()

    def get_y(self):
        # sum of squares, is minimum at x = [0, 0, 0, 0, 0 ... ]
        return np.array([[self._func(i)] for i in self.X])

    def _func(self, i):
        return sum(i * i)

    def fit(self):
        self.clf.fit(self.X, self.y)

    def optimize(self):
        x0 = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
        initial_simplex = self._get_simplex(x0, 0.1)
        result = minimize(fun=self._call_model,
                          x0=np.array(x0),
                          method='Nelder-Mead',
                          options={'xatol': 0.1,
                                   'initial_simplex': np.array(initial_simplex)})
        return result

    def _get_simplex(self, x0, step):
        simplex = []
        for i in range(len(x0)):
            point = copy(x0)
            point[i] -= step
            simplex.append(point)

        point2 = copy(x0)
        point2[-1] += step
        simplex.append(point2)
        return simplex

    def _call_model(self, x):
        prediction = self.clf.predict([x])
        return prediction[0]

example = Example()
result = example.optimize()
print(result)