我主要使用ANN进行分类,直到最近才开始尝试对连续变量进行建模。作为练习,我生成了一组简单的(x,y)对,其中y = x ^ 2,并尝试训练ANN以学习该二次函数。
人工神经网络模型:
此ANN具有1个输入节点(即x),2个隐藏层(每个层中每个层都有2个节点)和1个输出节点。所有四个隐藏节点都使用非线性tanh激活函数,而输出节点没有激活函数(因为它是回归函数)。
数据:
对于训练集,我在(-20,20)之间为x随机生成了100个数字,并计算出y = x ^ 2。对于测试集,我为x随机生成了介于(-30,30)之间的100个数字,并且还计算了y = x ^ 2。然后,我对所有x进行了变换,以使它们以0为中心,并且其min和max大约为-1.5和1.5。我也对所有y进行了类似的变换,但将其最小值和最大值设为-0.9和0.9。这样,所有数据都位于tanh激活函数的中间范围内,而不是极端。
问题:
在Keras中训练了ANN之后,我看到只学习了多项式函数的右半部分,而左半部分则完全平坦。有谁知道为什么会这样?我尝试使用不同的缩放选项以及隐藏层规格,但左侧没有运气。
谢谢!
随附的代码是我用于所有内容的代码,图像显示了缩放训练x与预测y的关系图。如您所见,抛物线只有一半被回收。
import numpy as np, pandas as pd
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import matplotlib.pyplot as plt
seed = 10
n = 100
X_train = np.random.uniform(-20, 20, n)
Y_train = X_train ** 2
X_test = np.random.uniform(-30, 30, n)
Y_test = X_test ** 2
#### Scale the data
x_cap = max(abs(np.array(list(X_train) + list(X_test))))
y_cap = max(abs(np.array(list(Y_train) + list(Y_test))))
x_mean = np.mean(np.array(list(X_train) + list(X_test)))
y_mean = np.mean(np.array(list(Y_train) + list(Y_test)))
X_train2 = (X_train-x_mean) / x_cap
X_test2 = (X_test-x_mean) / x_cap
Y_train2 = (Y_train-y_mean) / y_cap
Y_test2 = (Y_test-y_mean) / y_cap
X_train2 = X_train2 * (1.5 / max(X_train2))
Y_train2 = Y_train2 * (0.9 / max(Y_train2))
# define base model
def baseline_model1():
# create model
model1 = Sequential()
model1.add(Dense(2, input_dim=1, kernel_initializer='normal', activation='tanh'))
model1.add(Dense(2, input_dim=1, kernel_initializer='normal', activation='tanh'))
model1.add(Dense(1, kernel_initializer='normal'))
# Compile model
model1.compile(loss='mean_squared_error', optimizer='adam')
return model1
np.random.seed(seed)
estimator1 = KerasRegressor(build_fn=baseline_model1, epochs=100, batch_size=5, verbose=0)
estimator1.fit(X_train2, Y_train2)
prediction = estimator1.predict(X_train2)
plt.scatter(X_train2, prediction)
答案 0 :(得分:0)
您的网络对初始参数非常敏感。以下内容将有所帮助:
将您的kernel_initializer
更改为glorot_uniform
。您的网络非常小,glorot_uniform
与tanh激活配合使用会更好。 Glorot uniform会鼓励您的权重最初在更合理的范围内(因为它考虑了每一层的扇入和扇出)。
训练模型以获取更多的时间(即1000)。
答案 1 :(得分:0)
您还应该考虑向隐藏层添加更多宽度。我从2变到5,非常合适。我也根据rvinas的建议使用了更多的时代