为什么我的机器学习算法会卡住?
Why Is My Machine Learning Algorithm Getting Stuck?
所以我的 C# 机器学习项目碰壁了。我正在尝试训练一种算法来识别数字。由于这只是一个练习,我有一个包含 200 个数字的图像集(0 到 9 每个 20 个)。显然,如果我想要一个经过适当训练的算法,我会使用更强大的训练集,但这只是一个练习,看看我能否首先让它发挥作用。我可以达到 60% 的准确率,但不会超过那个。我一直在研究激活函数,据我所知,LeakyRelu 是我应该使用的函数。但是,如果我全面使用 LeakyRelu 函数,那么它不会学到任何东西,而且我不确定如何将 LeakyRelu 用作输出激活函数。使用 sigmoid 或 tanh 作为输出激活函数对我来说更有意义。这是一个代码块,它创建了用于反向传播的数组:
public static float ACTIVE_VALUE = 1;
public static float INACTIVE_VALUE = -1;
// This is specifically designed for a algorithm that will detect a number between 0 - 9
public static float[] valueToArray(int value)
{
switch (value)
{
case 0:
return new float[] { ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 1:
return new float[] { INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 2:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 3:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 4:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 5:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 6:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 7:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 8:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE };
case 9:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE };
default:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
}
}
我不知道如何使用类似这样的东西来读取 LeakyRelu 输出。所以我认为最好的选择是对输入层和隐藏层使用 LeakyRelu,然后对输出层使用 tanh 或 sigmoid。然而,这会产生一个问题,因为 sigmoid 只是 returns NAN(由于我理解的舍入误差)和 tanh returns -1 或 1 但两者之间没有任何东西。如果我全面使用 tanh,它可以工作,并且可以学习,但它只能达到 60% 的准确率,然后停止在那里发展。我认为这是由于 "vanishing gradient" 问题造成的。但是,如果我对输入层和隐藏层使用 LeakyRelu,然后对输出使用 tanh,它会保持在 12-14%(这与随机猜测数字一样好)。
我正在使用从 github 用户那里得到的神经网络:
https://github.com/kipgparker/BackPropNetwork
他在网上发布了一篇关于神经网络的研究论文,是 google 上的热门文章之一。这就是我最初找到它的方式。我在 GitHub 上以 zip 的形式在此处发布了我的完整项目:
https://github.com/JoshuaC0352/Machine-Learning
我不反对使用可以从 nuget 获得的库,例如 SiaNet (https://scisharp.github.io/SiaNet/api/SiaNet.Layers.AvgPooling1D.html),但是我已经非常熟悉我目前正在使用的库,所以我有点不愿意切换,因为我觉得我几乎是从头开始,因为我必须学习如何与一个全新的库交互。
编辑:附加代码。这是我的 while 循环,它读取图像并训练算法:
public static void singleThread()
{
int batchSize = 10000;
int rangeLow = 0;
int rangeHi = 9;
int hits = 0;
while (true)
{
// alternates between training and testing
//Console.WriteLine("Training... ");
for (int i = 0; i < batchSize; i++)
{
// Give a training progress report every 100 iterations, this should increase performance
if (i % 100 == 0)
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write("Training: ");
Console.Write("(" + (((float)i / (float)batchSize) * 100) + "%)");
Console.Write(" ");
}
// randomly select an image from the list
int number = rng.Next(rangeLow, rangeHi);
int index = rng.Next(1, 20);
Bitmap loadedImage = (Bitmap)Image.FromFile("Train/" + number + "/" +
index + ".png", true);
int indexLocation = 0;
// Convert the image into a grayScale value
for (int x = 0; x < loadedImage.Width; x++)
{
for (int y = 0; y < loadedImage.Height; y++)
{
Color pixel = loadedImage.GetPixel(x, y);
int grayValue = (int)((pixel.R * 0.3) + (pixel.G * 0.59) + (pixel.B * 0.11));
//Console.WriteLine(grayValue);
networkInputs[indexLocation] = grayValue;
indexLocation++;
}
}
// The network will guess what the image is, and return the guess as a float array
float[] guess = currentNetwork.BackPropagate(networkInputs, Interface.valueToArray(number));
// This if statement checks if the guess was correct
if (Interface.guessToValue(guess) == number)
{
hits++;
}
}
currentNetwork.Performance = ((float) hits / (float) batchSize);
hits = 0;
Console.WriteLine("Score: " + (currentNetwork.Performance * 100) + "%");
}
}
为未来的访问者添加了答案
尝试将灰度值从 0-255 区间转换为 0-1
间隔。只需将每个像素除以 255。LeakyRELU 的事实
表现优于 sigmoid 或 tanh 是因为值太
大。在某种意义上他们被 tanh 和 sigmoid 虐待
并由计算机四舍五入为整数。
仔细看看神经网络的权重是怎样的
如果您打算使用 tanh 或 sigmoid,则初始化。
既然是分类问题,我推荐你使用softmax
输出层中的激活函数。
经过数据预处理后,@JMC0352 的准确率只有 88%
你只得到 88% 的原因是因为神经网络(单独)不适合图像识别。卷积神经网络用于此目的。为了直观地理解问题,您可以将原始神经网络想象成一起理解所有像素,其中 conv。网。理解相对接近的像素。
所以我的 C# 机器学习项目碰壁了。我正在尝试训练一种算法来识别数字。由于这只是一个练习,我有一个包含 200 个数字的图像集(0 到 9 每个 20 个)。显然,如果我想要一个经过适当训练的算法,我会使用更强大的训练集,但这只是一个练习,看看我能否首先让它发挥作用。我可以达到 60% 的准确率,但不会超过那个。我一直在研究激活函数,据我所知,LeakyRelu 是我应该使用的函数。但是,如果我全面使用 LeakyRelu 函数,那么它不会学到任何东西,而且我不确定如何将 LeakyRelu 用作输出激活函数。使用 sigmoid 或 tanh 作为输出激活函数对我来说更有意义。这是一个代码块,它创建了用于反向传播的数组:
public static float ACTIVE_VALUE = 1;
public static float INACTIVE_VALUE = -1;
// This is specifically designed for a algorithm that will detect a number between 0 - 9
public static float[] valueToArray(int value)
{
switch (value)
{
case 0:
return new float[] { ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 1:
return new float[] { INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 2:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 3:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 4:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 5:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 6:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 7:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
case 8:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE, INACTIVE_VALUE };
case 9:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, ACTIVE_VALUE };
default:
return new float[] { INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE,
INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE, INACTIVE_VALUE };
}
}
我不知道如何使用类似这样的东西来读取 LeakyRelu 输出。所以我认为最好的选择是对输入层和隐藏层使用 LeakyRelu,然后对输出层使用 tanh 或 sigmoid。然而,这会产生一个问题,因为 sigmoid 只是 returns NAN(由于我理解的舍入误差)和 tanh returns -1 或 1 但两者之间没有任何东西。如果我全面使用 tanh,它可以工作,并且可以学习,但它只能达到 60% 的准确率,然后停止在那里发展。我认为这是由于 "vanishing gradient" 问题造成的。但是,如果我对输入层和隐藏层使用 LeakyRelu,然后对输出使用 tanh,它会保持在 12-14%(这与随机猜测数字一样好)。
我正在使用从 github 用户那里得到的神经网络: https://github.com/kipgparker/BackPropNetwork
他在网上发布了一篇关于神经网络的研究论文,是 google 上的热门文章之一。这就是我最初找到它的方式。我在 GitHub 上以 zip 的形式在此处发布了我的完整项目: https://github.com/JoshuaC0352/Machine-Learning
我不反对使用可以从 nuget 获得的库,例如 SiaNet (https://scisharp.github.io/SiaNet/api/SiaNet.Layers.AvgPooling1D.html),但是我已经非常熟悉我目前正在使用的库,所以我有点不愿意切换,因为我觉得我几乎是从头开始,因为我必须学习如何与一个全新的库交互。
编辑:附加代码。这是我的 while 循环,它读取图像并训练算法:
public static void singleThread()
{
int batchSize = 10000;
int rangeLow = 0;
int rangeHi = 9;
int hits = 0;
while (true)
{
// alternates between training and testing
//Console.WriteLine("Training... ");
for (int i = 0; i < batchSize; i++)
{
// Give a training progress report every 100 iterations, this should increase performance
if (i % 100 == 0)
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write("Training: ");
Console.Write("(" + (((float)i / (float)batchSize) * 100) + "%)");
Console.Write(" ");
}
// randomly select an image from the list
int number = rng.Next(rangeLow, rangeHi);
int index = rng.Next(1, 20);
Bitmap loadedImage = (Bitmap)Image.FromFile("Train/" + number + "/" +
index + ".png", true);
int indexLocation = 0;
// Convert the image into a grayScale value
for (int x = 0; x < loadedImage.Width; x++)
{
for (int y = 0; y < loadedImage.Height; y++)
{
Color pixel = loadedImage.GetPixel(x, y);
int grayValue = (int)((pixel.R * 0.3) + (pixel.G * 0.59) + (pixel.B * 0.11));
//Console.WriteLine(grayValue);
networkInputs[indexLocation] = grayValue;
indexLocation++;
}
}
// The network will guess what the image is, and return the guess as a float array
float[] guess = currentNetwork.BackPropagate(networkInputs, Interface.valueToArray(number));
// This if statement checks if the guess was correct
if (Interface.guessToValue(guess) == number)
{
hits++;
}
}
currentNetwork.Performance = ((float) hits / (float) batchSize);
hits = 0;
Console.WriteLine("Score: " + (currentNetwork.Performance * 100) + "%");
}
}
为未来的访问者添加了答案
尝试将灰度值从 0-255 区间转换为 0-1 间隔。只需将每个像素除以 255。LeakyRELU 的事实 表现优于 sigmoid 或 tanh 是因为值太 大。在某种意义上他们被 tanh 和 sigmoid 虐待 并由计算机四舍五入为整数。
仔细看看神经网络的权重是怎样的 如果您打算使用 tanh 或 sigmoid,则初始化。
既然是分类问题,我推荐你使用softmax 输出层中的激活函数。
经过数据预处理后,@JMC0352 的准确率只有 88%
你只得到 88% 的原因是因为神经网络(单独)不适合图像识别。卷积神经网络用于此目的。为了直观地理解问题,您可以将原始神经网络想象成一起理解所有像素,其中 conv。网。理解相对接近的像素。