特征缩放会降低性能?

数据挖掘 Python 神经网络 执行
2021-09-30 07:01:43

我注意到在某些情况下,特征缩放会完全破坏神经网络的性能。以下是我的结果,您可以轻松复制。

我使用神经网络来近似函数 g[0,100] 如下:

NN(X;θ)g(X)

在哪里 XU([0,100]). 然后我随机抽样一些X ((Xi)i) 作为我的训练集,并使用 Yi=g(Xi) 作为目标。

通常 NN是一个 Keras Sequential 模型,有几个隐藏层,有 15-20 个神经元 (elu),还有一个没有激活函数的输出层。使用 初始化参数kernel_initializer='normal'

现在我在 1dim 中测试我的近似值时注意到以下内容(在尝试推广到更高维度之前):

为了 g(x)=max(0,X50), 缩放 X 除以 100 并不会真正改变 NN, 估计 g 比较好。

但是,当我使用其他功能时,例如 g(x)=1Ix[40,60] 或者 g(x)=(x50)2,它完全失败了。

你有解释吗?

这非常令人不安,因为如果简单的一维示例完全失败,您如何相信您的网络可以逼近高维函数?

以下是 Python 中的示例实现:

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import matplotlib.pyplot as plt

d=1
nn_value_batch_size=128
nn_value_epochs=50
nn_value_training_size=10000

def nn_value_get_architecture(layers_sizes):
        nn_value = Sequential()
        nn_value.add(Dense(layers_sizes[0], input_dim=d, #d=1
                        kernel_initializer='normal', activation='elu'))

        # hidden layers
        for nb in layers_sizes[1:]:
            nn_value.add(Dense(nb, kernel_initializer='normal',
                               activation='elu'))

        # output layer
        nn_value.add(Dense(1, kernel_initializer='normal'))

        nn_value.compile(loss="mean_squared_error", optimizer='adam')
        return nn_value

def nn_value_optimize(nn_value, objective_function,
                          x_normalize=True):
        # fit the model
        x_distribution = lambda size: np.random.uniform(0, 100, size)
        for epoch in range(nn_value_epochs):
            X_train = x_distribution(nn_value_training_size)
            y_train = objective_function(X_train)
            if x_normalize==True:
                X_train = X_train/100
            nn_value.fit(X_train, y_train,
                         batch_size=nn_value_batch_size,
                         verbose=1)

        return nn_value

def g(X):
        #return 1-(np.maximum(0., X-40)/(X-40) - np.maximum(0., X-60)/(X-60))
        return (X-50)**2
        #return np.maximum(0., X-50) #only example that works

nn_value = nn_value_get_architecture(
                layers_sizes=[20,15,15,15,15])
g = np.vectorize(g)
normalize=True
nn_value = nn_value_optimize(nn_value, g, normalize)

# plot results
x = np.arange(0,101,1)
if normalize==True:
  plt.plot(x, nn_value.predict(x/100))
else:
  plt.plot(x, nn_value.predict(x))
plt.show()

无缩放:

无缩放

使用缩放:

带缩放

1个回答

通过缩放X而不是y,并且在初始化时权重很小,我认为你让 NN 很难将权重提升到他们需要的规模。可能如果你让它训练更多的时期,它会找到合适的规模,但快速的实验表明它陷入了相当大的振荡损失。

我也成功地通过(1)缩放达到了抛物线曲线,y大致降落在[0,1], 或 (2) 将初始权重设置为更大,例如from keras import initializers; nn_initializer=initializers.RandomNormal(std=0.5)kernel_initializer=nn_initializer始终使用。std( in的默认RandomNormal值为0.05)。

对于指标函数目标,显然缩放y不是问题。但有趣的是,扩大初始权重确实有效。也许是因为您需要在 40 和 60 处获得这两个大坡度钻头?

我建议尝试的另一件事(我没有在这里)是改变学习率,这取决于事物的规模。尤其是当初始权重远低于我们所知道的它们最终需要的权重时,也许较大的初始学习率和一些衰减会有所帮助。