728x90
반응형
728x170
▶ NeuralNetwork.cs
using System;
namespace TestProject
{
/// <summary>
/// 신경망
/// </summary>
public class NeuralNetwork
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 난수 발생기
/// </summary>
private static Random _random;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 입력 노드 카운트
/// </summary>
private int inputNodeCount;
/// <summary>
/// 은닉 노드 카운트
/// </summary>
private int hiddenNodeCount;
/// <summary>
/// 출력 노드 카운트
/// </summary>
private int outputNodeCount;
/// <summary>
/// 입력 노드 값 배열
/// </summary>
private double[] inputNodeValueArray;
/// <summary>
/// 입력-은닉 가중치 배열
/// </summary>
private double[][] inputHiddenWeightArray;
/// <summary>
/// 은닉 노드 바이어스 배열
/// </summary>
private double[] hiddenNodeBiasArray;
/// <summary>
/// 은닉 노드 값 배열
/// </summary>
private double[] hiddenNodeValueArray;
/// <summary>
/// 은닉-출력 가중치 배열
/// </summary>
private double[][] hiddenOutputWeightArray;
/// <summary>
/// 출력 노드 바이어스 배열
/// </summary>
private double[] outputNodeBiasArray;
/// <summary>
/// 출력 노드 값 배열
/// </summary>
private double[] outputNodeValueArray;
/// <summary>
/// 은닉 노드 그라디언트 배열
/// </summary>
private double[] hiddenNodeGradientArray;
/// <summary>
/// 출력 노드 그라디언트 배열
/// </summary>
private double[] outputNodeGradientArray;
/// <summary>
/// 입력-은닉 이전 가중치 델타 배열
/// </summary>
private double[][] inputHiddenPreviousWeightDeltaArray;
/// <summary>
/// 은닉 노드 이전 바이어스 델타 배열
/// </summary>
private double[] hiddenNodePreviousBiasDeltaArray;
/// <summary>
/// 은닉-출력 이전 가중치 델타 배열
/// </summary>
private double[][] hiddenOutputPreviousWeightDeltaArray;
/// <summary>
/// 출력 노드 이전 바이어스 델타 배열
/// </summary>
private double[] outputNodePreviousBiasDeltaArray;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - NeuralNetwork(inputNodeCount, hiddenNodeCount, outputNodeCount)
/// <summary>
/// 생성자
/// </summary>
/// <param name="inputNodeCount">입력 노드 카운트</param>
/// <param name="hiddenNodeCount">은닉 노드 카운트</param>
/// <param name="outputNodeCount">출력 노드 카운트</param>
public NeuralNetwork(int inputNodeCount, int hiddenNodeCount, int outputNodeCount)
{
_random = new Random(0);
this.inputNodeCount = inputNodeCount;
this.hiddenNodeCount = hiddenNodeCount;
this.outputNodeCount = outputNodeCount;
this.inputNodeValueArray = new double[inputNodeCount];
this.inputHiddenWeightArray = GetMatrixArray(inputNodeCount, hiddenNodeCount);
this.hiddenNodeBiasArray = new double[hiddenNodeCount];
this.hiddenNodeValueArray = new double[hiddenNodeCount];
this.hiddenOutputWeightArray = GetMatrixArray(hiddenNodeCount, outputNodeCount);
this.outputNodeBiasArray = new double[outputNodeCount];
this.outputNodeValueArray = new double[outputNodeCount];
this.InitializeWeightArray();
this.hiddenNodeGradientArray = new double[hiddenNodeCount];
this.outputNodeGradientArray = new double[outputNodeCount];
this.inputHiddenPreviousWeightDeltaArray = GetMatrixArray(inputNodeCount, hiddenNodeCount);
this.hiddenNodePreviousBiasDeltaArray = new double[hiddenNodeCount];
this.hiddenOutputPreviousWeightDeltaArray = GetMatrixArray(hiddenNodeCount, outputNodeCount);
this.outputNodePreviousBiasDeltaArray = new double[outputNodeCount];
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 가중치 배열 구하기 - GetWeightArray()
/// <summary>
/// 가중치 배열 구하기
/// </summary>
/// <returns>가중치 배열</returns>
public double[] GetWeightArray()
{
int totalWeightCount = (this.inputNodeCount * this.hiddenNodeCount) +
(this.hiddenNodeCount * this.outputNodeCount) +
this.hiddenNodeCount + this.outputNodeCount;
double[] targetWeightArray = new double[totalWeightCount];
int k = 0;
for(int i = 0; i < this.inputNodeCount; i++)
{
for(int j = 0; j < this.hiddenNodeCount; j++)
{
targetWeightArray[k++] = this.inputHiddenWeightArray[i][j];
}
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
targetWeightArray[k++] = this.hiddenNodeBiasArray[i];
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
for(int j = 0; j < this.outputNodeCount; j++)
{
targetWeightArray[k++] = this.hiddenOutputWeightArray[i][j];
}
}
for(int i = 0; i < this.outputNodeCount; i++)
{
targetWeightArray[k++] = this.outputNodeBiasArray[i];
}
return targetWeightArray;
}
#endregion
#region 가중치 배열 설정하기 - SetWeightArray(sourceWeightArray)
/// <summary>
/// 가중치 배열 설정하기
/// </summary>
/// <param name="sourceWeightArray">소스 가중치 배열</param>
public void SetWeightArray(double[] sourceWeightArray)
{
int totalWeightCount = (this.inputNodeCount * this.hiddenNodeCount) +
(this.hiddenNodeCount * this.outputNodeCount) +
this.hiddenNodeCount + this.outputNodeCount;
if(sourceWeightArray.Length != totalWeightCount)
{
throw new Exception("잘못된 소스 가중치 배열 길이 입니다.");
}
int k = 0;
for(int i = 0; i < this.inputNodeCount; i++)
{
for(int j = 0; j < this.hiddenNodeCount; j++)
{
this.inputHiddenWeightArray[i][j] = sourceWeightArray[k++];
}
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
this.hiddenNodeBiasArray[i] = sourceWeightArray[k++];
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
for(int j = 0; j < this.outputNodeCount; j++)
{
this.hiddenOutputWeightArray[i][j] = sourceWeightArray[k++];
}
}
for(int i = 0; i < this.outputNodeCount; i++)
{
this.outputNodeBiasArray[i] = sourceWeightArray[k++];
}
}
#endregion
#region 학습하기 - Train(trainingValueArray, maximumEpochCount, learningRate, momentum)
/// <summary>
/// 학습하기
/// </summary>
/// <param name="trainingValueArray">학습 값 배열</param>
/// <param name="maximumEpochCount">최대 시대 카운트</param>
/// <param name="learningRate">학습률</param>
/// <param name="momentum">모멘텀</param>
public void Train(double[][] trainingValueArray, int maximumEpochCount, double learningRate, double momentum)
{
int epochCount = 0;
double[] xValueArray = new double[this.inputNodeCount ];
double[] targetValueArray = new double[this.outputNodeCount];
int traingingValueCount = trainingValueArray.Length;
int[] sequenceArray = new int[traingingValueCount];
int sequenceCount = sequenceArray.Length;
for(int i = 0; i < sequenceCount; ++i)
{
sequenceArray[i] = i;
}
while(epochCount < maximumEpochCount)
{
double mse = GetMeanSquaredError(trainingValueArray);
if(mse < 0.04d)
{
break;
}
Shuffle(sequenceArray);
for(int i = 0; i < traingingValueCount; i++)
{
int sequenceIndex = sequenceArray[i];
Array.Copy(trainingValueArray[sequenceIndex], xValueArray, this.inputNodeCount);
Array.Copy(trainingValueArray[sequenceIndex], this.inputNodeCount, targetValueArray, 0, this.outputNodeCount);
ComputeOutputNodeValueArray(xValueArray);
UpdateWeightArray(targetValueArray, learningRate, momentum);
}
epochCount++;
}
}
#endregion
#region 출력 노드 배열 계산하기 - ComputeOutputNodeValueArray(sourceInputNodeValueArray)
/// <summary>
/// 출력 노드 배열 계산하기
/// </summary>
/// <param name="sourceInputNodeValueArray">소스 입력 노드 값 배열</param>
/// <returns>출력 노드 값 배열</returns>
public double[] ComputeOutputNodeValueArray(double[] sourceInputNodeValueArray)
{
if(sourceInputNodeValueArray.Length != this.inputNodeCount)
{
throw new Exception("잘못된 소스 입력 노드 값 배열 길이 입니다.");
}
double[] hiddenNodeSummaryArray = new double[this.hiddenNodeCount];
double[] outputNodeSummaryArray = new double[this.outputNodeCount];
int sourceInputNodeValueCount = sourceInputNodeValueArray.Length;
for(int i = 0; i < sourceInputNodeValueCount; i++)
{
this.inputNodeValueArray[i] = sourceInputNodeValueArray[i];
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
for(int j = 0; j < this.inputNodeCount; j++)
{
hiddenNodeSummaryArray[i] += this.inputNodeValueArray[j] * this.inputHiddenWeightArray[j][i];
}
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
hiddenNodeSummaryArray[i] += this.hiddenNodeBiasArray[i];
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
this.hiddenNodeValueArray[i] = GetHyperTangentValue(hiddenNodeSummaryArray[i]);
}
for(int i = 0; i < this.outputNodeCount; i++)
{
for(int j = 0; j < this.hiddenNodeCount; j++)
{
outputNodeSummaryArray[i] += this.hiddenNodeValueArray[j] * this.hiddenOutputWeightArray[j][i];
}
}
for(int i = 0; i < this.outputNodeCount; i++)
{
outputNodeSummaryArray[i] += this.outputNodeBiasArray[i];
}
double[] softMaximumArray = GetSoftMaximumArray(outputNodeSummaryArray);
Array.Copy(softMaximumArray, this.outputNodeValueArray, softMaximumArray.Length);
double[] targetOutputNodeValueArray = new double[this.outputNodeCount];
Array.Copy(this.outputNodeValueArray, targetOutputNodeValueArray, targetOutputNodeValueArray.Length);
return targetOutputNodeValueArray;
}
#endregion
#region 정확도 구하기 - GetAccuracy(trainingValueArray)
/// <summary>
/// 정확도 구하기
/// </summary>
/// <param name="trainingValueArray">훈련 값 배열</param>
/// <returns>정확도</returns>
public double GetAccuracy(double[][] trainingValueArray)
{
int correctCount = 0;
int wrongCount = 0;
double[] xValueArray = new double[this.inputNodeCount ];
double[] targetValueArray = new double[this.outputNodeCount];
double[] yValueArray;
int trainingValueCount = trainingValueArray.Length;
for(int i = 0; i < trainingValueCount; i++)
{
Array.Copy(trainingValueArray[i], xValueArray, this.inputNodeCount);
Array.Copy(trainingValueArray[i], this.inputNodeCount, targetValueArray, 0, this.outputNodeCount);
yValueArray = ComputeOutputNodeValueArray(xValueArray);
int maximumIndex = GetMaximumIndex(yValueArray);
if(targetValueArray[maximumIndex] == 1d)
{
correctCount++;
}
else
{
wrongCount++;
}
}
return (correctCount * 1d) / (correctCount + wrongCount);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 매트릭스 배열 구하기 - GetMatrixArray(rowCount, columnCount)
/// <summary>
/// 매트릭스 배열 구하기
/// </summary>
/// <param name="rowCount">행 카운트</param>
/// <param name="columnCount">컬럼 카운트</param>
/// <returns>매트릭스 배열</returns>
private static double[][] GetMatrixArray(int rowCount, int columnCount)
{
double[][] matrixArray = new double[rowCount][];
int count = matrixArray.Length;
for(int i = 0; i < count; i++)
{
matrixArray[i] = new double[columnCount];
}
return matrixArray;
}
#endregion
#region 가중치 배열 초기화 하기 - InitializeWeightArray()
/// <summary>
/// 가중치 배열 초기화 하기
/// </summary>
private void InitializeWeightArray()
{
int totalWeightCount = (this.inputNodeCount * this.hiddenNodeCount) +
(this.hiddenNodeCount * this.outputNodeCount) +
this.hiddenNodeCount + this.outputNodeCount;
double[] initialWeightArray = new double[totalWeightCount];
double low = -0.01d;
double high = 0.01d;
int initialWeightCount = initialWeightArray.Length;
for(int i = 0; i < initialWeightCount; i++)
{
initialWeightArray[i] = (high - low) * _random.NextDouble() + low;
}
SetWeightArray(initialWeightArray);
}
#endregion
#region 하이퍼 탄젠트 값 구하기 - GetHyperTangentValue(x)
/// <summary>
/// 하이퍼 탄젠트 값 구하기
/// </summary>
/// <param name="x">X</param>
/// <returns>하이퍼 탄젠트 값</returns>
private static double GetHyperTangentValue(double x)
{
if(x < -20d)
{
return -1d;
}
else if(x > 20d)
{
return 1d;
}
else
{
return Math.Tanh(x);
}
}
#endregion
#region SOFT-MAX 배열 구하기 - GetSoftMaximumArray(sourceOutputNodeSummaryArray)
/// <summary>
/// SOFT-MAX 배열 구하기
/// </summary>
/// <param name="sourceOutputNodeSummaryArray">소스 출력 노드 합산 배열</param>
/// <returns>SOFT-MAX 배열</returns>
private static double[] GetSoftMaximumArray(double[] sourceOutputNodeSummaryArray)
{
int sourceOutputNodeSummaryCount = sourceOutputNodeSummaryArray.Length;
double maximum = sourceOutputNodeSummaryArray[0];
for(int i = 0; i < sourceOutputNodeSummaryCount; i++)
{
if(sourceOutputNodeSummaryArray[i] > maximum)
{
maximum = sourceOutputNodeSummaryArray[i];
}
}
double scale = 0d;
for(int i = 0; i < sourceOutputNodeSummaryCount; ++i)
{
scale += Math.Exp(sourceOutputNodeSummaryArray[i] - maximum);
}
double[] targetArray = new double[sourceOutputNodeSummaryCount];
for(int i = 0; i < sourceOutputNodeSummaryCount; ++i)
{
targetArray[i] = Math.Exp(sourceOutputNodeSummaryArray[i] - maximum) / scale;
}
return targetArray;
}
#endregion
#region 가중치 배열 갱신하기 - UpdateWeightArray(targetValueArray, learningRate, momentum)
/// <summary>
/// 가중치 배열 갱신하기
/// </summary>
/// <param name="targetValueArray">타겟 값 배열</param>
/// <param name="learningRate">학습률</param>
/// <param name="momentum">모멘텀</param>
private void UpdateWeightArray(double[] targetValueArray, double learningRate, double momentum)
{
if(targetValueArray.Length != this.outputNodeCount)
{
throw new Exception("타겟 값 배열 길이가 출력 노드 값 배열과 같지 않습니다.");
}
for(int i = 0; i < this.outputNodeCount; i++)
{
double derivative = (1 - this.outputNodeValueArray[i]) * this.outputNodeValueArray[i];
this.outputNodeGradientArray[i] = derivative * (targetValueArray[i] - this.outputNodeValueArray[i]);
}
for(int i = 0; i < hiddenNodeCount; i++)
{
double derivative = (1 - this.hiddenNodeValueArray[i]) * (1 + this.hiddenNodeValueArray[i]);
double summary = 0d;
for(int j = 0; j < this.outputNodeCount; j++)
{
double x = this.outputNodeGradientArray[j] * this.hiddenOutputWeightArray[i][j];
summary += x;
}
this.hiddenNodeGradientArray[i] = derivative * summary;
}
for(int i = 0; i < this.inputNodeCount; i++)
{
for(int j = 0; j < this.hiddenNodeCount; j++)
{
double delta = learningRate * this.hiddenNodeGradientArray[j] * this.inputNodeValueArray[i];
this.inputHiddenWeightArray[i][j] += delta;
this.inputHiddenWeightArray[i][j] += momentum * this.inputHiddenPreviousWeightDeltaArray[i][j];
this.inputHiddenPreviousWeightDeltaArray[i][j] = delta;
}
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
double delta = learningRate * this.hiddenNodeGradientArray[i];
this.hiddenNodeBiasArray[i] += delta;
this.hiddenNodeBiasArray[i] += momentum * this.hiddenNodePreviousBiasDeltaArray[i];
this.hiddenNodePreviousBiasDeltaArray[i] = delta;
}
for(int i = 0; i < this.hiddenNodeCount; i++)
{
for(int j = 0; j < this.outputNodeCount; j++)
{
double delta = learningRate * this.outputNodeGradientArray[j] * this.hiddenNodeValueArray[i];
this.hiddenOutputWeightArray[i][j] += delta;
this.hiddenOutputWeightArray[i][j] += momentum * this.hiddenOutputPreviousWeightDeltaArray[i][j];
this.hiddenOutputPreviousWeightDeltaArray[i][j] = delta;
}
}
for(int i = 0; i < this.outputNodeCount; i++)
{
double delta = learningRate * this.outputNodeGradientArray[i] * 1d;
this.outputNodeBiasArray[i] += delta;
this.outputNodeBiasArray[i] += momentum * this.outputNodePreviousBiasDeltaArray[i];
this.outputNodePreviousBiasDeltaArray[i] = delta;
}
}
#endregion
#region 섞기 - Shuffle(sequenceArray)
/// <summary>
/// 섞기
/// </summary>
/// <param name="sequenceArray">시퀀스 배열</param>
private static void Shuffle(int[] sequenceArray)
{
for(int i = 0; i < sequenceArray.Length; i++)
{
int randomIndex = _random.Next(i, sequenceArray.Length);
int sequence = sequenceArray[randomIndex];
sequenceArray[randomIndex] = sequenceArray[i];
sequenceArray[i] = sequence;
}
}
#endregion
#region 평균 제곱 에러 구하기 - GetMeanSquaredError(trainingValueArray)
/// <summary>
/// 평균 제곱 에러 구하기
/// </summary>
/// <param name="trainingValueArray">훈련 값 배열</param>
/// <returns>평균 제곱 에러</returns>
private double GetMeanSquaredError(double[][] trainingValueArray)
{
double summarySquaredError = 0d;
double[] xValueArray = new double[this.inputNodeCount ];
double[] targetValueArray = new double[this.outputNodeCount];
int trainingValueCount = trainingValueArray.Length;
for(int i = 0; i < trainingValueCount; i++)
{
Array.Copy(trainingValueArray[i], xValueArray, this.inputNodeCount);
Array.Copy(trainingValueArray[i], this.inputNodeCount, targetValueArray, 0, this.outputNodeCount);
double[] yValueArray = ComputeOutputNodeValueArray(xValueArray);
for(int j = 0; j < this.outputNodeCount; j++)
{
double error = targetValueArray[j] - yValueArray[j];
summarySquaredError += error * error;
}
}
return summarySquaredError / trainingValueCount;
}
#endregion
#region 최대 인덱스 구하기 - GetMaximumIndex(vectorArray)
/// <summary>
/// 최대 인덱스 구하기
/// </summary>
/// <param name="vectorArray">벡터 배열</param>
/// <returns>최대 인덱스</returns>
private static int GetMaximumIndex(double[] vectorArray)
{
int maximumIndex = 0;
double maximum = vectorArray[0];
int vectorCount = vectorArray.Length;
for(int i = 0; i < vectorCount; i++)
{
if(vectorArray[i] > maximum)
{
maximum = vectorArray[i];
maximumIndex = i;
}
}
return maximumIndex;
}
#endregion
}
}
728x90
▶ Program.cs
using System;
namespace TestProject
{
class Program
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 프로그램 시작하기 - Main()
/// <summary>
/// 프로그램 시작하기
/// </summary>
private static void Main()
{
Console.Title = "신경망 역전파 알고리즘 사용하기";
Console.WriteLine();
Console.WriteLine("신경망 훈련 데모를 시작한다.");
Console.WriteLine();
Console.WriteLine("데이터는 유명한 아이리스 꽃 세트이다.");
Console.WriteLine("꽃받침 길이/너비, 꽃잎 길이/너비에서 종을 예측한다.");
Console.WriteLine("Iris setosa = 0 0 1, versicolor = 0 1 0, virginica = 1 0 0");
Console.WriteLine();
Console.WriteLine("실제 데이터와 유사하다 :");
Console.WriteLine();
Console.WriteLine(" 5.1, 3.5, 1.4, 0.2, Iris setosa" );
Console.WriteLine(" 7.0, 3.2, 4.7, 1.4, Iris versicolor");
Console.WriteLine(" 6.3, 3.3, 6.0, 2.5, Iris versinica" );
Console.WriteLine(" ......");
Console.WriteLine();
double[][] sourceValueArray = new double[150][];
#region 소스 값 배열 데이터를 설정한다.
sourceValueArray[0] = new double[] { 5.1, 3.5, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[1] = new double[] { 4.9, 3.0, 1.4, 0.2, 0, 0, 1 }; // Iris setosa = 0 0 1
sourceValueArray[2] = new double[] { 4.7, 3.2, 1.3, 0.2, 0, 0, 1 }; // Iris versicolor = 0 1 0
sourceValueArray[3] = new double[] { 4.6, 3.1, 1.5, 0.2, 0, 0, 1 }; // Iris verginica = 1 0 0
sourceValueArray[4] = new double[] { 5.0, 3.6, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[5] = new double[] { 5.4, 3.9, 1.7, 0.4, 0, 0, 1 };
sourceValueArray[6] = new double[] { 4.6, 3.4, 1.4, 0.3, 0, 0, 1 };
sourceValueArray[7] = new double[] { 5.0, 3.4, 1.5, 0.2, 0, 0, 1 };
sourceValueArray[8] = new double[] { 4.4, 2.9, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[9] = new double[] { 4.9, 3.1, 1.5, 0.1, 0, 0, 1 };
sourceValueArray[10] = new double[] { 5.4, 3.7, 1.5, 0.2, 0, 0, 1 };
sourceValueArray[11] = new double[] { 4.8, 3.4, 1.6, 0.2, 0, 0, 1 };
sourceValueArray[12] = new double[] { 4.8, 3.0, 1.4, 0.1, 0, 0, 1 };
sourceValueArray[13] = new double[] { 4.3, 3.0, 1.1, 0.1, 0, 0, 1 };
sourceValueArray[14] = new double[] { 5.8, 4.0, 1.2, 0.2, 0, 0, 1 };
sourceValueArray[15] = new double[] { 5.7, 4.4, 1.5, 0.4, 0, 0, 1 };
sourceValueArray[16] = new double[] { 5.4, 3.9, 1.3, 0.4, 0, 0, 1 };
sourceValueArray[17] = new double[] { 5.1, 3.5, 1.4, 0.3, 0, 0, 1 };
sourceValueArray[18] = new double[] { 5.7, 3.8, 1.7, 0.3, 0, 0, 1 };
sourceValueArray[19] = new double[] { 5.1, 3.8, 1.5, 0.3, 0, 0, 1 };
sourceValueArray[20] = new double[] { 5.4, 3.4, 1.7, 0.2, 0, 0, 1 };
sourceValueArray[21] = new double[] { 5.1, 3.7, 1.5, 0.4, 0, 0, 1 };
sourceValueArray[22] = new double[] { 4.6, 3.6, 1.0, 0.2, 0, 0, 1 };
sourceValueArray[23] = new double[] { 5.1, 3.3, 1.7, 0.5, 0, 0, 1 };
sourceValueArray[24] = new double[] { 4.8, 3.4, 1.9, 0.2, 0, 0, 1 };
sourceValueArray[25] = new double[] { 5.0, 3.0, 1.6, 0.2, 0, 0, 1 };
sourceValueArray[26] = new double[] { 5.0, 3.4, 1.6, 0.4, 0, 0, 1 };
sourceValueArray[27] = new double[] { 5.2, 3.5, 1.5, 0.2, 0, 0, 1 };
sourceValueArray[28] = new double[] { 5.2, 3.4, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[29] = new double[] { 4.7, 3.2, 1.6, 0.2, 0, 0, 1 };
sourceValueArray[30] = new double[] { 4.8, 3.1, 1.6, 0.2, 0, 0, 1 };
sourceValueArray[31] = new double[] { 5.4, 3.4, 1.5, 0.4, 0, 0, 1 };
sourceValueArray[32] = new double[] { 5.2, 4.1, 1.5, 0.1, 0, 0, 1 };
sourceValueArray[33] = new double[] { 5.5, 4.2, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[34] = new double[] { 4.9, 3.1, 1.5, 0.1, 0, 0, 1 };
sourceValueArray[35] = new double[] { 5.0, 3.2, 1.2, 0.2, 0, 0, 1 };
sourceValueArray[36] = new double[] { 5.5, 3.5, 1.3, 0.2, 0, 0, 1 };
sourceValueArray[37] = new double[] { 4.9, 3.1, 1.5, 0.1, 0, 0, 1 };
sourceValueArray[38] = new double[] { 4.4, 3.0, 1.3, 0.2, 0, 0, 1 };
sourceValueArray[39] = new double[] { 5.1, 3.4, 1.5, 0.2, 0, 0, 1 };
sourceValueArray[40] = new double[] { 5.0, 3.5, 1.3, 0.3, 0, 0, 1 };
sourceValueArray[41] = new double[] { 4.5, 2.3, 1.3, 0.3, 0, 0, 1 };
sourceValueArray[42] = new double[] { 4.4, 3.2, 1.3, 0.2, 0, 0, 1 };
sourceValueArray[43] = new double[] { 5.0, 3.5, 1.6, 0.6, 0, 0, 1 };
sourceValueArray[44] = new double[] { 5.1, 3.8, 1.9, 0.4, 0, 0, 1 };
sourceValueArray[45] = new double[] { 4.8, 3.0, 1.4, 0.3, 0, 0, 1 };
sourceValueArray[46] = new double[] { 5.1, 3.8, 1.6, 0.2, 0, 0, 1 };
sourceValueArray[47] = new double[] { 4.6, 3.2, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[48] = new double[] { 5.3, 3.7, 1.5, 0.2, 0, 0, 1 };
sourceValueArray[49] = new double[] { 5.0, 3.3, 1.4, 0.2, 0, 0, 1 };
sourceValueArray[50] = new double[] { 7.0, 3.2, 4.7, 1.4, 0, 1, 0 };
sourceValueArray[51] = new double[] { 6.4, 3.2, 4.5, 1.5, 0, 1, 0 };
sourceValueArray[52] = new double[] { 6.9, 3.1, 4.9, 1.5, 0, 1, 0 };
sourceValueArray[53] = new double[] { 5.5, 2.3, 4.0, 1.3, 0, 1, 0 };
sourceValueArray[54] = new double[] { 6.5, 2.8, 4.6, 1.5, 0, 1, 0 };
sourceValueArray[55] = new double[] { 5.7, 2.8, 4.5, 1.3, 0, 1, 0 };
sourceValueArray[56] = new double[] { 6.3, 3.3, 4.7, 1.6, 0, 1, 0 };
sourceValueArray[57] = new double[] { 4.9, 2.4, 3.3, 1.0, 0, 1, 0 };
sourceValueArray[58] = new double[] { 6.6, 2.9, 4.6, 1.3, 0, 1, 0 };
sourceValueArray[59] = new double[] { 5.2, 2.7, 3.9, 1.4, 0, 1, 0 };
sourceValueArray[60] = new double[] { 5.0, 2.0, 3.5, 1.0, 0, 1, 0 };
sourceValueArray[61] = new double[] { 5.9, 3.0, 4.2, 1.5, 0, 1, 0 };
sourceValueArray[62] = new double[] { 6.0, 2.2, 4.0, 1.0, 0, 1, 0 };
sourceValueArray[63] = new double[] { 6.1, 2.9, 4.7, 1.4, 0, 1, 0 };
sourceValueArray[64] = new double[] { 5.6, 2.9, 3.6, 1.3, 0, 1, 0 };
sourceValueArray[65] = new double[] { 6.7, 3.1, 4.4, 1.4, 0, 1, 0 };
sourceValueArray[66] = new double[] { 5.6, 3.0, 4.5, 1.5, 0, 1, 0 };
sourceValueArray[67] = new double[] { 5.8, 2.7, 4.1, 1.0, 0, 1, 0 };
sourceValueArray[68] = new double[] { 6.2, 2.2, 4.5, 1.5, 0, 1, 0 };
sourceValueArray[69] = new double[] { 5.6, 2.5, 3.9, 1.1, 0, 1, 0 };
sourceValueArray[70] = new double[] { 5.9, 3.2, 4.8, 1.8, 0, 1, 0 };
sourceValueArray[71] = new double[] { 6.1, 2.8, 4.0, 1.3, 0, 1, 0 };
sourceValueArray[72] = new double[] { 6.3, 2.5, 4.9, 1.5, 0, 1, 0 };
sourceValueArray[73] = new double[] { 6.1, 2.8, 4.7, 1.2, 0, 1, 0 };
sourceValueArray[74] = new double[] { 6.4, 2.9, 4.3, 1.3, 0, 1, 0 };
sourceValueArray[75] = new double[] { 6.6, 3.0, 4.4, 1.4, 0, 1, 0 };
sourceValueArray[76] = new double[] { 6.8, 2.8, 4.8, 1.4, 0, 1, 0 };
sourceValueArray[77] = new double[] { 6.7, 3.0, 5.0, 1.7, 0, 1, 0 };
sourceValueArray[78] = new double[] { 6.0, 2.9, 4.5, 1.5, 0, 1, 0 };
sourceValueArray[79] = new double[] { 5.7, 2.6, 3.5, 1.0, 0, 1, 0 };
sourceValueArray[80] = new double[] { 5.5, 2.4, 3.8, 1.1, 0, 1, 0 };
sourceValueArray[81] = new double[] { 5.5, 2.4, 3.7, 1.0, 0, 1, 0 };
sourceValueArray[82] = new double[] { 5.8, 2.7, 3.9, 1.2, 0, 1, 0 };
sourceValueArray[83] = new double[] { 6.0, 2.7, 5.1, 1.6, 0, 1, 0 };
sourceValueArray[84] = new double[] { 5.4, 3.0, 4.5, 1.5, 0, 1, 0 };
sourceValueArray[85] = new double[] { 6.0, 3.4, 4.5, 1.6, 0, 1, 0 };
sourceValueArray[86] = new double[] { 6.7, 3.1, 4.7, 1.5, 0, 1, 0 };
sourceValueArray[87] = new double[] { 6.3, 2.3, 4.4, 1.3, 0, 1, 0 };
sourceValueArray[88] = new double[] { 5.6, 3.0, 4.1, 1.3, 0, 1, 0 };
sourceValueArray[89] = new double[] { 5.5, 2.5, 4.0, 1.3, 0, 1, 0 };
sourceValueArray[90] = new double[] { 5.5, 2.6, 4.4, 1.2, 0, 1, 0 };
sourceValueArray[91] = new double[] { 6.1, 3.0, 4.6, 1.4, 0, 1, 0 };
sourceValueArray[92] = new double[] { 5.8, 2.6, 4.0, 1.2, 0, 1, 0 };
sourceValueArray[93] = new double[] { 5.0, 2.3, 3.3, 1.0, 0, 1, 0 };
sourceValueArray[94] = new double[] { 5.6, 2.7, 4.2, 1.3, 0, 1, 0 };
sourceValueArray[95] = new double[] { 5.7, 3.0, 4.2, 1.2, 0, 1, 0 };
sourceValueArray[96] = new double[] { 5.7, 2.9, 4.2, 1.3, 0, 1, 0 };
sourceValueArray[97] = new double[] { 6.2, 2.9, 4.3, 1.3, 0, 1, 0 };
sourceValueArray[98] = new double[] { 5.1, 2.5, 3.0, 1.1, 0, 1, 0 };
sourceValueArray[99] = new double[] { 5.7, 2.8, 4.1, 1.3, 0, 1, 0 };
sourceValueArray[100] = new double[] { 6.3, 3.3, 6.0, 2.5, 1, 0, 0 };
sourceValueArray[101] = new double[] { 5.8, 2.7, 5.1, 1.9, 1, 0, 0 };
sourceValueArray[102] = new double[] { 7.1, 3.0, 5.9, 2.1, 1, 0, 0 };
sourceValueArray[103] = new double[] { 6.3, 2.9, 5.6, 1.8, 1, 0, 0 };
sourceValueArray[104] = new double[] { 6.5, 3.0, 5.8, 2.2, 1, 0, 0 };
sourceValueArray[105] = new double[] { 7.6, 3.0, 6.6, 2.1, 1, 0, 0 };
sourceValueArray[106] = new double[] { 4.9, 2.5, 4.5, 1.7, 1, 0, 0 };
sourceValueArray[107] = new double[] { 7.3, 2.9, 6.3, 1.8, 1, 0, 0 };
sourceValueArray[108] = new double[] { 6.7, 2.5, 5.8, 1.8, 1, 0, 0 };
sourceValueArray[109] = new double[] { 7.2, 3.6, 6.1, 2.5, 1, 0, 0 };
sourceValueArray[110] = new double[] { 6.5, 3.2, 5.1, 2.0, 1, 0, 0 };
sourceValueArray[111] = new double[] { 6.4, 2.7, 5.3, 1.9, 1, 0, 0 };
sourceValueArray[112] = new double[] { 6.8, 3.0, 5.5, 2.1, 1, 0, 0 };
sourceValueArray[113] = new double[] { 5.7, 2.5, 5.0, 2.0, 1, 0, 0 };
sourceValueArray[114] = new double[] { 5.8, 2.8, 5.1, 2.4, 1, 0, 0 };
sourceValueArray[115] = new double[] { 6.4, 3.2, 5.3, 2.3, 1, 0, 0 };
sourceValueArray[116] = new double[] { 6.5, 3.0, 5.5, 1.8, 1, 0, 0 };
sourceValueArray[117] = new double[] { 7.7, 3.8, 6.7, 2.2, 1, 0, 0 };
sourceValueArray[118] = new double[] { 7.7, 2.6, 6.9, 2.3, 1, 0, 0 };
sourceValueArray[119] = new double[] { 6.0, 2.2, 5.0, 1.5, 1, 0, 0 };
sourceValueArray[120] = new double[] { 6.9, 3.2, 5.7, 2.3, 1, 0, 0 };
sourceValueArray[121] = new double[] { 5.6, 2.8, 4.9, 2.0, 1, 0, 0 };
sourceValueArray[122] = new double[] { 7.7, 2.8, 6.7, 2.0, 1, 0, 0 };
sourceValueArray[123] = new double[] { 6.3, 2.7, 4.9, 1.8, 1, 0, 0 };
sourceValueArray[124] = new double[] { 6.7, 3.3, 5.7, 2.1, 1, 0, 0 };
sourceValueArray[125] = new double[] { 7.2, 3.2, 6.0, 1.8, 1, 0, 0 };
sourceValueArray[126] = new double[] { 6.2, 2.8, 4.8, 1.8, 1, 0, 0 };
sourceValueArray[127] = new double[] { 6.1, 3.0, 4.9, 1.8, 1, 0, 0 };
sourceValueArray[128] = new double[] { 6.4, 2.8, 5.6, 2.1, 1, 0, 0 };
sourceValueArray[129] = new double[] { 7.2, 3.0, 5.8, 1.6, 1, 0, 0 };
sourceValueArray[130] = new double[] { 7.4, 2.8, 6.1, 1.9, 1, 0, 0 };
sourceValueArray[131] = new double[] { 7.9, 3.8, 6.4, 2.0, 1, 0, 0 };
sourceValueArray[132] = new double[] { 6.4, 2.8, 5.6, 2.2, 1, 0, 0 };
sourceValueArray[133] = new double[] { 6.3, 2.8, 5.1, 1.5, 1, 0, 0 };
sourceValueArray[134] = new double[] { 6.1, 2.6, 5.6, 1.4, 1, 0, 0 };
sourceValueArray[135] = new double[] { 7.7, 3.0, 6.1, 2.3, 1, 0, 0 };
sourceValueArray[136] = new double[] { 6.3, 3.4, 5.6, 2.4, 1, 0, 0 };
sourceValueArray[137] = new double[] { 6.4, 3.1, 5.5, 1.8, 1, 0, 0 };
sourceValueArray[138] = new double[] { 6.0, 3.0, 4.8, 1.8, 1, 0, 0 };
sourceValueArray[139] = new double[] { 6.9, 3.1, 5.4, 2.1, 1, 0, 0 };
sourceValueArray[140] = new double[] { 6.7, 3.1, 5.6, 2.4, 1, 0, 0 };
sourceValueArray[141] = new double[] { 6.9, 3.1, 5.1, 2.3, 1, 0, 0 };
sourceValueArray[142] = new double[] { 5.8, 2.7, 5.1, 1.9, 1, 0, 0 };
sourceValueArray[143] = new double[] { 6.8, 3.2, 5.9, 2.3, 1, 0, 0 };
sourceValueArray[144] = new double[] { 6.7, 3.3, 5.7, 2.5, 1, 0, 0 };
sourceValueArray[145] = new double[] { 6.7, 3.0, 5.2, 2.3, 1, 0, 0 };
sourceValueArray[146] = new double[] { 6.3, 2.5, 5.0, 1.9, 1, 0, 0 };
sourceValueArray[147] = new double[] { 6.5, 3.0, 5.2, 2.0, 1, 0, 0 };
sourceValueArray[148] = new double[] { 6.2, 3.4, 5.4, 2.3, 1, 0, 0 };
sourceValueArray[149] = new double[] { 5.9, 3.0, 5.1, 1.8, 1, 0, 0 };
#endregion
Console.WriteLine("150개 항목 데이터 세트의 첫번째 6개 행들 :");
Console.WriteLine();
DisplayMatrixArray(sourceValueArray, 6, 1, true);
Console.WriteLine("80% 훈련 데이터 매트릭스와 20% 테스트 데이터 매트릭스 생성");
double[][] traingingValueArray = null;
double[][] testValueArray = null;
PrepareData(sourceValueArray, 72, out traingingValueArray, out testValueArray);
Console.WriteLine();
Console.WriteLine("훈련 데이터의 첫번째 3개 행들 :");
Console.WriteLine();
DisplayMatrixArray(traingingValueArray, 3, 1, true);
Console.WriteLine("테스트 데이터의 첫번째 3개 행들 :");
Console.WriteLine();
DisplayMatrixArray(testValueArray, 3, 1, true);
Console.WriteLine("4개 입력 노드, 7개 은닉 노드, 3개 출력 노드를 갖는 신경망 생성");
Console.WriteLine("입력-은닉층을 위한 하드 코딩된 하이퍼 탄젠트 함수와 은닉-출력층 활성화를 위한 소프트 맥스 함수");
int inputNodeCount = 4;
int hiddenModeCount = 7;
int outputNodeCount = 3;
NeuralNetwork neuralNetwork = new NeuralNetwork(inputNodeCount, hiddenModeCount, outputNodeCount);
int maximumEpochCount = 1000;
double learningRate = 0.05d;
double momentum = 0.01d;
Console.WriteLine("최대 시대 카운트 = " + maximumEpochCount + ", 학습률 = " + learningRate + ", 모멘텀 = " + momentum);
Console.WriteLine("훈련은 하드 코딩된 평균 제곱 오류가 0.040보다 작은 경우 중단하는 조건을 갖는다.");
Console.WriteLine();
Console.WriteLine("증분 역전파를 사용해 훈련 시작하기");
Console.WriteLine();
neuralNetwork.Train(traingingValueArray, maximumEpochCount, learningRate, momentum);
Console.WriteLine("훈련 완료");
Console.WriteLine();
double[] weightArray = neuralNetwork.GetWeightArray();
Console.WriteLine("최종 신경망 가중치와 바이어스 값들 : ");
DisplayVectorArray(weightArray, 10, 3, true);
double trainingAccuracy = neuralNetwork.GetAccuracy(traingingValueArray);
double testAccuracy = neuralNetwork.GetAccuracy(testValueArray );
Console.WriteLine();
Console.WriteLine("훈련 데이터 정확도 = " + trainingAccuracy.ToString("F4"));
Console.WriteLine("테스트 데이터 정확도 = " + testAccuracy.ToString("F4"));
Console.WriteLine();
Console.WriteLine("입력 데이터 : ");
double[] inputArray = new double[] { 5.1, 3.5, 1.4, 0.2 };
DisplayVectorArray(inputArray, 4, 3, true);
double[] resultArray = neuralNetwork.ComputeOutputNodeValueArray(inputArray);
Console.WriteLine();
Console.WriteLine("출력 데이터 : ");
DisplayVectorArray(resultArray, 3, 3, true);
Console.WriteLine();
Console.WriteLine("신경망 훈련 데모 종료");
Console.ReadLine();
}
#endregion
#region 데이터 준비하기 - PrepareData(sourceValueArray, seed, trainingValueArray, testValueArray)
/// <summary>
/// 데이터 준비하기
/// </summary>
/// <param name="sourceValueArray">소스 값 배열</param>
/// <param name="seed">시드</param>
/// <param name="trainingValueArray">훈련 값 배열</param>
/// <param name="testValueArray">테스트 값 배열</param>
private static void PrepareData
(
double[][] sourceValueArray,
int seed,
out double[][] trainingValueArray,
out double[][] testValueArray
)
{
Random random = new Random(seed);
int rowCount = sourceValueArray.Length;
int columnCount = sourceValueArray[0].Length;
int trainingRowCount = (int)(rowCount * 0.80);
int testRowCount = rowCount - trainingRowCount;
trainingValueArray = new double[trainingRowCount][];
testValueArray = new double[testRowCount][];
double[][] copyValueArray = new double[sourceValueArray.Length][];
for(int i = 0; i < copyValueArray.Length; i++)
{
copyValueArray[i] = sourceValueArray[i];
}
for(int i = 0; i < copyValueArray.Length; i++)
{
int randomIndex = random.Next(i, copyValueArray.Length);
double[] temporaryArray = copyValueArray[randomIndex];
copyValueArray[randomIndex] = copyValueArray[i];
copyValueArray[i ] = temporaryArray;
}
for(int i = 0; i < trainingRowCount; i++)
{
trainingValueArray[i] = new double[columnCount];
for(int j = 0; j < columnCount; j++)
{
trainingValueArray[i][j] = copyValueArray[i][j];
}
}
for(int i = 0; i < testRowCount; i++)
{
testValueArray[i] = new double[columnCount];
for(int j = 0; j < columnCount; j++)
{
testValueArray[i][j] = copyValueArray[i + trainingRowCount][j];
}
}
}
#endregion
#region 벡터 배열 출력하기 - DisplayVectorArray(sourceVectorArray, valueCountPerRow, decimalCount, newLine)
/// <summary>
/// 벡터 배열 출력하기
/// </summary>
/// <param name="sourceVectorArray">소스 벡터 배열</param>
/// <param name="valueCountPerRow">행당 값 카운트</param>
/// <param name="decimalCount">소수점 카운트</param>
/// <param name="newLine">개행 여부</param>
private static void DisplayVectorArray(double[] sourceVectorArray, int valueCountPerRow, int decimalCount, bool newLine)
{
int sourceVectorCount = sourceVectorArray.Length;
for(int i = 0; i < sourceVectorCount; i++)
{
if(i % valueCountPerRow == 0)
{
Console.WriteLine("");
}
Console.Write(sourceVectorArray[i].ToString("F" + decimalCount).PadLeft(decimalCount + 4) + " ");
}
if (newLine == true)
{
Console.WriteLine("");
}
}
#endregion
#region 매트릭스 배열 출력하기 - DisplayMatrixArray(sourceMatrixArray, rowCount, decimalCount, newLine)
/// <summary>
/// 매트릭스 배열 출력하기
/// </summary>
/// <param name="sourceMatrixArray">소스 매트릭스 배열</param>
/// <param name="rowCount">행 카운트</param>
/// <param name="decimalCount">소수점 카운트</param>
/// <param name="newLine">개행 여부</param>
private static void DisplayMatrixArray(double[][] sourceMatrixArray, int rowCount, int decimalCount, bool newLine)
{
for(int i = 0; i < rowCount; i++)
{
Console.Write(i.ToString().PadLeft(3) + " : ");
for(int j = 0; j < sourceMatrixArray[i].Length; j++)
{
if(sourceMatrixArray[i][j] >= 0d)
{
Console.Write(" ");
}
else
{
Console.Write("-");
}
Console.Write(Math.Abs(sourceMatrixArray[i][j]).ToString("F" + decimalCount) + " ");
}
Console.WriteLine("");
}
if(newLine == true)
{
Console.WriteLine("");
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > Common' 카테고리의 다른 글
[C#/COMMON] 이스케이프 시퀀스 코드 참조하기 (0) | 2017.01.28 |
---|---|
[C#/COMMON] 접근자 참조하기 (0) | 2017.01.28 |
[C#/COMMON] 문자열 포맷하기 (0) | 2017.01.28 |
[C#/COMMON] 데이터 타입 (값형 기준) 참조하기 (0) | 2017.01.28 |
[C#/COMMON] Environment 클래스 : 환경 변수 참조하기 (0) | 2017.01.28 |
[C#/COMMON] 조합 구하기 (0) | 2017.01.27 |
[C#/COMMON] CSharpCodeProvider 클래스 : 동적 컴파일 사용하기 (0) | 2017.01.27 |
[C#/COMMON] FtpWebRequest 클래스 : FTP 사용하기 (0) | 2017.01.27 |
[C#/COMMON] DateTime 구조체 : 특정 시간대 시간 구하기 (0) | 2017.01.27 |
[C#/COMMON] TimeZoneInfo 클래스 : GetSystemTimeZones 정적 메소드를 사용해 표준 시간대명 나열하기 (0) | 2017.01.27 |
댓글을 달아 주세요