使用Keras构建ANN拟合正弦函数参数过多的技术咨询
我正在研究不同的函数逼近方法,首先尝试使用ANN(人工神经网络)通过Keras实现,代码如下:
import tensorflow as tf import matplotlib.pyplot as plt %matplotlib inline import numpy as np from tensorflow.keras.layers import Input, Dense, Flatten, Dropout from tensorflow.keras.optimizers import Adam from tensorflow.keras.models import Model from sklearn.preprocessing import MinMaxScaler X = np.linspace(0.0 , 2.0 * np.pi, 20000).reshape(-1, 1) Y = np.sin(X) x_scaler = MinMaxScaler() y_scaler = MinMaxScaler() X = x_scaler.fit_transform(X) Y = y_scaler.fit_transform(Y) plt.plot(X, Y) plt.show() inp = Input(shape=(20000, 1)) x = Dense(32, activation='relu')(inp) x = Dense(64, activation='relu')(x) x = Dense(128, activation='relu')(x) x = Dense(256, activation='relu')(x) predictions = Dense(1, activation='linear')(x) model = Model(inp, predictions) model.compile(loss='mse', optimizer='adam') model.summary() X = X.reshape((-1, 20000, 1)) Y = Y.reshape((-1, 20000, 1)) history = model.fit(X, Y, epochs=500, batch_size=32, verbose=2) X_test = np.linspace(0.0 , 2.0 * np.pi, 20000).reshape(-1, 1) X_test.shape X_test = x_scaler.transform(X_test) X_test = X_test.reshape((-1, 20000, 1)) res = model.predict(X_test, batch_size=32) res = res.reshape((20000, 1)) res_rscl = y_scaler.inverse_transform(res) Y_rscl = y_scaler.inverse_transform(Y.reshape(20000, 1)) plt.subplot(211) plt.plot(res_rscl, label='ann') plt.plot(Y_rscl, label='train') plt.xlabel('#') plt.ylabel('value [arb.]') plt.legend() plt.subplot(212) plt.plot(Y_rscl - res_rscl, label='diff') plt.legend() plt.show()该模型拟合正弦曲线效果良好,但参数数量达43777个,我对此存疑。对比相关R代码(我不懂R,但推测其ANN规模更小)后更困惑。现咨询:
- 我的方法是否正确?
- 能否优化以减少参数?
- 正弦函数拟合需大量参数是否正常?
- 有观点认为数据的周期性是ANN拟合难点,这是否是参数过多的原因?
嘿,你的问题核心其实是数据维度和网络结构的理解偏差,这才导致了参数爆炸,和正弦函数的周期性完全没关系!咱们一步步拆解:
1. 你的方法哪里错了?
你把整个20000个x值当成了一个样本(看代码里X = X.reshape((-1, 20000, 1)),这意味着你的数据集只有1个样本,输入是20000步的序列)。但函数逼近的逻辑应该是:每个样本是单个x值,对应的标签是sin(x)——也就是你需要20000个独立样本,每个样本的输入形状是(1,),标签是(1,)。
这种错误的输入设计直接让你的网络变成了序列建模结构(类似时间序列预测),而非函数逼近的回归模型,自然会产生大量冗余参数。
2. 怎么优化减少参数?
修正数据维度,用正确的样本结构,然后用小得多的网络就能完美拟合正弦曲线。以下是修正后的代码:
import tensorflow as tf import matplotlib.pyplot as plt %matplotlib inline import numpy as np from tensorflow.keras.layers import Input, Dense from tensorflow.keras.optimizers import Adam from tensorflow.keras.models import Model from sklearn.preprocessing import MinMaxScaler # 正确的样本结构:20000个样本,每个样本对应单个x值 X = np.linspace(0.0, 2.0 * np.pi, 20000).reshape(-1, 1) # shape (20000, 1) Y = np.sin(X) # 数据归一化(这部分你之前的做法是对的) x_scaler = MinMaxScaler() y_scaler = MinMaxScaler() X_scaled = x_scaler.fit_transform(X) Y_scaled = y_scaler.fit_transform(Y) # 正确的模型结构:输入是单个x值(shape (1,)) inp = Input(shape=(1,)) x = Dense(16, activation='relu')(inp) x = Dense(32, activation='relu')(x) x = Dense(16, activation='relu')(x) predictions = Dense(1, activation='linear')(x) model = Model(inp, predictions) model.compile(loss='mse', optimizer=Adam(learning_rate=0.001)) model.summary() # 这里参数总数只有1105个,远少于你的4万+! # 训练:每个样本独立,无需序列reshape history = model.fit(X_scaled, Y_scaled, epochs=50, batch_size=64, verbose=1) # 测试与可视化 X_test = np.linspace(0.0, 2.0 * np.pi, 20000).reshape(-1, 1) X_test_scaled = x_scaler.transform(X_test) res_scaled = model.predict(X_test_scaled, batch_size=64) # 反归一化还原真实值 res = y_scaler.inverse_transform(res_scaled) Y_true = y_scaler.inverse_transform(Y_scaled) # 绘图对比 plt.subplot(211) plt.plot(X_test, res, label='ANN Predictions') plt.plot(X_test, Y_true, label='True Sine Curve', alpha=0.5) plt.xlabel('x') plt.ylabel('sin(x)') plt.legend() plt.subplot(212) plt.plot(X_test, Y_true - res, label='Error') plt.ylabel('Error') plt.legend() plt.tight_layout() plt.show()
这个修正后的模型不仅参数数量骤降,训练效率也会大幅提升,拟合效果和你之前的模型一样好(甚至更稳定)。
3. 正弦函数拟合需要大量参数正常吗?
完全不正常!正弦函数是非常简单的连续周期函数,用几层小的全连接层(甚至单个隐藏层,比如16个神经元)就能轻松拟合,参数数量通常在几百到一千以内就足够了。你之前的参数过多纯粹是结构设计错误,和函数本身无关。
4. 周期性是ANN拟合的难点吗?
对于像正弦这样的简单周期函数,完全不是难点。ANN的非线性拟合能力足够捕捉这种平滑的周期模式。只有当周期模式非常复杂(比如多周期叠加、非固定周期)时,才可能需要RNN或Transformer这类序列模型,但对于单周期的正弦曲线,普通全连接层就绰绰有余。你之前的问题和周期性没有任何关系。
内容的提问来源于stack exchange,提问作者SRC

