理论上神经网络可以拟合任意的函数(应该用逼近更贴切一些)。

定义好神经网,送进去x和y,模型就学完了。但实际上,远没有这么简单。

不信,我们来看个简单例子。拟合一个y=cos(x),这样一个简单的函数。

这似乎是一个简单的不能再简单的问题。

下图这是循环1000次的效果,次数越多,逼近的越好。

代码如下:

import numpy as np
from keras import losses
from keras.layers import Input,Dense
from keras.models import Model
import matplotlib.pyplot as plt

np.random.seed(1024)

def get_data(startvalue_of_x,endValue_of_x,step_value,function):
    dataX=np.arange(startvalue_of_x,endValue_of_x,step_value)
    dataX=dataX.reshape(len(dataX),1)    
    dataY=function(dataX)
    return dataX,dataY

def get_dense_model(unitsCount,activationFunction):
	input=Input(shape=(1,),name="input")
	dense=Dense(units=unitsCount,name="dense",activation=activationFunction)(input)
	output=Dense(units=1,name="denseOutput")(dense)
	model=Model(input,output)
	return model

def run_train_and_test(startvalue_of_x,endValue_of_x,step_value,function,unitsCount,activationFunctionName):
    X,Y=get_data(startvalue_of_x,endValue_of_x,step_value,function)
    model=get_dense_model(unitsCount,activationFunctionName)
    model.compile(optimizer="adam", loss=losses.mean_squared_error, metrics=[losses.mean_absolute_error])
    model.fit(X,Y,batch_size=50,epochs=10000)
    
    
    result=model.predict(X)
    plt.plot(X,Y)
    plt.plot(X,result,'--')
    plt.show()

   
if __name__ == "__main__":
    run_train_and_test(0,2*np.pi,0.01,np.cos,100,"relu")
    

一个周期没问题,接下来我们将最后一行代码,x的范围调整为[0,10*np.pi]之间,然后神奇的事情出现了。如下图所示,他只拟合了前面的一部分,why?循环1000次,难道不应该每个点都是一样的权重吗?为什么优先优化前面的点?这个问题至今没有想清楚。

循环10000次,是这样的效果。

更换激活函数,选择不一样的初始化,增加训练次数,增加层数,都能产生较为明显的变化。感兴趣可以参考一下代码,实现几个函数的模拟:

import numpy as np
from keras import losses
from keras.layers import Input,Dense
from keras.models import Model
import matplotlib.pyplot as plt
#x的取值范围
np.random.seed(np.power(2,10))

def get_data(startvalue_of_x,endValue_of_x,step_value,function):
    dataX=np.arange(startvalue_of_x,endValue_of_x,step_value)
    dataX=dataX.reshape(len(dataX),1)    
    dataY=function(dataX)
    return dataX,dataY

def get_dense_model(unitsCount,activationFunction):
	input=Input(shape=(1,),name="input")
	dense=Dense(units=unitsCount,name="dense",activation=activationFunction)(input)
	output=Dense(units=1,name="denseOutput")(dense)
	model=Model(input,output)
	return model

def get_dense_model_two_layer(unitsCount,activationFunction1,activationFunction2):
	input=Input(shape=(1,),name="input")
	dense1=Dense(units=unitsCount,name="dense1",activation=activationFunction1)(input)
	dense2=Dense(units=unitsCount,name="dense2",activation=activationFunction2)(dense1)
	output=Dense(units=1,name="denseOutput")(dense2)
	model=Model(input,output)
	return model

def run_train_and_test(startvalue_of_x,endValue_of_x,step_value,function,unitsCount,activationFunctionName):
    X,Y=get_data(startvalue_of_x,endValue_of_x,step_value,function)
    model=get_dense_model(unitsCount,activationFunctionName)
    model.compile(optimizer="adam", loss=losses.mean_absolute_error, metrics=[losses.mean_absolute_error])
    model.fit(X,Y,batch_size=50,epochs=1000)   
    result=model.predict(X)
    plt.plot(X,Y)
    plt.plot(X,result,'--')
    plt.show()

def Pow_x_2(x):
    return np.power(x,2)

def fun1(x):
    return np.power(x,2)*np.cos(x)*np.sin(x)-20*x-300
def fun2(x):
    return np.power(x,-1)

def run_train_and_test(startvalue_of_x,endValue_of_x,step_value,function,unitsCount,activationFunctionName1,activationFunctionName2):
    X,Y=get_data(startvalue_of_x,endValue_of_x,step_value,function)
    model=get_dense_model_two_layer(unitsCount,activationFunctionName1,activationFunctionName2)
    model.compile(optimizer="adam", loss=losses.mean_squared_error, metrics=[losses.mean_absolute_error])
    model.fit(X,Y,batch_size=50,epochs=200)   
    result=model.predict(X)
    print(X)
    print(Y)
    plt.plot(X,Y)
    plt.plot(X,result,'--')
    plt.show()
   
if __name__ == "__main__":
    run_train_and_test(0,10*np.pi,0.01,np.cos,100,"softplus","softplus")#cos
    run_train_and_test(0,10*np.pi,0.01,Pow_x_2,100,"softplus","softplus")#x的平方   
    run_train_and_test(1,1000,1.0,fun2,100,"softplus","softplus")#1/x
    run_train_and_test(0,10*np.pi,0.01,fun1,100,"softplus","softplus")#复杂一点的函数
    

如果要拟合更为复杂的函数,实践上应该将每个变量先经过一个神经网变换,再合并送入网络效果会更好一些。比如以下代码,将六个输入先经过神经网变换,然后合并成一个newinput,再作为输入去拟合,效果比较好。

def get_convert_x_model():
    input=Input(shape=(1,))
    dense11=Dense(activation='softplus',units=100)(input)
    dense12=Dense(activation='softplus',units=100)(dense11)
    newinput1=Dense(units=100)(dense12)
    model=Model(input,newinput1)
    return model

input1=Input(shape=(1,))
input2=Input(shape=(1,))
input3=Input(shape=(1,))
input4=Input(shape=(1,))
input5=Input(shape=(1,))
input6=Input(shape=(1,))

newinput1=get_convert_x_model()(input1)
newinput2=get_convert_x_model()(input2)
newinput3=get_convert_x_model()(input3)
newinput4=get_convert_x_model()(input4)
newinput5=get_convert_x_model()(input5)
newinput6=get_convert_x_model()(input6)

newinput=[newinput1,newinput2,newinput3,newinput4,newinput5,newinput6]
newinput=keras.layers.concatenate(newinput,axis=-1) 

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐