【问题标题】:Why Is My Machine Learning Algorithm Getting Stuck?为什么我的机器学习算法会卡住?
【发布时间】:2020-09-20 04:14:42
【问题描述】:

所以我的 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 只返回 NAN(由于我理解的舍入错误),而 tanh 返回 -1 或 1,但两者之间没有。如果我全面使用 tanh,它可以工作,它会学习,但它只能达到 60% 的准确度,然后停止在那里开发。我认为这是由于“梯度消失”问题造成的。但是,如果我将 LeakyRelu 用于输入层和隐藏层,然后将 tanh 用于输出,它会保持在 12-14%(这与随机猜测一个数字一样好)。

我正在使用从 github 用户那里获得的神经网络: https://github.com/kipgparker/BackPropNetwork

他在网上发表了一篇关于神经网络的研究论文,该论文是谷歌上的热门文章之一。这就是我最初找到它的方式。我在 GitHub 上以 zip 的形式发布了我的完整项目: https://github.com/JoshuaC0352/Machine-Learning

我不反对使用我可以从像 SiaNet (https://scisharp.github.io/SiaNet/api/SiaNet.Layers.AvgPooling1D.html) 这样的 nuget 获得的库,但是我已经非常熟悉我目前正在使用的库,我有点不愿意切换,因为我觉得就像我几乎从头开始一样,因为我必须学习如何与一个全新的库进行交互。

编辑:附加代码。这是我的 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-255 区间转换为 0-1 区间。只需将每个像素除以 255。如果您打算使用 tanh 或 sigmoid,请仔细查看神经网络权重是如何初始化的。由于这是一个分类问题,我建议您在输出层中使用 softmax 激活函数。
  • LeakyRELU 比 sigmoid 或 tanh 表现更好的事实是因为值太大。从某种意义上说,它们被 tanh 和 sigmoid 虐待,并被计算机四舍五入为整数。
  • softmax 激活函数会在每个节点(1-0)给出一个百分比。其中所有百分比总和为 1。它会让你比 sigmoid 更有意义

标签: machine-learning deep-learning neural-network backpropagation activation-function


【解决方案1】:

为未来的访客添加了答案

  • 尝试将灰度值从 0-255 区间转换为 0-1 间隔。只需将每个像素除以 255。LeakyRELU 的事实 比 sigmoid 或 tanh 表现更好是因为值太 大。从某种意义上说,他们受到了 tanh 和 sigmoid 的虐待 并由计算机四舍五入为整数。

  • 仔细观察神经网络的权重是怎样的 如果您打算使用 tanh 或 sigmoid,则初始化。

  • 由于这是一个分类问题,我建议你使用 softmax 输出层中的激活函数。

在对数据进行预处理后,@JMC0352 的准确率仅为 88%。

之所以只获得 88%,是因为神经网络(单独)不适合图像识别。卷积神经网络就是用来解决这个问题的。为了直观地理解这个问题,你可以将原始神经网络想象成对所有像素都有意义,其中 conv.网。理解相对接近的像素。

【讨论】:

  • 感谢您的帮助。我的下一步将是研究卷积网络。
猜你喜欢
  • 2018-02-04
  • 2022-12-11
  • 2011-11-22
  • 2014-03-05
  • 2014-04-09
  • 2012-03-04
  • 2013-10-09
  • 2011-08-01
  • 1970-01-01
相关资源
最近更新 更多