Нейронная сеть не работает правильно
Я использую ( библиотека ENCOG) для создания и обучения нейронной сети. Он должен найти реальный вектор неисправности (он имеет 12 чисел - как вектор = сигнатура неисправности) из словаря моделирования (он имеет 70 неисправностей, идентифицирующих на 12 частотах).
В NN у меня есть входной (12 нейронов = len одного входного вектора ошибок), скрытый (14 нейронов = 2* выходных нейронов) и выходной (7 нейронов - для распознавания по 0\1' 70 ошибкам) слоев.
Это код (на C#) с NN:
public static double[][] XORInput =
{
new double[] { 1, 1, 1, 1,1,1,1,2,2,2,2,2 },
new double[] { 5, 5, 5, 5,5,5,5,6,6,7,7,7 },
new double[] { 6, 6,6,6,6,6,5,5,5,1,2,3 },
new double[] { 3, 3, 3, 3,3,3,3,3,2,2,1,1 } ,
new double[] { 1, 1, 2, 2,2,3,3,3,3,3,3,3 },
new double[] { 1, 4, 2, 7,2,5,6,7,8,8,8,8 },
new double[] { 2, 3, 3, 3,3,3,3,3,3,3,2,2 },
new double[] { 7,7, 7, 7,7,8,8,8,7,7,7,7 },
new double[] { 6, 7, 7, 8,8,8,8,8,8,7,7,6 },
new double[] { 3, 3, 3, 4 ,4,4,4,4,4,3,3,3 },
new double[] { 1, 1, 1, 1,1,2,2,2,2,2,2,2 },
new double[] { 5, 5, 5, 5,5,6,6,6,6,6,6,7 },
new double[] { 1,2,3,4,5,6,7,8,1,2,3,1 },
new double[] { 1, 1, 1, 1,1,1,1,1,1,2,4,1 },
new double[] { 1, 1, 1, 1,1,1,1,1,1,1,1,1 },
new double[] { 5, 5, 5,5,5,5,5,5,5,5,5,5 },
new double[] {7, 8, 8, 8,8,7,6,4,1,2,2,2 },
new double[] { 2, 3, 3, 3,3,4,4,4,4,3,3,3 },
new double[] { 8, 8,8, 8,8,5,6,7,8,8,8,8 },
new double[] { 5, 5, 5, 5,5,6,8,6,1,1,1,1 },
new double[] { 1, 1, 1, 1,1,1,1,4,4,6,3,5 },
new double[] { 2, 2, 2, 2,2,2,2,2,3,3,3,3 },
new double[] { 6, 6, 6, 6,7,7,7,7,7,8,8,8 },
new double[] { 1, 16, 2, 6,71,72,73,27,74,81,81,58 },
new double[] { 2, 36, 3, 67,87,7,17,27,37,2,1,1 },
new double[] { 3, 46, 4, 8,4,5,6,7,22,8,18,2 },
new double[] { 4, 56, 12, 9,1,2,4,12,4,44,1,8 },
new double[] { 5, 66, 5, 6,17,4,5,11,5,7,8,9 },
new double[] { 6, 86, 6, 6, 10,2,5,8,1,3,5,1 },
new double[] { 66, 16, 14, 11,1,1,1,2,1,4,1,6 },
new double[] { 67, 6,11 , 16,2,2,2,7,21,2,1,9 },
new double[] { 7, 6, 10, 62,12,3,4,54,1,1,3,3 },
new double[] { 8, 16,9, 6,17,7,1,2,7,5,1,4 },
new double[] { 9, 26,11, 6,73,6,2,3,4,5,5,2 },
new double[] { 61, 21, 85, 61,5,2,5,1,6,3,4,5 },
new double[] { 31, 1, 11, 1,1,1,1,2,2,2,2,2 },
new double[] { 15, 5, 15, 5,5,5,5,6,6,7,7,7 },
new double[] { 36, 6,16,6,6,6,5,5,5,1,2,3 },
new double[] { 53, 3, 13, 3,3,3,3,3,2,2,1,1 } ,
new double[] { 71, 1, 22, 2,2,3,3,3,3,3,3,3 },
new double[] { 81, 4, 21, 7,2,5,6,7,8,8,8,8 },
new double[] { 12, 3, 13, 3,3,3,3,3,3,3,2,2 },
new double[] { 97,7, 71, 7,7,8,8,8,7,7,7,7 },
new double[] { 5, 7, 17, 8,8,8,8,8,8,7,7,6 },
new double[] { 13, 3, 13, 4,4,4,4,4,4,3,3,3 },
new double[] { 11, 1, 11, 1,1,2,2,2,2,2,2,2 },
new double[] { 55, 5, 51, 5,5,6,6,6,6,6,6,7 },
new double[] { 16,2,19,4,5,6,7,8,1,2,3,1 },
new double[] { 17, 1, 11, 1,1,1,1,1,1,2,4,1 },
new double[] { 19, 1, 21, 1,1,1,1,1,1,1,1,1 },
new double[] { 25, 5, 25,5,5,5,5,5,5,5,5,5 },
new double[] {27, 8, 28, 8,8,7,6,4,1,2,2,2 },
new double[] { 22, 3, 23, 3,3,3,3,3,3,2,1,7 },
new double[] { 32, 3, 27, 3,3,4,4,4,4,3,3,3 },
new double[] { 18, 8,2, 8,8,5,6,7,8,8,8,8 },
new double[] { 31, 1, 4, 1,1,1,1,4,4,6,3,5 },
new double[] { 23, 2, 6, 2,2,2,2,2,3,3,3,3 },
new double[] { 36, 6, 16, 6,7,7,7,7,7,8,8,8 },
new double[] { 31, 16, 5, 6,71,72,73,27,74,81,81,58 },
new double[] { 12, 36, 14, 67,87,7,17,27,37,2,1,1 },
new double[] { 31, 46, 41, 8,4,5,6,7,22,8,18,2 },
new double[] { 14, 56, 1, 9,1,2,4,12,4,44,1,8 },
new double[] { 15, 66, 59, 6,17,4,5,11,5,7,8,9 },
new double[] { 16, 86, 16, 6, 10,2,5,8,1,3,5,1 },
new double[] { 16, 16, 10, 11,1,1,1,2,1,4,1,6 },
new double[] { 17, 6,114, 16,2,2,2,7,21,2,1,9 },
new double[] { 71, 6, 1, 62,12,3,4,54,1,1,3,3 },
new double[] { 18, 16,19, 6,17,7,1,2,7,5,1,4 },
new double[] { 19, 26,1, 6,73,6,2,3,4,5,5,2 },
new double[] { 6, 21, 5, 61,5,2,5,1,6,3,4,5 } //70
};
/// <summary>
/// Array of numbers, which equal to squares of two
/// </summary>
static int[] powOfTwo = {2, 4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536 };
private static void Main(string[] args)
{
double[][] XORIdeal = computeOutputVector(XORInput);
// normalizing input data
double[][] input = normalizeData(XORInput);
// create a neural network, without using a factory
var network = new BasicNetwork();
network.AddLayer(new BasicLayer(null, true, 12));
network.AddLayer(new BasicLayer(new ActivationSigmoid(), true, 14));
network.AddLayer(new BasicLayer(new ActivationSigmoid(), false, 7));
network.Structure.FinalizeStructure();
network.Reset();
// create training data
IMLDataSet trainingSet = new BasicMLDataSet(input, XORIdeal);
//IMLDataSet trainingSet = new BasicMLDataSet(XORInput, XORIdeal);
// train the neural network
//IMLTrain train = new ResilientPropagation(network, trainingSet);
//var train = new Backpropagation ( network , trainingSet , 0.3 , 0.7 ) ;
var train = new Backpropagation(network, trainingSet, 0.2, 0.15); // speed and influence of backpropogation algorithm
int epoch = 1;
do
{
train.Iteration();
Console.WriteLine(@"Epoch #" + epoch + @" Error:" + train.Error);
epoch++;
} while (train.Error > 0.05 && epoch < 2000);
train.FinishTraining();
// test the neural network
Console.WriteLine(@"Neural Network Results:");
double[] data = new double[] { 1, 1, 1, 1,1,1,1,2,2,2,2,2 }; //{ 5.1, 5.4, 5.5, 5.5, 5.8, 5.6, 5.6, 6.5, 6.6, 7.1, 7.1, 7.1 }; // 0000001
double[] realSignature22 = new double[] { 6.21, 4.2, 6.6, 6.6, 6.6, 5.56, 6.5, 7, 7, 6.89, 6.8, 8 }; // 0010110
double[] realSignature34 = new double[] { 58, 24, 90, 55, 4.5, 1.82, 5.4, 1.1, 6.4, 3.1, 3.4, 5.3 }; // 0100010
IMLData example1 = new BasicMLData(normilizeRow(data));
IMLData output1 = network.Compute(example1);
Console.WriteLine("\nactual : 0 0 0 0 0 0 0 = #0 ");
findNumber(output1);
IMLData example = new BasicMLData(normilizeRow(realSignature34));
IMLData output = network.Compute(example);
Console.WriteLine("\nactual : 0 1 0 0 0 1 0 = #34 ");
findNumber(output);
IMLData example2 = new BasicMLData(normilizeRow(realSignature22));
IMLData output2 = network.Compute(example2);
Console.WriteLine("\nactual : 0 0 1 0 1 1 0 = #22 ");
findNumber(output2);
EncogFramework.Instance.Shutdown();
}
/// <summary>
/// Returns degree of two which cowers number of mistakes in the input vector
/// </summary>
/// <param name="XORInput"></param>
/// <returns></returns>
static int calcSizeOfOutputVector(double[][] XORInput)
{
int size = 0;
int len = XORInput.GetLength(0);
foreach (int number in powOfTwo)
{
size++;
if (len <= number) return size;
}
return -1;
}
static double[][] computeOutputVector(double[][] XORInput)
{
double[][] output;
int sizeOfOut = calcSizeOfOutputVector(XORInput);
int numOfFaults = XORInput.GetLength(0);
output = new double[numOfFaults][];
// convert decimal number into corresponding array from 0 and 1 (equal to decimal number)
for (int i = 0; i < numOfFaults; i++)
{
output[i] = new double[sizeOfOut];
convertDecToByteAndSaveInDoubleArray(output[i], i);
}
return output;
}
static double[] convertDecToByteAndSaveInDoubleArray(double[] outArray, int number ){
// convert number into binary representation
string binaryCode = Convert.ToString(number, 2);
int size = outArray.GetLength(0);
// Initially fill with zeros
for (int i = 0; i < size; i++) outArray[i] = 0;
//
for (int i = 0; i < binaryCode.Length; i++)
{
double d = Double.Parse(binaryCode.Substring(binaryCode.Length - i - 1, 1));
outArray[size - 1 - i] = d;
}
return outArray;
}
static void printOutputResults(IMLData output){
Console.WriteLine("\nFrom NN ");
for (int i = 0; i < output.Count; i++ )
Console.Write(" " + output[i] + " " );
}
static int[] findNumber(IMLData output)
{
int len = output.Count;
// Round to 0 and 1 numbers, which is received from NN
int[] outAr = new int[len];
for (int i = 0; i < output.Count; i++)
{
outAr[i] = (int)Math.Round(output[i]);
}
// Display output vectors
// Bug for number 1 and length 7 in the input vector looks like : 0[0] 0[1] 0[2] 0[3] 0[4] 0[5] 1[6] (in binary system) = 1 (in decimal system)
Console.WriteLine("\nFrom NN ");
for (int i = 0; i < len; i++)
Console.Write(" " + outAr[i] + " ");
// Convert binary vector into decimal
Console.WriteLine("\nFrom NN (converted number)" + convertBinArrayToDecNumber(outAr));
return outAr;
}
static int convertBinArrayToDecNumber(int[] binaryArray)
{
int n = 0;
int maxIndex = binaryArray.Length - 1;
for (int i = maxIndex; i >= 0; i--)
n += (int)Math.Pow(2, maxIndex - i) * binaryArray[i];
return n;
}
static double[][] normalizeData(double[][] data)
{
int numOfRows = data.Length;
int lenOfRow = data[0].GetLength(0);
double[][] result = new double[numOfRows][];
for (int i = 0; i < numOfRows; i++)
result[i] = normilizeRow(data[i]);
return result;
}
static double[] normilizeRow(double[] row)
{
int lenOfRow = row.GetLength(0);
double[] result = new double[lenOfRow];
for (int i = 0; i < lenOfRow; i++) result[i] = 0;
double N = 0;
foreach (double num in row) N += num * num;
if (N != 0) {
for (int j = 0; j < lenOfRow; j++)
{
result[j] = (row[j] / Math.Sqrt(N));
}
}
return result;
}
Я пытаюсь редактировать параметры обучения с помощью backpropogation, но почти каждый раз, когда у меня высокий уровень train.error.
Но самая большая проблема в этом коде - это результаты. Каждый прогон кода имеет разные (и не правильные!!!) результаты. Например:
actual : 0 0 0 0 0 0 0 = #0
From NN
0 0 0 0 0 0 1
From NN (converted number)1
actual : 0 1 0 0 0 1 0 = #34
From NN
0 1 0 0 0 1 0
From NN (converted number)34
actual : 0 0 1 0 1 1 0 = #22
From NN
0 0 0 0 0 1 0
From NN (converted number)2
Или другой:
Neural Network Results:
actual : 0 0 0 0 0 0 0 = #0
From NN
0 0 0 0 1 0 1
From NN (converted number)5
actual : 0 1 0 0 0 1 0 = #34
From NN
0 1 0 0 0 1 0
From NN (converted number)34
actual : 0 0 1 0 1 1 0 = #22
From NN
0 0 0 1 1 1 1
From NN (converted number)15
Может кто-нибудь сказать мне:
1) как я могу тренировать сеть более эффективно
2) почему строки типа '{ 1, 1, 1, 1,1,1,1,2,2,2,2,2 }' (которые находятся в данных поезда) неправильно распознаются NN?
// ------------------------------------------------ -------------------
Пытаюсь нормировать данные с помощью функции Encog. Код:
public static void readCSVFileToNN(){
int numOfCol = 12;
// Define the format of the data file.
// This area will change, depending on the columns and
// format of the file that you are trying to model.
IVersatileDataSource source = new CSVDataSource("c:\\test.txt", false,
CSVFormat.DecimalPoint);
var data = new VersatileMLDataSet(source);
for (int i = 0; i < numOfCol; i++ )
data.DefineSourceColumn("freq#" +i , i, ColumnType.Nominal);
// Define the column that we are trying to predict.
ColumnDefinition outputColumn = data.DefineSourceColumn("faultNumbers", 12,
ColumnType.Nominal);
// Analyze the data, determine the min/max/mean/sd of every column.
data.Analyze();
// Map the prediction column to the output of the model, and all
// other columns to the input.
data.DefineSingleOutputOthersInput(outputColumn);
// Create feedforward neural network as the model type. MLMethodFactory.TYPE_FEEDFORWARD.
// You could also other model types, such as:
// MLMethodFactory.SVM: Support Vector Machine (SVM)
// MLMethodFactory.TYPE_RBFNETWORK: RBF Neural Network
// MLMethodFactor.TYPE_NEAT: NEAT Neural Network
// MLMethodFactor.TYPE_PNN: Probabilistic Neural Network
var model = new EncogModel(data);
model.SelectMethod(data, MLMethodFactory.TypeFeedforward);
// Send any output to the console.
model.Report = new ConsoleStatusReportable();
// Now normalize the data. Encog will automatically determine the correct normalization
// type based on the model you chose in the last step.
data.Normalize();
// Hold back some data for a final validation.
// Shuffle the data into a random ordering.
// Use a seed of 1001 so that we always use the same holdback and will get more consistent results.
model.HoldBackValidation(0.3, true, 1001);
// Choose whatever is the default training type for this model.
model.SelectTrainingType(data);
// Use a 5-fold cross-validated train. Return the best method found.
var bestMethod = (IMLRegression)model.Crossvalidate(2, true);
// Display the training and validation errors.
Console.WriteLine(@"Training error: " + model.CalculateError(bestMethod, model.TrainingDataset));
Console.WriteLine(@"Validation error: " + model.CalculateError(bestMethod, model.ValidationDataset));
// Display our normalization parameters.
NormalizationHelper helper = data.NormHelper;
Console.WriteLine(helper.ToString());
// Display the final model.
Console.WriteLine(@"Final model: " + bestMethod);
source.Close();
// test work of model on the example:
IMLData input = helper.AllocateInputVector();
var line = new String[numOfCol];
var result = new StringBuilder();
// в качестве примера возьмем сигнатуру [5,5,..,5] под номером 15
for (int i = 0; i < numOfCol; i++)
line[i] = 5.ToString();
String correct = 15.ToString();
// нормализуем входной вектор
helper.NormalizeInputVector(line, ((BasicMLData) input).Data, false);
// производим поиск по НС
IMLData output = bestMethod.Compute(input);
// выводим результат
String faultChosen = helper.DenormalizeOutputVectorToString(output)[0];
result.Append(line);
result.Append(" -> predicted: ");
result.Append(faultChosen);
result.Append("(correct: ");
result.Append(correct);
result.Append(")");
Console.WriteLine(result.ToString());
}
Но результаты все еще плохие. Я делаю эту функцию ~10 раз и ни один из результатов не был правильным
1 ответ
Ваша проблема в том, что нормализация каждой строки не зависит от других строк. Например, первая строка будет делением каждого значения на 27, вторая строка будет делением каждого числа на 394. Другим источником проблем может быть необходимость нормализовать не каждую строку независимо, но все строки должны быть нормализованы согласно некоторому правилу, Затем вы должны применить то же правило нормализации для вашего ввода. Я предлагаю вам посмотреть на функцию нормализации в Encog.