【问题标题】:How to improve accuracy of a FeedForward Neural Network?如何提高前馈神经网络的准确性?
【发布时间】:2023-06-15 12:07:01
【问题描述】:

我想用这个神经网络绘制 * 的标志:

NN 应该理想地变为 [r, g, b] = f([x, y])。换句话说,它应该返回给定坐标对的 RGB 颜色。 FFNN 非常适用于圆形或盒子等简单形状。例如,在几千个 epoch 之后,一个圆看起来像这样:

自己试试吧:https://codepen.io/adelriosantiago/pen/PoNGeLw


但是,由于 * 的徽标要复杂得多,即使经过数千次迭代,FFNN 的结果也有些差:

从左到右:

  1. * 的 256 色徽标。
  2. 有 15 个隐藏神经元:左手柄永远不会出现。
  3. 50 个隐藏神经元:总体上效果很差。
  4. 0.03 作为学习率:在结果中显示为蓝色(原始图像中没有蓝色)
  5. 学习率随时间递减:左侧手柄出现,但其他细节现在丢失。

自己试试吧:https://codepen.io/adelriosantiago/pen/xxVEjeJ

一些感兴趣的参数是synaptic.Architect.Perceptron 定义和learningRate 值。


如何提高此 NN 的准确性?

你能改进sn-p吗?如果是这样,请解释你做了什么。如果有更好的神经网络架构来解决这类工作,您能否提供一个示例?

附加信息:

【问题讨论】:

    标签: javascript neural-network artificial-intelligence training-data synaptic.js


    【解决方案1】:

    通过添加另一层,您可以获得更好的结果:

    let perceptron = new synaptic.Architect.Perceptron(2, 15, 10, 3)
    

    您可以做一些小的改进来提高效率(略微): 这是我的优化代码:

    const width = 125
    const height = 125
    const outputCtx = document.getElementById("output").getContext("2d")
    const iterationLabel = document.getElementById("iteration")
    const stopAtIteration = 3000
    let perceptron = new synaptic.Architect.Perceptron(2, 15, 10, 3)
    let iteration = 0
    
    let inputData = (() => {
      const tempCtx = document.createElement("canvas").getContext("2d")
      tempCtx.drawImage(document.getElementById("input"), 0, 0)
      return tempCtx.getImageData(0, 0, width, height)
    })()
    
    const getRGB = (img, x, y) => {
      var k = (height * y + x) * 4;
      return [
        img.data[k] / 255, // R
        img.data[k + 1] / 255, // G
        img.data[k + 2] / 255, // B
        //img.data[(height * y + x) * 4 + 3], // Alpha not used
      ]
    }
    const paint = () => {
      var imageData = outputCtx.getImageData(0, 0, width, height)
      for (let x = 0; x < width; x++) {
        for (let y = 0; y < height; y++) {
          var rgb = perceptron.activate([x / width, y / height])
          var k = (height * y + x) * 4;
          imageData.data[k] = rgb[0] * 255
          imageData.data[k + 1] = rgb[1] * 255
          imageData.data[k + 2] = rgb[2] * 255
          imageData.data[k + 3] = 255 // Alpha not used
        }
      }
      outputCtx.putImageData(imageData, 0, 0)
    
      setTimeout(train, 0)
    }
    
    const train = () => {
      iterationLabel.innerHTML = ++iteration
    
      if (iteration > stopAtIteration) return
    
      let learningRate = 0.01 / (1 + 0.0005 * iteration) // Attempt with dynamic learning rate
      //let learningRate = 0.01 // Attempt with non-dynamic learning rate
          
      for (let x = 0; x < width; x += 1) {
        for (let y = 0; y < height; y += 1) {
          perceptron.activate([x / width, y / height])
          perceptron.propagate(learningRate, getRGB(inputData, x, y))
        }
      }
      paint()
    }
    
    const startTraining = (btn) => {
      btn.disabled = true
      train()
    }
    

    编辑:我制作了另一个 CodePen,效果更好:

    https://codepen.io/xurei/pen/KKzWLxg

    顺便说一句,它很可能是过度拟合的。 感知器定义:

    let perceptron = new synaptic.Architect.Perceptron(2, 8, 15, 7, 3)
    

    【讨论】:

    • 您可以尝试的另一件事是使用 RGB 以外的其他东西。我相信 Lab* 或 HSV 颜色空间可能效果更好。
    • 另外,您的误差函数目前是线性的。我的直觉是,均方误差也可能会更好。
    • 谢谢!结果看起来还不错。赏金时间已过,我决定将其奖励给你。我唯一真正想知道的是新价值观背后的原因。基本上如何选择合适的?运气?谢谢!
    • 感谢您的奖励,非常感谢 :-) 回答您的问题:运气和经验的组合。基本上,只有一层的感知器就像一个线性聚类算法(即它可以定义一个分隔空间的平面)。每个额外的层都允许 NN 将输入转换为另一种更容易线性分割的形式。基于此,我的想法是“图像太复杂而无法线性分离,让我们尝试额外的层”。检查内核技巧以获取更多理论:en.wikipedia.org/wiki/Kernel_method.
    【解决方案2】:

    从 Bhiksha Raj 的讲座/slides(从幻灯片 62 开始)中获得一些见解,总结如下:

    可以假设每个节点都像一个线性分类器,在单层神经网络中多个节点的组合可以逼近任何基本形状。例如,一个矩形可以由每条线的4个节点组成,假设每个节点对一条线有贡献,并且形状可以由最终的输出层来近似。

    回到圆形等复杂形状的总结,它可能需要一层中的无限节点。或者这可能适用于具有两个不相交形状(非重叠三角形和矩形)的单层。但是,这仍然可以使用超过 1 个隐藏层来学习。其中,第 1 层学习基本形状,然后第 2 层近似它们的不相交组合。

    因此,您可以假设此徽标是不相交的矩形组合(5 个橙色矩形和 3 个灰色矩形)。我们可以在第一个隐藏层中使用至少 32 个节点,在第二个隐藏层中使用几个节点。但是,我们无法控制每个节点学习的内容。因此,比所需神经元多一些神经元应该是有帮助的。

    【讨论】:

      最近更新 更多