ML/NN 作为进一步优化(最大化)的函数评估器 - 实际示例

数据挖掘 机器学习 Python 神经网络 优化
2021-10-11 15:53:41

我正在研究生产优化问题;与 Vegard Flovik How to use machine learning for production optimization所描述的想法非常相似下图取自引用的帖子,很好地总结了它:

在此处输入图像描述

第一步很明显,我确实有一个机器学习或神经网络模型形式的模型。我将如何进行第二步?我如何使用经过训练的模型作为函数评估器,通过 Scipy、贝叶斯优化等进行进一步的多维非线性优化(例如最大化)?

我似乎找不到一个实际的例子。以封闭形式的分析函数作为优化问题的目标是公认的。Tirthajyoti Sarkar的文章Optimization with SciPy and application ideas to machine learning给出了一些使用 Scipy 的示例,并介绍了使用绑定约束等进行优化的包。然而例子非常简单(一个封闭形式的数学函数),他只是掩盖了这种想法的扩展以使用 NN 作为目标函数,我引用:

你可以自由选择一个分析函数,一个深度学习网络(也许是一个回归模型),甚至是一个复杂的模拟模型,把它们一起扔进优化的坑里。

任何线索/提示/链接表示赞赏!


[附录]

为了有一个具体的例子,让我们假设我们有一个虚拟数据集,其中包含一组特征和一个虚构的 ProductionYield,它是输入变量的非线性组合:

import numpy as np
import pandas as pd

df = pd.DataFrame(columns=['Pressure','Temprerature','Speed','ProductionYield'])

df['Pressure'] = np.random.randint(low= 2, high=10, size=2000)
df['Temprerature'] = np.random.randint(10, 30, size=2000)
df['Speed'] = np.random.weibull(2, size=2000)
df['ProductionYield'] = (df['Pressure'])**2 + df['Temprerature'] * df['Speed'] + 10
df['ProductionYield']= df['ProductionYield'].clip(0, 100)

   Pressure  Temprerature     Speed  ProductionYield
0         7            20  1.810557        95.211139
1         2            29  0.674221        33.552409
2         8            17  0.537533        83.138065
3         3            24  1.945914        65.701938
4         6            23  0.514679        57.837610

1.Predictive Algorithm(一个简单的神经网络):

## Train/Test Split
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(df[['Pressure','Temprerature','Speed']].values, df['ProductionYield'].values, test_size=0.33, random_state=42)

## Build NN Model
import tensorflow as tf
from tensorflow.keras import layers

def build_model():
    
    # create model
    model = tf.keras.Sequential()
    model.add(layers.Dense(64, input_dim=3, kernel_initializer='normal', activation='relu'))
    model.add(layers.Dense(128, kernel_initializer='normal', activation='relu'))
    model.add(layers.Dense(1, kernel_initializer='normal'))
    
    # Compile model
    model.compile(loss='mean_squared_error', optimizer='adam')
    
    return model

model = build_model()
model.fit(x_train, y_train,
          validation_split=0.2,
          verbose=0, epochs=1000)

2.优化【问题核心】:

问题出在此处,当训练 ML/NN 时,我看不到(按我的意愿导出)函数的数学形式(在此示例中为 NN)及其变量(应该是我的特征变量)要做优化就像我们对封闭式显式数学函数所做的那样。

[更新 15.01.2021 ]:

根据 Valentin 的出色回答,我在一个实际示例中将各个部分组合在一起,展示了如何使用 ML/NN 模型作为输入函数,使用附录中显示的虚拟数据集进行进一步优化(此处通过 scipy.optimize)。有关详细信息,请参阅此笔记本。

1个回答

这篇文章似乎与您的相似,可能会有所帮助。看来您正在寻找的是一种无导数的优化方法该概念的Wikipedia 页面列出了此类方法。

直观地说,这些技术将使用各种输入(压力、温度、速度)对函数(在您的情况下为网络)进行采样,并找出哪些输入对其进行优化。它们的不同之处在于它们的采样策略,因为采样可能不切实际或昂贵。

你可以用它scipy.optimize.minimize来做到这一点。传递您的网络func并使用初始猜测,这可以是变量的最后一个值。Scipy 需要一个具有以下签名的函数:fun(x, *args) -> floatwherex是一个一维 numpy 数组。这可能意味着您需要将网络包装成这样:

def wrapper(x, *args) -> float:
    
    network_input = _numpy_to_valid_network_input(x)

    network_output = network.predict(network_input, *args)

    scipy_output = _network_output_to_float(network_output)

    return scipy_output

然后,您可以wrapper作为您的func. 否定 的输出scipy_output会将最小化问题变成最大化问题。如果您的输入变量是有界的,即 [0, 100],您可以做两件事:

  • 使用允许您明确定义这些界限的算法(即使用bounds参数的 L-BFGS-B)
  • 例如,使用 sigmoid 函数隐式绑定您的输入。通过像我在下面所做的那样,您可以创建一个bounded_value始终返回您选择范围内的值的函数,即使优化算法可能会尝试任何浮点数。
import numpy as np

def sigmoid(x):
  return 1 / (1 + np.exp(-x))

def bounded_value(x, min_value=0, max_value=100):
   return min_value + (sigmoid(x) * (max_value - min_value))

如果你想限制你的输出,那就更容易了。如果您的目标是最小化,如果您的网络输出任何超出您范围的值,则返回一个非常大的值。显然,可以通过调整训练期间使用的损失来确保您的网络始终返回合理的值(这对于 AutoKeras 来说很难)。

如果您想实现自己的方法,我建议您使用坐标下降,因为您没有很多输入维度 (3),而且从头开始实现非常简单。显然,随机采样空间并选择产生最佳函数值的输入的蛮力方法更容易实现。