?? neuralnet.cs
字號:
using System;
using System.Collections.Generic;
using System.Text;
namespace ValidationCode
{
public class NeuralNet
{
//相關系數
const double momentum = 0;
//最小均方誤差
const double minex = 0.001;
//BP網絡隱層結點的數目
const int hidden = 10;
//訓練步長
const double eta = 0.015;
//網絡輸出層結點的個數
const int output = 4;
//輸入層結點個數,,待識別圖片的像素點個數
const int input = 156;
//理想輸出模板
static double[] output0 = { 0.1, 0.1, 0.1, 0.1 };
static double[] output1 = { 0.1, 0.1, 0.1, 0.9 };
static double[] output2 = { 0.1, 0.1, 0.9, 0.1 };
static double[] output3 = { 0.1, 0.1, 0.9, 0.9 };
static double[] output4 = { 0.1, 0.9, 0.1, 0.1 };
static double[] output5 = { 0.1, 0.9, 0.1, 0.9 };
static double[] output6 = { 0.1, 0.9, 0.9, 0.1 };
static double[] output7 = { 0.1, 0.9, 0.9, 0.9 };
static double[] output8 = { 0.9, 0.1, 0.1, 0.1 };
static double[] output9 = { 0.9, 0.1, 0.1, 0.9 };
static double[][] outnumber = { output0, output1, output2, output3, output4, output5, output6, output7, output8, output9 };
//指向輸入層于隱層之間權值的指針
static double[][] input_weights;
//指向隱層與輸出層之間的權值的指針
static double[][] hidden_weights;
//指向上一此輸入層于隱層之間權值的指針
static double[][] input_prev_weights;
//指向上一此隱層與輸出層之間的權值的指針
static double[][] hidden_prev_weights;
static NeuralNet()
{
ran = new Random();
input_weights = new double[input + 1][];
hidden_weights = new double[hidden + 1][];
input_prev_weights = new double[input + 1][];
hidden_prev_weights = new double[hidden + 1][];
//對各種權值進行初始化
randomize_weights(input_weights, input, hidden);
randomize_weights(hidden_weights, hidden, output);
zero_weights(input_prev_weights, input, hidden);
zero_weights(hidden_prev_weights, hidden, output);
}
static double squash(double x)
{
return (1.0 / (1.0 + Math.Exp(-x)));
}
//生成-1~1的隨機數
static Random ran;
static double getrandom()
{
double a = ran.NextDouble();
double b = ran.NextDouble();
return a - b;
}
/// <summary>
/// 隨機初始化權值
/// </summary>
/// <param name="w"></param>
/// <param name="m"></param>
/// <param name="n"></param>
static void randomize_weights(double[][] w, int m, int n)
{
for (int i = 0; i <= m; i++)
{
double[] temp = new double[n + 1];
for (int j = 0; j <= n; j++)
temp[j] = getrandom();
w[i] = temp;
}
}
/// <summary>
/// 0初始化權值
/// </summary>
/// <param name="?"></param>
/// <param name="m"></param>
/// <param name="n"></param>
static void zero_weights(double[][] w, int m, int n)
{
for (int i = 0; i <= m; i++)
{
double[] temp = new double[n + 1];
for (int j = 0; j <= n; j++)
temp[j] = 0.0;
w[i] = temp;
}
}
/// <summary>
/// 前向傳輸
/// </summary>
/// <param name="l1"></param>
/// <param name="l2"></param>
/// <param name="conn"></param>
/// <param name="n1"></param>
/// <param name="n2"></param>
static void LayerForward(double[] curr, double[] next, double[][] weights, int n1, int n2)
{
double sum;
/*** 設置偏置對應輸入層值 ***/
curr[0] = 1.0;
/*** 對于第二層的每個神經元 ***/
for (int j = 1; j <= n2; j++)
{
/*** 計算輸入的加權總和 ***/
sum = 0.0;
for (int k = 0; k <= n1; k++)
sum += weights[k][j] * curr[k];
next[j] = squash(sum);
}
}
/// <summary>
/// 輸出誤差
/// </summary>
/// <param name="delta"></param>
/// <param name="target"></param>
/// <param name="output"></param>
/// <param name="nj"></param>
static void OutputError(double[] delta, double[] target, double[] output, int nj)
{
double o, t;
for (int j = 1; j <= nj; j++)
{
o = output[j];
t = target[j];
delta[j] = o * (1.0 - o) * (t - o);
}
}
/// <summary>
/// 隱含層誤差
/// </summary>
/// <param name="delta_h"></param>
/// <param name="nh"></param>
/// <param name="delta_o"></param>
/// <param name="no"></param>
/// <param name="who"></param>
/// <param name="hidden"></param>
static void HiddenError(double[] delta_h, int nh, double[] delta_o, int no, double[][] weights, double[] hidden)
{
double h, sum;
for (int j = 1; j <= nh; j++)
{
h = hidden[j];
sum = 0.0;
for (int k = 1; k <= no; k++)
sum += delta_o[k] * weights[j][k];
delta_h[j] = h * (1.0 - h) * sum;
}
}
/* 調整權值 */
static void AdjustWeights(double[] delta, int ndelta, double[] ly, int nly, double[][] w, double[][] oldw, double eta, double momentum)
{
double new_dw;
ly[0] = 1.0;
for (int j = 1; j <= ndelta; j++)
{
for (int k = 0; k <= nly; k++)
{
new_dw = ((eta * delta[j] * ly[k]) + (momentum * oldw[k][j]));
w[k][j] += new_dw;
oldw[k][j] = new_dw;
}
}
}
/// <summary>
/// 根據輸入的特征向量和期望的理想輸出向量對BP網絡盡行訓練,訓練結束后將權值保存
/// </summary>
/// <param name="data_in">輸入的特征向量</param>
/// <param name="data_out">理想輸出特征向量</param>
public static bool Train(List<List<double>> data_in, List<int> data_out)
{
//循環變量
int i, l, k, flag;
//指向輸入層數據的指針
double[] input_layer = new double[input + 1];
//指向隱層數據的指針
double[] hidden_layer = new double[input + 1];
//指向輸出層數據的指針
double[] output_layer = new double[hidden + 1];
//指向隱層誤差數據的指針
double[] hidden_deltas = new double[hidden + 1];
//指向輸出層誤差數劇的指針
double[] output_deltas = new double[output + 1];
//指向理想目標輸出的指針
double[] target = new double[output + 1];
//每次循環后的均方誤差誤差值
double ex = double.MaxValue;
//開始進行BP網絡訓練
//這里設定最大的迭代次數為15000次
for (l = 0; l < 15000; l++)
{
//對均方誤差置零
ex = 0;
for (k = 0; k < data_in.Count; k++)
{
//將提取的樣本的特征向量輸送到輸入層上
for (i = 1; i <= input; i++)
input_layer[i] = data_in[k][i - 1];
flag = data_out[k];
//將預定的理想輸出輸送到BP網絡的理想輸出單元
for (i = 1; i <= output; i++)
target[i] = outnumber[flag][i - 1];
//前向傳輸激活
//將數據由輸入層傳到隱層
LayerForward(input_layer, hidden_layer, input_weights, input, hidden);
//將隱層的輸出傳到輸出層
LayerForward(hidden_layer, output_layer, hidden_weights, hidden, output);
//誤差計算
//將輸出層的輸出與理想輸出比較計算輸出層每個結點上的誤差
OutputError(output_deltas, target, output_layer, output);
//根據輸出層結點上的誤差計算隱層每個節點上的誤差
HiddenError(hidden_deltas, hidden, output_deltas, output, hidden_weights, hidden_layer);
//權值調整
//根據輸出層每個節點上的誤差來調整隱層與輸出層之間的權值
AdjustWeights(output_deltas, output, hidden_layer, hidden, hidden_weights, hidden_prev_weights, eta, momentum);
//根據隱層每個節點上的誤差來調整隱層與輸入層之間的權值
AdjustWeights(hidden_deltas, hidden, input_layer, input, input_weights, input_prev_weights, eta, momentum);
//誤差統計
for (i = 1; i <= output; i++)
ex = (output_layer[i] - outnumber[flag][i - 1]) * (output_layer[i] - outnumber[flag][i - 1]);
}
ex = ex / Convert.ToDouble(data_in.Count*output);
if (ex < minex) break;
}
if (ex <= minex)
return true;
else
return false;
}
///<summary>
///讀入輸入樣本的特征相量并根據訓練所得的權值,進行識別
///</summary>
///<param name="data_in"></param>
public static int Recognize(List<double> data_in)
{
int i, result;
result = 0;
//指向輸入層數據的指針
double[] input_layer = new double[input + 1];
//指向隱層數據的指針
double[] hidden_layer = new double[input + 1];
//指向輸出層數據的指針
double[] output_layer = new double[hidden + 1];
//將提取的樣本的特征向量輸送到輸入層上
for (i = 1; i <= input; i++)
input_layer[i] = data_in[i - 1];
//前向輸入激活
LayerForward(input_layer, hidden_layer, input_weights, input, hidden);
LayerForward(hidden_layer, output_layer, hidden_weights, hidden, output);
//考察每一位的輸出
//如果大于0.5判為1
for (i = 1; i <= output; i++)
{
if (output_layer[i] > 0.5)
result += (int)Math.Pow(2, Convert.ToDouble(4 - i));
}
return result;
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -