Я пытаюсь создать пользовательскую библиотеку машинного обучения на C #, я достаточно исследовал эту тему.Мой первый пример (оценщик XOR) был успешным, я смог снизить среднюю потерю почти до нуля.Затем я попытался построить модель для классификации рукописных цифр (с использованием текстовой базы данных MNIST). Проблема заключается в том, что независимо от того, как я настраиваю модель, я всегда застреваю на определенной средней потере по набору данных. Вторая проблема, потому что MNISTнабор данных очень большой, для вычисления модели требуется много времени, может быть, я могу воспользоваться некоторыми советами о том, как выполнять самые медленные части алгоритма (я использую стохастический градиентный спуск). Я собираюсь показать основной метод, которыйвыполняет большую часть работы.
Я пытался использовать функции потери MSE и CrossEntropy, а также функции активации tanh, sigmoid, reLu и softPlus.Модель, которую я пытаюсь построить, является четырехслойной.Первый слой, 784 входных нейронов;Во-вторых, 16 нейронов, сигмовидная кишка;В-третьих, 16 нейронов, сигмовидный и выходной слой, 10 нейронов (одна горячая закодированная цифра) с сигмоидом.Я знаю, что приведенный ниже код не может быть минимальным воспроизводимым примером, но он представляет алгоритм, который я пытаюсь изобразить.Я также загрузил решение в GitHub, может быть, кто-нибудь может помочь мне разобраться в проблеме.Это ссылка https://github.com/juan-carvajal/MachineLearningFramework Сначала запустится метод Main приложения, запустит классификатор XOR, который работает нормально.Тогда MNIST классификатор.
Модель лучше всего представлена здесь:
DataSet dataSet = new DataSet("mnist2.txt", ' ', 10, false);
//This creates a model with batching=128 , learningRate=0.5 and
//CrossEntropy loss function
var p = new Perceptron(128, 0.5, ErrorFunction.CrossEntropy())
.Layer(784, ActivationFunction.Sigmoid())
.Layer(16, ActivationFunction.Sigmoid())
.Layer(16, ActivationFunction.Sigmoid())
.Layer(10, ActivationFunction.Sigmoid());
//1000 is the number of epochs
p.Train2(dataSet, 1000);
Фактический алгоритм (стохастический градиентный спуск):
Console.WriteLine("Initial Loss:"+ CalculateMeanErrorOverDataSet(dataSet));
for (int i = 0; i < epochs; i++)
{
//Shuffle the data in every step
dataSet.Shuffle();
List<DataRow> batch = dataSet.NextBatch(this.Batching);
//Gets random batch from the dataSet
int count = 0;
foreach (DataRow example in batch)
{
count++;
double[] result = this.FeedForward(example.GetFeatures());
double[] labels = example.GetLabels();
if (result.Length != labels.Length)
{
throw new Exception("Inconsistent array size, Incorrect implementation.");
}
else
{
//What follows is the calculation of the gradient for this example, every example affects the current gradient, then all those changes are averaged an every parameter is updated.
double error = CalculateExampleLost(example);
for (int l = this.Layers.Count - 1; l > 0; l--)
{
if (l == this.Layers.Count - 1)
{
for (int j = 0; j < this.Layers[l].CostDerivatives.Length; j++)
{
this.Layers[l].CostDerivatives[j] = ErrorFunction.GetDerivativeValue(labels[j], this.Layers[l].Activations[j]);
}
}
else
{
for (int j = 0; j < this.Layers[l].CostDerivatives.Length; j++)
{
double acum = 0;
for (int j2 = 0; j2 < Layers[l + 1].Size; j2++)
{
acum += Layers[l + 1].WeightMatrix[j2, j] * this.Layers[l+1].ActivationFunction.GetDerivativeValue(Layers[l + 1].WeightedSum[j2]) * Layers[l + 1].CostDerivatives[j2];
}
this.Layers[l].CostDerivatives[j] = acum;
}
}
for (int j = 0; j < this.Layers[l].Activations.Length; j++)
{
this.Layers[l].BiasVectorChangeRecord[j] += this.Layers[l].ActivationFunction.GetDerivativeValue(Layers[l].WeightedSum[j]) * Layers[l].CostDerivatives[j];
for (int k = 0; k < Layers[l].WeightMatrix.GetLength(1); k++)
{
this.Layers[l].WeightMatrixChangeRecord[j, k] += Layers[l - 1].Activations[k]
* this.Layers[l].ActivationFunction.GetDerivativeValue(Layers[l].WeightedSum[j])
* Layers[l].CostDerivatives[j];
}
}
}
}
}
TakeGradientDescentStep(batch.Count);
if ((i + 1) % (epochs / 10) == 0)
{
Console.WriteLine("Epoch " + (i + 1) + ", Avg.Loss:" + CalculateMeanErrorOverDataSet(dataSet));
}
}
Это пример того, как локальные минимумы выглядят в текущей модели.В своем исследовании я обнаружил, что подобные модели могут обеспечивать точность до 90%.Моя модель едва получила 10%.