【问题标题】:Problem with simple artificial neural network -- adding简单人工神经网络的问题——添加
【发布时间】:2011-08-16 09:50:03
【问题描述】:

我正在尝试使一个简单的人工神经网络与反向传播算法一起工作。我已经创建了一个 ANN,并且我相信我已经正确地实现了 BP 算法,但我当然可能是错的。

现在,我正在尝试通过给它两个介于 0 和 0.5 之间的随机数 (a, b) 并让它相加来训练网络。然后,当然,每次网络给出的输出都会与 a + b 的理论答案进行比较(这总是可以通过 sigmoid 函数实现)。

奇怪的是,输出总是收敛到 0 和 1 之间的一个数字(因为它必须是 sigmoid 函数),但我输入的随机数似乎对它没有影响。

编辑:抱歉,它似乎没有收敛。这是输出的图像:

权重在 -1 和 1 之间随机分布,但我也尝试过在 0 和 1 之间。

我还尝试给它两个常数 (0.35,0.9) 并尝试训练它吐出 0.5。这很有效并且很快收敛到 0.5。如果我给它 0 和 1 之间的任意两个随机数,我还训练它吐出 0.5,这也有效。

如果相反,我的目标是:

vector<double> target;
target.push_back(.5);

然后它会很快收敛,即使是随机输入:

我尝试了几个不同的网络,因为我可以很容易地向我的网络添加层。我使用的标准是一个有两个输入,一层有 2 个神经元,第二层只有一个神经元(输出神经元)。但是,我也尝试过添加几层,并在其中添加神经元。它似乎没有改变任何东西。我的学习率等于 1.0,虽然我试过等于 0.5,但差别不大。

有人知道我可以尝试什么吗?

这甚至是 ANN 能够做到的吗?我无法想象它不会,因为他们可以被训练来做如此复杂的事情。

有什么建议吗?谢谢!

这是我训练它的地方:

//Initialize it. This will be one with 2 layers, the first having 2 Neurons and the second (output layer) having 1.
vector<int> networkSize;
networkSize.push_back(2);
networkSize.push_back(1);
NeuralNetwork myNet(networkSize,2);

for(int i = 0; i<5000; i++){
    double a = randSmallNum();
    double b = randSmallNum();
    cout << "\n\n\nInputs: " << a << ", " << b << " with expected target: " << a + b;

    vector<double> myInput;
    myInput.push_back(a);   
    myInput.push_back(b);   

    vector<double> target;
    target.push_back(a + b);

    cout << endl << "Iteration " << i;
    vector<double> output = myNet.backPropagate(myInput,target);
    cout << "Output gotten: " << output[0];
    resultPlot << i << "\t" << abs(output[0] - target[0]) << endl;
}

编辑:我设置了我的网络并一直遵循本指南:A pdf。我实现了“Worked example 3.1”并得到了与他们完全相同的结果,所以我认为我的实现是正确的,至少就他们而言是正确的。

【问题讨论】:

  • 由于神经网络建立在连接的神经元之上,并且每个神经元本身都是带有加权输入的加法器,因此我认为您试图达到的目标在某种程度上是错误定义的。因此,要添加两个数字,网络的权重必须设置为“1”,并且在使用标准 sigmoid 函数时输出只能介于 0 或 1 之间。

标签: c++ neural-network


【解决方案1】:

正如@macs 所说,标准 sigmoid 的最大输出为 1,因此,如果您尝试从 [0, 1] 中添加 n 个数字,那么您的目标应该被归一化,即 sum(A1, A2, ... , 一个) / n.

【讨论】:

  • @macs,@vines,对不起,我应该更具体一些。这两个数字介于 0 和 0.5 之间,因此它们的总和始终可以通过 sigmoid 函数获得。让我在我原来的帖子中解决这个问题。
【解决方案2】:

在这样的模型中,sigmoid 函数(在输出层和中间层中)主要用于产生类似于 0/1 切换的东西,同时仍然是一个连续函数,所以用它来表示一个数字范围不是这种网络的设计目的。这是因为它的设计主要考虑了分类问题。 当然,还有其他 NN 模型可以做这种事情(例如,将 sigmoid 放在输出上,并将其保留为子节点的总和)。

如果您可以根据输入分类重新定义模型,您可能会得到更好的结果。

网络更适合的类似任务的一些示例:

  1. 测试输出是否大于或小于某个常数 - 这应该很容易。
  2. 输出:一系列输出,每个代表一个不同的潜在值(例如,一个输出代表 0 到 10 之间的值,一个代表“大于 10”,一个代表“小于 0”)。您将希望您的网络将结果四舍五入到最接近的整数
  3. 一个棘手的问题是尝试通过具有多个输出节点来创建输出的布尔表示。

不过,这些都不会为您提供您可能想要的精度,因为 NN 本质上更“模糊”

【讨论】:

  • 感谢您的回复!嗯,好吧,我想我可能误解了 ANN。但我仍然想弄清楚它们。所以我尝试了你的第一个问题,如下所示:double a = randSmallNum2(); double b = 0; if(max(a,.5)==a){ b = 1; } cout &lt;&lt; "\n\n\nInputs: " &lt;&lt; a &lt;&lt; " with expected target: " &lt;&lt; b; vector&lt;double&gt; myInput; myInput.push_back(a); vector&lt;double&gt; target; target.push_back(b); vector&lt;double&gt; output = myNet.backPropagate(myInput,target); 当然,在 for 循环中。它不会每次都给我 0 或 1,对吧?谢谢!
  • 实际上通过示例 #1 我的意思是输入参数的总和是否大于某个数字(不知何故我从描述中删除了该部分)。你所做的甚至更简单一些,对于神经网络来说应该很容易学习。尽管如此,sigmoid 函数几乎不会给你精确的 0 或 1,但应该给你非常接近它们的数字(因此,将 0.95 视为 1,将 0.05 视为 0。你可以选择 0.5 作为阈值)。
  • 嗯...我将进行一些诊断以打印每个级别的信息,然后返回结果...谢谢!
  • 好的,所以我让我的程序吐出了很多数字,并完成了示例 3.1 在我链接到的 PDF 中所做的每一步。我注意到他们的一般算法和他们的例子之间存在差异。在一般情况下,他们找到一层的输出误差,然后找到该层的新权重,然后重复下一层。但是,当找到下一层的输出错误时,在他们的算法中,他们说使用前一层的旧(未更新的权重),但在他们的示例中,他们使用更新的权重。这可能有很大的不同。哪个是对的?谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-11-19
  • 2011-01-31
  • 2022-01-08
  • 1970-01-01
  • 2019-10-17
  • 2011-01-22
  • 2011-07-13
相关资源
最近更新 更多