由于Rosenblatt感知器的局限性,对于非线性分类的效果不理想。为了对线性分类无法区分的数据进行分类,需要构建多层感知器结构对数据进行分类,多层感知器结构如下:
该网络由输入层,隐藏层,和输出层构成,能表示种类繁多的非线性曲面,每一个隐藏层都有一个激活函数,将该单元的输入数据与权值相乘后得到的值(即诱导局部域)经过激活函数,激活函数的输出值作为该单元的输出,激活函数类似与硬限幅函数,但硬限幅函数在阈值处是不可导的,而激活函数处处可导。本次程序中使用的激活函数是tanh函数,公式如下:
tanh函数的图像如下:
程序中具体的tanh函数形式如下:
就是神经元j的诱导局部域
它的局部梯度分两种情况:
(1)神经元j没有位于隐藏层:
(2)神经元j位于隐藏层:
其中k是单元j后面相连的所有的单元。
局部梯度得到之后,根据增量梯度下降法的权值更新法则
即可得到下一次的权值w,经过若干次迭代,设定误差条件,即可找到权值空间的最小值。
python程序如下,为了能够可视化,训练数据采用二维数据,每一个隐藏层有8个节点,设置了7个隐藏层,一个输出层,输出层有2个单元:
import numpy as np
import random
import copy
import matplotlib.pyplot as plt
#x和d样本初始化
train_x = [[1,6],[3,12],[3,9],[3,21],[2,16],[3,15]]
d =[[1,0],[1,0],[0,1],[0,1],[1,0],[0,1]]
warray_txn=len(train_x[0])
warray_n=warray_txn*4
#基本参数初始化
oldmse=10**100
fh=1
maxtrycount=500
mycount=0.0
if maxtrycount>=20:
r=maxtrycount/5
else:
r=maxtrycount/2
#sigmoid函数
ann_sigfun=None
ann_delta_sigfun=None
#总层数初始化,比非线性导数多一层线性层
alllevel_count=warray_txn*4
# 非线性层数初始化
hidelevel_count=alllevel_count-1
#学习率参数
learn_r0=0.002
learn_r=learn_r0
#动量参数
train_a0=learn_r0*1.2
train_a=train_a0
expect_e=0.05
#对输入数据进行预处理
ann_max=[]
for m_ani in xrange(0,warray_txn):#找出训练数据中每一项的最大值
temp_x=np.array(train_x)
ann_max.append(np.max(temp_x[:,m_ani]))
ann_max=np.array(ann_max)
def getnowsx(mysx,in_w):
'''''生成本次的扩维输入数据 '''
'''''mysx==>输入数据,in_w==>权值矩阵,每一列为一个神经元的权值向量'''
global warray_n
mysx=np.array(mysx)
x_end=[]
for i in xrange(0,warray_n):
x_end.append(np.dot(mysx,in_w[:,i]))
return x_end
def get_inlw(my_train_max,w_count,myin_x):
'''''找出权值矩阵均值接近0,输出结果方差接近1的权值矩阵'''
#对随机生成的多个权值进行优化选择,选择最优的权值
global warray_txn
global warray_n
mylw=[]
y_in=[]
#生成测试权值
mylw=np.random.rand(w_count,warray_txn,warray_n)
for ii in xrange (0,warray_txn):
mylw[:,ii,:]=mylw[:,ii,:]*1/float(my_train_max[ii])-1/float(my_train_max[ii])*0.5
#计算输出
for i in xrange(0,w_count):
y_in.append([])
for xj in xrange(0,len(myin_x)):
y_in[i].append(getnowsx(myin_x[xj],mylw[i]))
#计算均方差
mymin=10**5
mychoice=0
for i in xrange(0,w_count):
myvar=np.var(y_in[i])
if abs(myvar-1)0
atanh_b=2/float(3)#>0
temp_rs=atanh_a*np.tanh(atanh_b*myv)
return temp_rs
def ann_delta_atanh(myy,myd,nowlevel,level,n,mydelta,myw):
anndelta=[]
atanh_a=1.7159#>0
atanh_b=2/float(3)#>0
if nowlevel==level:
#输出层
anndelta=(float(atanh_b)/atanh_a)*(myd-myy)*(atanh_a-myy)*(atanh_a+myy)
else:
#隐藏层
anndelta=(float(atanh_b)/atanh_a)*(atanh_a-myy)*(atanh_a+myy)
temp_rs=[]
for j in xrange(0,n):
temp_rs.append(sum(myw[j]*mydelta))
anndelta=anndelta*temp_rs
return anndelta
def sample_train(myx,myd,n,sigmoid_func,delta_sigfun):
'''''一个样本的前向和后向计算'''
global ann_yi
global ann_delta
global ann_w
global ann_wj0
global ann_y0
global hidelevel_count
global alllevel_count
global learn_r
global train_a
global ann_oldw
level=hidelevel_count
allevel=alllevel_count
#清空yi输出信号数组
hidelevel=hidelevel_count
alllevel=alllevel_count
for i in xrange(0,alllevel):
#第一维是层数,从0开始
for j in xrange(0,n):
#第二维是神经元
ann_yi[i][j]=0.0
ann_yi=np.array(ann_yi)
yi=ann_yi
#清空delta矩阵
for i in xrange(0,hidelevel-1):
for j in xrange(0,n):
ann_delta[i][j]=0.0
delta=ann_delta
#保留W的拷贝,以便下一次迭代
ann_oldw=copy.deepcopy(ann_w)
oldw=ann_oldw
#前向计算
#对输入变量进行预处理
myo=np.array([])
for nowlevel in xrange(0,alllevel):
#一层层向前计算
#计算诱导局部域
my_y=[]
myy=yi[nowlevel-1]
myw=ann_w[nowlevel-1]
if nowlevel==0:
#第一层隐藏层
my_y=myx
yi[nowlevel]=my_y
elif nowlevel==(alllevel-1):
#输出层
my_y=o_func(yi[nowlevel-1,:len(myd)])
yi[nowlevel,:len(myd)]=my_y
elif nowlevel==(hidelevel-1):
#最后一层输出层
for i in xrange(0,len(myd)):
temp_y=sigmoid_func(np.dot(myw[:,i],myy))
my_y.append(temp_y)
yi[nowlevel,:len(myd)]=my_y
else:
#中间隐藏层
for i in xrange(0,len(myy)):
temp_y=sigmoid_func(np.dot(myw[:,i],myy))
my_y.append(temp_y)
yi[nowlevel]=my_y
#计算误差与均方误差
myo=yi[hidelevel-1][:len(myd)]
myo_end=yi[alllevel-1][:len(myd)]
mymse=get_e(myd,myo_end)
#反向计算
#输入层不需要计算delta,输出层不需要计算W
#计算delta
for nowlevel in xrange(level-1,0,-1):
if nowlevel==level-1:
mydelta=delta[nowlevel]
my_n=len(myd)
else:
mydelta=delta[nowlevel+1]
my_n=n
myw=ann_w[nowlevel]
if nowlevel==level-1:
#输出层
mydelta=delta_sigfun(myo,myd,None,None,None,None,None)
## mydelta=mymse*myo
elif nowlevel==level-2:
#输出隐藏层的前一层,因为输出结果和前一层隐藏层的神经元数目可能存在不一致
#所以单独处理,传相当于输出隐藏层的神经元数目的数据
mydelta=delta_sigfun(yi[nowlevel],myd,nowlevel,level-1,my_n,mydelta[:len(myd)],myw[:,:len(myd)])
else:
mydelta=delta_sigfun(yi[nowlevel],myd,nowlevel,level-1,my_n,mydelta,myw)
delta[nowlevel][:my_n]=mydelta
#计算与更新权值W
for nowlevel in xrange(level-1,0,-1):
#每个层的权值不一样
if nowlevel==level-1:
#输出层
my_n=len(myd)
mylearn_r=learn_r*0.8
mytrain_a=train_a*1.6
elif nowlevel==1:
#输入层
my_n=len(myd)
mylearn_r=learn_r*0.9
mytrain_a=train_a*0.8
else:
#其它层
my_n=n
mylearn_r=learn_r
mytrain_a=train_a
pre_level_myy=yi[nowlevel-1]
pretrain_myww=oldw[nowlevel-1]
pretrain_myw=pretrain_myww[:,:my_n]
#第二个调整参数
temp_i=[]
for i in xrange(0,n):
temp_i.append([])
for jj in xrange(0,my_n):
temp_i[i].append(mylearn_r*delta[nowlevel,jj]*pre_level_myy[i])
temp_rs2=np.array(temp_i)
temp_rs1=mytrain_a*pretrain_myw
#总调整参数
temp_change=temp_rs1+temp_rs2
my_ww=ann_w[nowlevel-1]
my_ww[:,:my_n]+=temp_change
return mymse
def train_update(level,nowtraincount,sigmoid_func,delta_sigfun):
'''''一次读取所有样本,然后迭代一次进行训练'''
#打乱样本顺序
global learn_r
global train_a
global train_a0
global learn_r0
global r
global x
global d
global maxtrycount
global oldmse
x_n=len(x)
ids=range(0,x_n)
train_ids=[]
sample_x=[]
sample_d=[]
while len(ids)>0:
myxz=random.randint(0,len(ids)-1)
train_ids.append(ids[myxz])
del ids[myxz]
for i in xrange(0,len(train_ids)):
sample_x.append(x[train_ids[i]])
sample_d.append(d[train_ids[i]])
sample_x=np.array(sample_x)
sample_d=np.array(sample_d)
#读入x的每个样本,进行训练
totalmse=0.0
mymse=float(10**-10)
for i in xrange(0,x_n):
mymse=sample_train(sample_x[i],sample_d[i],warray_n,sigmoid_func,delta_sigfun)
totalmse+=sum(mymse*mymse)
totalmse=np.sqrt(totalmse/float(x_n))
print u"误差为:%f" %(totalmse)
nowtraincount[0]+=1
learn_r=learn_r0/(1+float(nowtraincount[0])/r)
train_a=train_a0/(1+float(nowtraincount[0])/r)
if nowtraincount[0]>=maxtrycount:
return False,True,totalmse
elif totalmse0.1 and (totalmse-oldmse)/oldmse<1:
print u"训练成功,正在进行检验"
totalmse=0.0
for i in xrange(0,x_n):
mytemper=(sample_d[i]-simulate(sample_x[i],sigmoid_func,delta_sigfun))
totalmse+=sum(mytemper*mytemper)
totalmse=np.sqrt(totalmse/float(x_n))
if totalmse3:
break
else:
print u"训练失败,重新尝试第%d次"%tryerr
nowtraincount[0]=0
generate_lw(15+tryerr*2)
else:
print u"训练成功,误差为:%f"%mymse
break
def simulate(myx,sigmoid_func,delta_sigfun):
'''''一个样本的仿真计算'''
print u"仿真计算中"
global ann_yi
global ann_w
global ann_wj0
global ann_y0
global hidelevel_count
global alllevel_count
global d
myd=d[0]
myx=np.array(myx)
n=len(myx)
level=hidelevel_count
allevel=alllevel_count
#清空yi输出信号数组
hidelevel=hidelevel_count
alllevel=alllevel_count
for i in xrange(0,alllevel):
#第一维是层数,从0开始
for j in xrange(0,n):
#第二维是神经元
ann_yi[i][j]=0.0
ann_yi=np.array(ann_yi)
yi=ann_yi
#前向计算
myo=np.array([])
myy=np.array([])
for nowlevel in xrange(0,alllevel):
#一层层向前计算
#计算诱导局部域
my_y=[]
myy=yi[nowlevel-1]
myw=ann_w[nowlevel-1]
if nowlevel==0:
#第一层隐藏层
my_y=myx
yi[nowlevel]=my_y
elif nowlevel==(alllevel-1):
#线性输出层,使用线性激活
my_y=o_func(yi[nowlevel-1,:len(myd)])
yi[nowlevel,:len(myd)]=my_y
elif nowlevel==(hidelevel-1):
#最后一层隐藏输出层,使用线性激活
for i in xrange(0,len(myd)):
temp_y=sigmoid_func(np.dot(myw[:,i],myy))
my_y.append(temp_y)
yi[nowlevel,:len(myd)]=my_y
else:
#中间隐藏层
#中间隐藏层需要加上偏置
for i in xrange(0,len(myy)):
temp_y=sigmoid_func(np.dot(myw[:,i],myy))
my_y.append(temp_y)
yi[nowlevel]=my_y
return yi[alllevel-1,:len(myd)]
train()
delta_sigfun=ann_delta_atanh
sigmoid_func=ann_atanh
for xn in xrange(0,len(x)):
if simulate(x[xn],sigmoid_func,delta_sigfun)[0]>0:
plt.plot(train_x[xn][0],train_x[xn][1],"bo")
else:
plt.plot(train_x[xn][0],train_x[xn][1],"b*")
temp_x=np.random.rand(20)*10
temp_y=np.random.rand(20)*20+temp_x
myx=temp_x
myy=temp_y
plt.subplot(111)
x_max=np.max(myx)+5
x_min=np.min(myx)-5
y_max=np.max(myy)+5
y_min=np.min(myy)-5
plt.xlim(x_min,x_max)
plt.ylim(y_min,y_max)
for i in xrange(0,len(myx)):
test=get_siminx([[myx[i],myy[i]]])
if simulate(test,sigmoid_func,delta_sigfun)[0]>0:
plt.plot(myx[i],myy[i],"ro")
else:
plt.plot(myx[i],myy[i],"r*")
plt.show()
图中蓝色是训练数据,红色是测试数据,圈圈代表类型[1,0],星星代表类型[0,1]。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



