<>delphi 2005下编译通过。支持变学习率。具有通用性,传递函数可自己写(动态调用)。</P>
<>下面是程序和使用的例子。学习《人工智能与专家系统》时写的。</P>
<>//////////////////主程序////////////////////////</P>
<P>program BP;<BR>{<BR> 输入文件:BP.in<BR> 第一行:DLL文件名<BR> 第二行:layer_count, n(1), n(2), ... , n(layer_count) ;n(i) <--第i层神经元个数<BR> 第三行:允许误差ε 学习率η 学习实例个数N 附加测试输入个数M 迭代次数(若0则不计迭代次数) 最低学习率min_yita<BR> // 若迭代次数为零,则最低学习率可以不用写<BR> // 若迭代次数不为零,则学习率为最高学习率,且必须输入最低学习率<BR> 接下来是学习实例,每个学习实例2行:<BR> 第一行:输入的n(1)个数<BR> 第二行:期望的输出<BR> 再接下来是M个测试输入<BR> 测试输入<BR> N<=40,M<=100<BR> n(i)<=10<BR> 3<=layer_count<=10<BR> 0<η<1,推荐0.3<=η<=0.9<BR> 输入:[0,1]</P>
<P> 注意:误差E[j,k]=1/2*(y*[j,k]-y[j,k])^2<=ε</P>
<P> 输出文件:BP.out<BR> 第一行:总迭代次数<BR> 接下来N行:对应每个学习实例的输出和测试输入的输出<BR> 接下来为所有权值<BR>}</P>
<P>uses<BR> SysUtils,<BR> Windows,<BR> ClassFunctionsUnit in 'ClassFunctionsUnit.pas';</P>
<P>{ Global Variables }</P>
<P>var<BR> yita,epsilon,min_yita,delta_yita:Extended;<BR> layer_count,t,k,instance_count,total_time,ExtraCount:integer;<BR> // t - 迭代次数,k - 学习实例序号,total_time - 总迭代次数<BR> func:TFunctions;<BR> n:array[1..10] of integer; // 每层的神经元个数<BR> instances:array[1..140] of record // 学习实例 <BR> X,Y:array[1..10] of Extended;<BR> end;</P>
<P> W:array[1..9] of array[1..10,1..10] of Extended;<BR> IO_map:array[1..10,1..10] of record<BR> I,Extended;<BR> end;<BR> E:array[1..10] of Extended; // E - 神经网络输出误差<BR> delta:array[1..10,1..10] of Extended;</P>
<P>{ Global Procedures }</P>
<P> procedure LoadFromFile;<BR> var F:TextFile;<BR> FileName:String;<BR> i,j:integer;<BR> begin<BR> AssignFile(F,'BP.in');<BR> Reset(F);<BR> Readln(F,FileName);</P>
<P> func:=TFunctions.Create(FileName);</P>
<P> Read(F,layer_count);</P>
<P> for i:=1 to layer_count do<BR> read(f,n);<BR> Readln(F);</P>
<P> Read(F,epsilon);<BR> read(F,yita);<BR> Read(F,instance_count);<BR> Read(F,ExtraCount);<BR> Read(F,total_time);<BR> if total_time>0 then Read(F,min_yita);<BR> Readln(F);</P>
<P> for i:=1 to instance_count do<BR> begin<BR> for j:=1 to n[1] do<BR> read(f,instances.X[j]);<BR> Readln(F);<BR> for j:=1 to n[layer_count] do<BR> read(F,Instances.Y[j]);<BR> Readln(F);<BR> end;<BR> if ExtraCount>0 then<BR> for i:=instance_count+1 to ExtraCount+instance_count do<BR> begin<BR> for j:=1 to n[1] do<BR> read(f,instances.X[j]);<BR> Readln(F);<BR> end;</P>
<P> CloseFile(F);<BR> end;</P>
<P> procedure MapIO;forward;</P>
<P> procedure WriteResultToFile;<BR> var F:TextFile;<BR> i,j,r:integer;<BR> begin<BR> AssignFile(F,'BP.out');<BR> Rewrite(F);<BR> Writeln(F,t-1);<BR> //for k:=1 to instance_count do<BR> k:=1;<BR> while k<=instance_count+ExtraCount do<BR> begin<BR> MapIO;<BR> if n[1]>1 then<BR> for i:=1 to n[1]-1 do<BR> write(F,Format('%f,',[Instances[k].X]));<BR> write(F,Format('%f',[Instances[k].X[n[1]]]));<BR> write(F,' --> ');<BR> if n[layer_count]>1 then<BR> for i:=1 to n[layer_count]-1 do<BR> write(F,Format('%f,',[IO_map[layer_count,i].O]));<BR> writeln(F,Format('%f',[IO_map[layer_count,n[layer_count]].O]));<BR> k:=k+1;<BR> end;<BR> for i:=1 to layer_count-1 do<BR> for j:=1 to n do<BR> for r:=1 to n[i+1] do<BR> Writeln(F,Format('w(%d,%d->%d,%d): %f',[i,j,i+1,r,W[j,r]]));<BR> CloseFile(F);<BR> end;</P>
<P> procedure Init;<BR> var i,j,r:integer;<BR> begin<BR> // init W<BR> for i:=1 to layer_count-1 do<BR> for j:=1 to n do<BR> for r:=1 to n[i+1] do<BR> W[j,r]:=Random(100)/1000;<BR> //init t,k<BR> t:=1;<BR> k:=1;<BR> // init delta_yita<BR> if total_time>0 then<BR> delta_yita:=(yita-min_yita)/total_time<BR> else delta_yita:=0;<BR> end;</P>
<P> function computeIn(layer,q:integer):Extended;<BR> { TEST OK }<BR> // 计算layer层第q个神经元的输入<BR> var j:integer;<BR> a,b:Extended;<BR> begin<BR> if layer=1 then<BR> begin<BR> Result:=Instances[k].X[q];<BR> Exit;<BR> end;</P>
<P> Result:=0;<BR> for j:=1 to n[layer-1] do<BR> begin<BR> a:=IO_map[layer-1,j].O;<BR> b:=W[layer-1][j,q];<BR> Result:=Result+a*b;<BR> end;<BR> end;</P>
<P> { MapIO 搞定所有神经元的输入输出值 }<BR> procedure MapIO;<BR> var i,j:integer;<BR> begin<BR> for i:=1 to layer_count do<BR> for j:=1 to n do<BR> begin<BR> IO_map[i,j].I:=computeIn(i,j);<BR> if i=1 then<BR> IO_map[i,j].=func.layer1(IO_map[i,j].I)<BR> else begin<BR> if i=layer_count then<BR> IO_map[i,j].=func.last_layer(IO_map[i,j].I)<BR> else IO_map[i,j].=func.middle_layer(IO_map[i,j].I);<BR> end;<BR> end;<BR> end;</P>
<P> { computeE 计算神经网络的输出误差,在<BR> 调用该过程前要先MapIO }<BR> procedure computeE;<BR> var i:integer;<BR> begin<BR> for i:=1 to n[layer_count] do<BR> E:=sqr(Instances[k].Y-IO_map[layer_count,i].O)/2;<BR> end;</P>
<P> procedure computeDelta;<BR> { maybe test OK }<BR> var i,j,r:integer;<BR> x:Extended;<BR> begin<BR> for i:=1 to n[layer_count] do<BR> delta[layer_count,i]:=(IO_map[layer_count,i].O-Instances[k].Y)*<BR> func.d_last_layer(IO_map[layer_count,i].I);<BR> for i:=layer_count-1 downto 1 do<BR> for j:=1 to n do<BR> begin<BR> x:=0;<BR> for r:=1 to n[i+1] do<BR> x:=x+delta[i+1,r]*W[j,r];<BR> if i>1 then<BR> // middle layer<BR> x:=x*func.d_middle_layer(IO_map[i,j].I)<BR> else // first layer<BR> x:=x*func.d_layer1(IO_map[i,j].I);<BR> delta[i,j]:=x;<BR> end;<BR> end;</P>
<P> procedure makeWChange;<BR> { maybe Test OK }<BR> var deltaW:Extended;<BR> i,j,r:integer;<BR> begin<BR> for i:=1 to layer_count-1 do<BR> for j:=1 to n do<BR> for r:=1 to n[i+1] do<BR> begin<BR> deltaW:=-yita*delta[i+1,r]*IO_map[i,j].O;<BR> W[j,r]:=W[j,r]+deltaW;<BR> end;<BR> end;</P>
<P> function isInRange:Boolean;<BR> var i:integer;<BR> begin<BR> Result:=True;<BR> for i:=1 to n[layer_count] do<BR> if E>epsilon then begin Result:=False; break; end;<BR> end;</P>
<P> function isAllInRange:Boolean;<BR> var old_k:integer;<BR> begin<BR> old_k:=k;<BR> k:=1;<BR> Result:=True;<BR> while (k<=instance_count)and(k<>old_k) do<BR> // 增加几行代码,减少了不少不必要的浮点运算 <BR> begin<BR> MapIO;<BR> computeE;<BR> if not isInRange then<BR> begin<BR> Result:=False;<BR> Break;<BR> end;<BR> k:=k+1;<BR> end;<BR> k:=old_k;<BR> MapIO;<BR> computeE;<BR> if not isInRange then<BR> Result:=False;<BR> end;</P>
<P> procedure MainCompute;<BR> begin<BR> while true do<BR> begin<BR> if (total_time>0) and (t>total_time) then break;<BR> if isAllInRange then Break;<BR>// MapIO; <-- included in isAllInRange<BR>// computeE;<BR> computeDelta;<BR> makeWChange;<BR> t:=t+1;<BR> k:=((k+1) mod instance_count)+1;<BR> yita:=yita-delta_yita;<BR> end;<BR> end;</P>
<P>begin<BR>Randomize;<BR>LoadFromFile;</P>
<P>Init;<BR>MainCompute;</P>
<P>WriteResultToFile;</P>
<P>func.Free;<BR>end.</P>
<P>////////////////////file: ClassFunctionsUnit.pas/////////////////////////</P>
<P>unit ClassFunctionsUnit;</P>
<P>interface</P>
<P>type<BR> TFunction=function (input:Extended):Extended;stdcall;</P>
<P> TFunctions=class // 这个类定义了所有的传递函数以及他们的导数<BR> private<BR> DLLHandle:Cardinal;<BR> public<BR> layer1:TFunction; //输入层传递函数<BR> d_layer1:TFunction; //输入层传递函数的导数<BR> middle_layer:TFunction; //隐层传递函数<BR> d_middle_layer:TFunction; //隐层传递函数的导数<BR> last_layer:TFunction; //输出层传递函数<BR> d_last_layer:TFunction; //输出层传递函数的导数<BR> //所有的这些都是在Create的时候从动态连接库导入<BR> //若DLL读入失败,则使用默认<BR> constructor Create(DLLFileName:string);<BR> destructor Destroy;override;<BR> end;</P>
<P>implementation</P>
<P>uses Windows;</P>
<P>{ Default Functions }</P>
<P>function TDefaultFunctions_d_last_layer(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1;<BR>end;</P>
<P>function TDefaultFunctions_d_layer1(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1;<BR>end;</P>
<P>function TDefaultFunctions_d_middle_layer(input: Extended): Extended;stdcall;<BR>var ex,ex2:Extended;<BR>begin<BR>ex:=exp(-input);<BR>ex2:=1+ex;<BR>Result:=ex/(ex2*ex2);<BR>end;</P>
<P>function TDefaultFunctions_last_layer(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=input;<BR>end;</P>
<P>function TDefaultFunctions_layer1(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=input;<BR>end;</P>
<P>function TDefaultFunctions_middle_layer(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1/(1+exp(-input));<BR>end;</P>
<P>{ TFuncions }</P>
<P>constructor TFunctions.Create(DLLFileName: string);<BR> procedure LoadDefault;<BR> begin<BR> layer1:=TDefaultFunctions_layer1;<BR> d_layer1:=TDefaultFunctions_d_layer1;<BR> middle_layer:=TDefaultFunctions_middle_layer;<BR> d_middle_layer:=TDefaultFunctions_d_middle_layer;<BR> last_layer:=TDefaultFunctions_last_layer;<BR> d_last_layer:=TDefaultFunctions_d_last_layer;</P>
<P> DLLHandle:=0;<BR> end;<BR>begin<BR>DLLHandle:=LoadLibrary(PAnsiChar(DLLFileName));</P>
<P>if DLLHandle=0 then<BR> begin<BR> LoadDefault;<BR> Exit;<BR> end;</P>
<P>// load from dll<BR>@layer1:=GetProcAddress(DLLHandle,'layer1');<BR>@d_layer1:=GetProcAddress(DLLHandle,'d_layer1');<BR>@middle_layer:=GetProcAddress(DLLHandle,'middle_layer');<BR>@d_middle_layer:=GetProcAddress(DLLHandle,'d_middle_layer');<BR>@last_layer:=GetProcAddress(DLLHandle,'last_layer');<BR>@d_last_layer:=GetProcAddress(DLLHandle,'d_last_layer');<BR>end;</P>
<P>destructor TFunctions.Destroy;<BR>begin<BR> if DLLHandle=0 then<BR> FreeLibrary(DLLHandle);<BR> inherited;<BR>end;</P>
<P><BR>end.</P>
<P>//////////////使用例子1 - BP.in//////////////////</P>
<P><BR>3 1 3 1<BR>0.000000000001 0.3 3 11 100000<BR>1<BR>-5.874<BR>2<BR>-5.994<BR>0.5<BR>-5.469<BR>3<BR>4<BR>-5<BR>6<BR>-7<BR>8<BR>-0.9<BR>0.25<BR>0.75<BR>-1<BR>-1.24<BR></P>
<P>////////////////////使用例子2 - BP.in/////////////////////</P>
<P>BPTest3.dll<BR>4 2 3 3 2<BR>0.00000001 0.3 20 0 1000000 0.3<BR>0.05 0.02<BR>1 0<BR>0.09 0.11<BR>1 0<BR>0.12 0.20<BR>1 0<BR>0.15 0.22<BR>1 0<BR>0.20 0.25<BR>1 0<BR>0.75 0.75<BR>0 1<BR>0.80 0.83<BR>0 1<BR>0.82 0.80<BR>0 1<BR>0.90 0.89<BR>0 1<BR>0.95 0.89<BR>0 1<BR>0.09 0.04<BR>1 0<BR>0.10 0.10<BR>1 0<BR>0.14 0.21<BR>1 0<BR>0.18 0.24<BR>1 0<BR>0.22 0.28<BR>1 0<BR>0.77 0.78<BR>0 1<BR>0.79 0.81<BR>0 1<BR>0.84 0.82<BR>0 1<BR>0.94 0.93<BR>0 1<BR>0.98 0.99<BR>0 1</P>
<P>///////////////BPTest3.dll 源程序////////////////////</P>
<P>library BPTest3;</P>
<P>function layer1(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=input;<BR>end;</P>
<P>function middle_layer(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1/(1+exp(-input));<BR>end;</P>
<P>function last_layer(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1/(1+exp(-input));<BR>end;</P>
<P>function d_layer1(input: Extended): Extended;stdcall;<BR>begin<BR>Result:=1;<BR>end;</P>
<P>function d_middle_layer(input: Extended): Extended;stdcall;<BR>var ex,ex2:Extended;<BR>begin<BR>ex:=exp(-input);<BR>ex2:=1+ex;<BR>Result:=ex/(ex2*ex2);<BR>end;</P>
<P>function d_last_layer(input: Extended): Extended;stdcall;<BR>var ex,ex2:Extended;<BR>begin<BR>ex:=exp(-input);<BR>ex2:=1+ex;<BR>Result:=ex/(ex2*ex2);<BR>end;</P>
<P>exports<BR> layer1,<BR> middle_layer,<BR> last_layer,<BR> d_layer1,<BR> d_middle_layer,<BR> d_last_layer;</P>
<P>begin<BR>end.</P>
<P>多多指教</P> |