问题描述
我想使用此神经网络绘制StackOverflow的徽标:
理想情况下,NN应该变为 [r,g,b] = f([x,y])。换句话说,它应该为给定的一对坐标返回RGB颜色。 FFNN非常适合简单的形状,例如圆形或盒子。例如,在数千个纪元之后,一个圆圈看起来像这样:
自己尝试:https://codepen.io/adelriosantiago/pen/PoNGeLw
但是,由于即使经过数千次迭代,StackOverflow的徽标也要复杂得多,所以FFNN的结果有些差:
从左到右:
- StackOverflow的徽标为256种颜色。
- 具有15个隐藏的神经元:永远不会出现左手柄。
- 50个隐藏的神经元:总体上效果很差。
- 0.03作为学习率:结果中显示蓝色(原始图像中没有蓝色)
- 学习速度递减:出现左手柄,但其他细节现在丢失了。
自己尝试:https://codepen.io/adelriosantiago/pen/xxVEjeJ
一些令人感兴趣的参数是synaptic.Architect.Perceptron
的定义和learningRate
的值。
如何提高该NN的准确性?
您可以改善摘要吗?如果是这样,请说明您做了什么。如果有更好的NN体系结构来解决此类工作,您可以举个例子吗?
其他信息:
- 使用的人工神经网络库:Synaptic.js
- 要在您的本地主机中运行此示例,请执行以下操作:See repository
解决方法
通过添加另一层,您可以获得更好的结果:
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,3)
let iteration = 0
let inputData = (() => {
const tempCtx = document.createElement("canvas").getContext("2d")
tempCtx.drawImage(document.getElementById("input"),0)
return tempCtx.getImageData(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,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)
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,y))
}
}
paint()
}
const startTraining = (btn) => {
btn.disabled = true
train()
}
编辑:我制作了另一个CodePen,效果更好:
https://codepen.io/xurei/pen/KKzWLxg
BTW可能过拟合。 感知器定义:
let perceptron = new synaptic.Architect.Perceptron(2,8,7,3)
,
从比克莎·拉吉(Bhiksha Raj)的演讲/ slides中获得一些见解(从幻灯片62开始),并总结如下:
可以像线性分类器那样假设每个节点,并且在神经网络的单层中多个节点的组合可以近似任何基本形状。例如,假设每个节点对一条线有贡献,则矩形可以由每条线的4个节点组成,并且形状可以由最终输出层近似。回到复杂形状(例如圆形)的摘要,它可能需要一层中的无限个节点。否则,对于具有两个不相交形状(非重叠三角形和矩形)的单层来说,这可能适用。但是,仍然可以使用多个隐藏层来学习。在那里,第一层学习基本形状,第二层学习它们的不相交组合。
因此,您可以假定此徽标是不相交的矩形的组合(橙色为5个矩形,灰色为3个矩形)。我们可以在第一个隐藏层中使用至少32个节点,在第二个隐藏层中使用几个节点。但是,我们无法控制每个节点的学习内容。因此,比所需神经元多一些的神经元应该会有所帮助。