類:
using System;using System.IO;using System.Text;namespace BpANNet{ /// <summary> /// BpNet 的摘要說明。 /// </summary> public class BpNet { public int inNum;//輸入節點數 int hideNum;//隱層節點數 public int outNum;//輸出層節點數 public int sampleNum;//樣本總數 Random R; double[] x;//輸入節點的輸入資料 double[] x1;//隱層節點的輸出 double[] x2;//輸出節點的輸出 double[] o1;//隱層的輸入 double[] o2;//輸出層的輸入 public double[,] w;//權值矩陣w public double[,] v;//權值矩陣V public double[,] dw;//權值矩陣w public double[,] dv;//權值矩陣V public double rate;//學習率 public double[] b1;//隱層閾值矩陣 public double[] b2;//輸出層閾值矩陣 public double[] db1;//隱層閾值矩陣 public double[] db2;//輸出層閾值矩陣 double[] pp;//輸出層的誤差 double[] qq;//隱層的誤差 double[] yd;//輸出層的教師資料 public double e;//均方誤差 double in_rate;//歸一化比例係數 public int computeHideNum(int m, int n) { double s = Math.Sqrt(0.43 * m * n + 0.12 * n * n + 2.54 * m + 0.77 * n + 0.35) + 0.51; int ss = Convert.ToInt32(s); return ((s - (double)ss) > 0.5) ? ss + 1 : ss; } public BpNet(double[,] p, double[,] t) { // 建構函式邏輯 R = new Random(); this.inNum = p.GetLength(1); //數組第二維大小 為 輸入節點數 this.outNum = t.GetLength(1); //輸出節點數 this.hideNum = computeHideNum(inNum, outNum); //隱藏節點數,不知其原理 // this.hideNum=18; this.sampleNum = p.GetLength(0); //數組第一維大小 為 樣本總數 Console.WriteLine("輸入節點數目: " + inNum); Console.WriteLine("隱層節點數目:" + hideNum); Console.WriteLine("輸出層節點數目:" + outNum); Console.ReadLine(); //讀個空行 x = new double[inNum]; x1 = new double[hideNum]; x2 = new double[outNum]; o1 = new double[hideNum]; o2 = new double[outNum]; w = new double[inNum, hideNum]; v = new double[hideNum, outNum]; dw = new double[inNum, hideNum]; dv = new double[hideNum, outNum]; b1 = new double[hideNum]; b2 = new double[outNum]; db1 = new double[hideNum]; db2 = new double[outNum]; pp = new double[hideNum]; qq = new double[outNum]; yd = new double[outNum]; //初始化w for (int i = 0; i < inNum; i++) { for (int j = 0; j < hideNum; j++) { w[i, j] = (R.NextDouble() * 2 - 1.0) / 2; } } //初始化v for (int i = 0; i < hideNum; i++) { for (int j = 0; j < outNum; j++) { v[i, j] = (R.NextDouble() * 2 - 1.0) / 2; } } rate = 0.8; e = 0.0; in_rate = 1.0; } //訓練函數 public void train(double[,] p, double[,] t) { e = 0.0; //求p,t中的最大值 double pMax = 0.0; for (int isamp = 0; isamp < sampleNum; isamp++) { for (int i = 0; i < inNum; i++) { if (Math.Abs(p[isamp, i]) > pMax) { pMax = Math.Abs(p[isamp, i]); } } for (int j = 0; j < outNum; j++) { if (Math.Abs(t[isamp, j]) > pMax) { pMax = Math.Abs(t[isamp, j]); } } in_rate = pMax; }//end isamp for (int isamp = 0; isamp < sampleNum; isamp++) { //資料歸一化 for (int i = 0; i < inNum; i++) { x[i] = p[isamp, i] / in_rate; } for (int i = 0; i < outNum; i++) { yd[i] = t[isamp, i] / in_rate; } //計算隱層的輸入和輸出 for (int j = 0; j < hideNum; j++) { o1[j] = 0.0; for (int i = 0; i < inNum; i++) { o1[j] += w[i, j] * x[i]; } x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j])); } //計算輸出層的輸入和輸出 for (int k = 0; k < outNum; k++) { o2[k] = 0.0; for (int j = 0; j < hideNum; j++) { o2[k] += v[j, k] * x1[j]; } x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k])); } //計算輸出層誤差和均方差 for (int k = 0; k < outNum; k++) { qq[k] = (yd[k] - x2[k]) * x2[k] * (1.0 - x2[k]); e += (yd[k] - x2[k]) * (yd[k] - x2[k]); //更新V for (int j = 0; j < hideNum; j++) { v[j, k] += rate * qq[k] * x1[j]; } } //計算隱層誤差 for (int j = 0; j < hideNum; j++) { pp[j] = 0.0; for (int k = 0; k < outNum; k++) { pp[j] += qq[k] * v[j, k]; } pp[j] = pp[j] * x1[j] * (1 - x1[j]); //更新W for (int i = 0; i < inNum; i++) { w[i, j] += rate * pp[j] * x[i]; } } //更新b2 for (int k = 0; k < outNum; k++) { b2[k] += rate * qq[k]; } //更新b1 for (int j = 0; j < hideNum; j++) { b1[j] += rate * pp[j]; } }//end isamp e = Math.Sqrt(e); // adjustWV(w,dw); // adjustWV(v,dv); }//end train public void adjustWV(double[,] w, double[,] dw) { for (int i = 0; i < w.GetLength(0); i++) { for (int j = 0; j < w.GetLength(1); j++) { w[i, j] += dw[i, j]; } } } public void adjustWV(double[] w, double[] dw) { for (int i = 0; i < w.Length; i++) { w[i] += dw[i]; } } //資料模擬函數 public double[] sim(double[] psim) { for (int i = 0; i < inNum; i++) x[i] = psim[i] / in_rate; for (int j = 0; j < hideNum; j++) { o1[j] = 0.0; for (int i = 0; i < inNum; i++) o1[j] = o1[j] + w[i, j] * x[i]; x1[j] = 1.0 / (1.0 + Math.Exp(-o1[j] - b1[j])); } for (int k = 0; k < outNum; k++) { o2[k] = 0.0; for (int j = 0; j < hideNum; j++) o2[k] = o2[k] + v[j, k] * x1[j]; x2[k] = 1.0 / (1.0 + Math.Exp(-o2[k] - b2[k])); x2[k] = in_rate * x2[k]; } return x2; } //end sim //儲存矩陣w,v public void saveMatrix(double[,] w, string filename) { StreamWriter sw = File.CreateText(filename); for (int i = 0; i < w.GetLength(0); i++) { for (int j = 0; j < w.GetLength(1); j++) { sw.Write(w[i, j] + " "); } sw.WriteLine(); } sw.Close(); } //儲存矩陣b1,b2 public void saveMatrix(double[] b, string filename) { StreamWriter sw = File.CreateText(filename); for (int i = 0; i < b.Length; i++) { sw.Write(b[i] + " "); } sw.Close(); } //讀取矩陣W,V public void readMatrixW(double[,] w, string filename) { StreamReader sr; try { sr = new StreamReader(filename, Encoding.GetEncoding("gb2312")); String line; int i = 0; while ((line = sr.ReadLine()) != null) { string[] s1 = line.Trim().Split(' '); for (int j = 0; j < s1.Length; j++) { w[i, j] = Convert.ToDouble(s1[j]); } i++; } sr.Close(); } catch (Exception e) { // Let the user know what went wrong. Console.WriteLine("The file could not be read:"); Console.WriteLine(e.Message); } } //讀取矩陣b1,b2 public void readMatrixB(double[] b, string filename) { StreamReader sr; try { sr = new StreamReader(filename, Encoding.GetEncoding("gb2312")); String line; int i = 0; while ((line = sr.ReadLine()) != null) { b[i] = Convert.ToDouble(line); i++; } sr.Close(); } catch (Exception e) { // Let the user know what went wrong. Console.WriteLine("The file could not be read:"); Console.WriteLine(e.Message); } } }//end bpnet} //end namespace
主程式:
//主調用程式using System;namespace BpANNet{ /// <summary> /// Class1 的摘要說明。 /// </summary> class Class1 { /// <summary> /// 應用程式的主進入點。 /// </summary> [STAThread] static void Main(string[] args) { //0.1399,0.1467,0.1567,0.1595,0.1588,0.1622,0.1611,0.1615,0.1685,0.1789,0.1790 // double [,] p1=new double[,]{{0.05,0.02},{0.09,0.11},{0.12,0.20},{0.15,0.22},{0.20,0.25},{0.75,0.75},{0.80,0.83},{0.82,0.80},{0.90,0.89},{0.95,0.89},{0.09,0.04},{0.1,0.1},{0.14,0.21},{0.18,0.24},{0.22,0.28},{0.77,0.78},{0.79,0.81},{0.84,0.82},{0.94,0.93},{0.98,0.99}}; // double [,] t1=new double[,]{{1,0},{1,0},{1,0},{1,0},{1,0},{0,1},{0,1},{0,1},{0,1},{0,1},{1,0},{1,0},{1,0},{1,0},{1,0},{0,1},{0,1},{0,1},{0,1},{0,1}}; double[,] p1 = new double[,] { { 0.1399, 0.1467, 0.1567, 0.1595, 0.1588, 0.1622 }, { 0.1467, 0.1567, 0.1595, 0.1588, 0.1622, 0.1611 }, { 0.1567, 0.1595, 0.1588, 0.1622, 0.1611, 0.1615 }, { 0.1595, 0.1588, 0.1622, 0.1611, 0.1615, 0.1685 }, { 0.1588, 0.1622, 0.1611, 0.1615, 0.1685, 0.1789 } }; double[,] t1 = new double[,] { { 0.1622 }, { 0.1611 }, { 0.1615 }, { 0.1685 }, { 0.1789 }, { 0.1790 } }; BpNet bp = new BpNet(p1, t1); int study = 0; do { study++; bp.train(p1, t1); // bp.rate=0.95-(0.95-0.3)*study/50000; // Console.Write("第 "+ study+"次學習: "); // Console.WriteLine(" 均方差為 "+bp.e); } while (bp.e > 0.001 && study < 50000); Console.Write("第 " + study + "次學習: "); Console.WriteLine(" 均方差為 " + bp.e); bp.saveMatrix(bp.w, "w.txt"); bp.saveMatrix(bp.v, "v.txt"); bp.saveMatrix(bp.b1, "b1.txt"); bp.saveMatrix(bp.b2, "b2.txt"); // double [,] p2=new double[,]{{0.05,0.02},{0.09,0.11},{0.12,0.20},{0.15,0.22},{0.20,0.25},{0.75,0.75},{0.80,0.83},{0.82,0.80},{0.90,0.89},{0.95,0.89},{0.09,0.04},{0.1,0.1},{0.14,0.21},{0.18,0.24},{0.22,0.28},{0.77,0.78},{0.79,0.81},{0.84,0.82},{0.94,0.93},{0.98,0.99}}; double[,] p2 = new double[,] { { 0.1399, 0.1467, 0.1567, 0.1595, 0.1588, 0.1622 }, { 0.1622, 0.1611, 0.1615, 0.1685, 0.1789, 0.1790 } }; int aa = bp.inNum; int bb = bp.outNum; int cc = p2.GetLength(0); double[] p21 = new double[aa]; double[] t2 = new double[bb]; for (int n = 0; n < cc; n++) { for (int i = 0; i < aa; i++) { p21[i] = p2[n, i]; } t2 = bp.sim(p21); for (int i = 0; i < t2.Length; i++) { Console.WriteLine(t2[i] + " "); } } Console.ReadLine(); } }}