多输出 Scikeras

Scikeras with multioutput

我尝试创建堆叠回归器以使用 SVR 和神经网络作为估计器来预测多个输出,最终估计器是线性回归。

print(X_train.shape) #(73, 39)
print(y_train.shape) #(73, 13)
print(X_test.shape) #(19, 39)
print(y_test.shape) #(19, 13)


 def build_nn():
  ann = Sequential()
  ann.add(Dense(40, input_dim=X_train.shape[1], activation='relu', name="Hidden_Layer_1"))
  ann.add(Dense(y_train.shape[1], activation='sigmoid', name='Output_Layer'))
  ann.compile( loss='mse', optimizer= 'adam', metrics = 'mse')
  return ann

keras_reg = KerasRegressor(model = build_nn,optimizer="adam",optimizer__learning_rate=0.001,epochs=100,verbose=0)


stacker = StackingRegressor(estimators=[('svr',SVR()),('ann',keras_reg)], final_estimator= LinearRegression())
reg = MultiOutputRegressor(estimator=stacker)
model = reg.fit(X_train,y_train)

我可以 'fit' 模型。但是,我在尝试预测时遇到了以下问题。

prediction = reg.predict(X_test)

ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 19 and the array at index 1 has size 247

我想重点如下。一方面,NN 模型本身确实支持 multi-output 回归任务,定义一个类似于您构建的输出层(即具有多个节点)的输出层可能会得到解决等于输出的数量(不过,关于你的构造,我会用 activation=None 指定线性激活而不是 sigmoid 激活)。

def build_nn():
    ann = Sequential()
    ann.add(Dense(40, input_dim=X_train.shape[1], activation='relu', name="Hidden_Layer_1"))
    ann.add(Dense(y_train.shape[1], name='Output_Layer'))
    ann.compile(loss='mse', optimizer= 'adam', metrics = 'mse')
    return ann

另一方面,在这里,您试图通过在 [=14] 上调用 MultiOutputRegressor 构造函数来解决 multi-output 回归任务=] 实例,即通过为每个输出显式训练一个回归模型,回归模型是多个回归模型的组合。

这个问题是由于 StackingRegressor 基本估计器的预测的串联,特别是它们的不同形状。确实:

这就是说,在 StackingRegressor 基础 estimators 中,您有一个 SVR() 模型,其设计无法原生解决 multi-output 回归任务和一个 KerasRegressor 神经网络,按照您的定义,它意味着能够在不委托的情况下解决 multi-output 回归任务至 MultiOutputRegressor。因此,_concatenate_predictions 中发生的是 dimensionally-inconsistent 预测来自 SVR()(形状为 (19,)=(n_samples,) 的一维数组最终重塑为 (19,1) 数组)和 KerasRegressor(形状为 (19,13)=(n_samples,n_outputs) 的二维数组最终变平并重塑为 (19*13,1)=(247,1) 数组)。这反映了这样一个事实,即让你的神经网络输出层的节点数量等于输出数量不能适应 StackingRegressor 与另一个基础估计器,它应该通过 MultiOutputRegressor 必须扩展才能能够解决 multi-output 回归任务。

因此,对我来说,如果你想保持相同的“架构”,你应该让你的神经网络有一个只有一个节点的输出层,这样它的预测就可以与 SVR 模型并可供 StackingRegressor final_estimator 访问并最终委托给 MultiOutputRegressor.

from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import tensorflow as tf
import tensorflow.keras
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential
from scikeras.wrappers import KerasRegressor
from sklearn.ensemble import StackingRegressor
from sklearn.multioutput import MultiOutputRegressor
from sklearn.linear_model import LinearRegression
from sklearn.svm import SVR

X, y = make_regression(n_samples=92, n_features=39, n_informative=39, n_targets=13, random_state=42)
print(X.shape, y.shape)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)

def build_nn():
    ann = Sequential()
    ann.add(Dense(40, input_dim=X_train.shape[1], activation='relu', name="Hidden_Layer_1"))
    ann.add(Dense(1, name='Output_Layer'))
    ann.compile(loss='mse', optimizer= 'adam', metrics = 'mse')
    return ann

keras_reg = KerasRegressor(model = build_nn, optimizer="adam", 
    optimizer__learning_rate=0.001, epochs=100, verbose=0)
stacker = StackingRegressor(estimators=[('svr', SVR()), ('ann', keras_reg)], final_estimator = LinearRegression())

reg = MultiOutputRegressor(estimator=stacker)
reg.fit(X_train,y_train)

predictions = reg.predict(X_test)