我正在训练一个神经网络(使用C++,没有使用任何额外的库),以学习一个随机的波动函数:
f(x)=0.2+0.4×2+0.3sin(15x)+0.05cos(50x)
在Python中绘制如下:
lim = 500for i in range(lim): x.append(i) p = 2*3.14*i/lim y.append(0.2+0.4*(p*p)+0.3*p*math.sin(15*p)+0.05*math.cos(50*p))plt.plot(x,y)
这对应于如下曲线:
同一个神经网络在使用单隐藏层(5个神经元)和tanh激活函数的情况下,已经成功地很好地近似了正弦函数。但是,我无法理解为什么波动函数会出问题。尽管均方误差似乎在下降。(**为了可见性,误差已放大100倍):
我怀疑是标准化的问题。我的做法如下:
生成训练数据如下:
int numTrainingSets = 100;double MAXX = -9999999999999999;for (int i = 0; i < numTrainingSets; i++) { double p = (2*PI*(double)i/numTrainingSets); training_inputs[i][0] = p; //INSERTING DATA INTO i'th EXAMPLE, 0th INPUT (Single input) training_outputs[i][0] = 0.2+0.4*pow(p, 2)+0.3*p*sin(15*p)+0.05*cos(50*p); //Single output ///FINDING NORMALIZING FACTOR (IN INPUT AND OUTPUT DATA) for(int m=0; m<numInputs; ++m) if(MAXX < training_inputs[i][m]) MAXX = training_inputs[i][m]; //FINDING MAXIMUM VALUE IN INPUT DATA for(int m=0; m<numOutputs; ++m) if(MAXX < training_outputs[i][m]) MAXX = training_outputs[i][m]; //FINDING MAXIMUM VALUE IN OUTPUT DATA ///NORMALIZE BOTH INPUT & OUTPUT DATA USING THIS MAXIMUM VALUE ////DO THIS FOR INPUT TRAINING DATA for(int m=0; m<numInputs; ++m) training_inputs[i][m] /= MAXX; ////DO THIS FOR OUTPUT TRAINING DATA for(int m=0; m<numOutputs; ++m) training_outputs[i][m] /= MAXX; }
这是模型训练的数据。验证/测试数据生成如下:
int numTestSets = 500; for (int i = 0; i < numTestSets; i++) { //NORMALIZING TEST DATA USING THE SAME "MAXX" VALUE double p = (2*PI*i/numTestSets)/MAXX; x.push_back(p); //FORMS THE X-AXIS FOR PLOTTING ///Actual Result double res = 0.2+0.4*pow(p, 2)+0.3*p*sin(15*p)+0.05*cos(50*p); y1.push_back(res); //FORMS THE GREEN CURVE FOR PLOTTING ///Predicted Value double temp[1]; temp[0] = p; y2.push_back(MAXX*predict(temp)); //FORMS THE RED CURVE FOR PLOTTING, scaled up to de-normalize }
这种标准化方法正确吗?如果是,可能出了什么问题?如果不是,应该怎么做?
回答:
我发现情况并不那么常规,这是我的错误:1) 我正确地找到了标准化因子,但必须将以下代码改为:
for (int i = 0; i < numTrainingSets; i++) { //Find and update Normalization factor(as shown in the question) //Normalize the training example }
改为
for (int i = 0; i < numTrainingSets; i++) { //Find Normalization factor (as shown in the question) } for (int i = 0; i < numTrainingSets; i++) { //Normalize the training example }
此外,之前的验证集生成如下:
int numTestSets = 500;for (int i = 0; i < numTestSets; i++){ //Generate data double p = (2*PI*i/numTestSets)/MAXX; //And other steps...}
而训练数据是基于numTrainingSets = 100生成的。因此,训练集和验证集生成的p值处于不同的范围。所以,我必须将** numTestSets 设置为 numTrainSets**。
最后,
这种标准化方法正确吗?
我之前错误地标准化了实际结果!如问题中所示:
double p = (2*PI*i/numTestSets)/MAXX;x.push_back(p); //FORMS THE X-AXIS FOR PLOTTING///Actual Resultdouble res = 0.2+0.4*pow(p, 2)+0.3*p*sin(15*p)+0.05*cos(50*p);
注意:生成这个实际结果的p值已经被标准化(不必要地)。