4

我应该做的事情。我有一个黑白图像(100x100px):Backprop实施问题

alt text

我应该来训练backpropagation神经网络与此图像。输入是图像的x,y坐标(从0到99),输出是1(白色)或0(黑色)。

一旦网络已经学会了,我希望它能够根据图像的重量重现图像,并获得最接近原始图像的图像。

这里是我的backprop实现:

import os 
import math 
import Image 
import random 
from random import sample 

#------------------------------ class definitions 

class Weight: 
    def __init__(self, fromNeuron, toNeuron): 
     self.value = random.uniform(-0.5, 0.5) 
     self.fromNeuron = fromNeuron 
     self.toNeuron = toNeuron 
     fromNeuron.outputWeights.append(self) 
     toNeuron.inputWeights.append(self) 
     self.delta = 0.0 # delta value, this will accumulate and after each training cycle used to adjust the weight value 

    def calculateDelta(self, network): 
     self.delta += self.fromNeuron.value * self.toNeuron.error 

class Neuron: 
    def __init__(self): 
     self.value = 0.0  # the output 
     self.idealValue = 0.0 # the ideal output 
     self.error = 0.0  # error between output and ideal output 
     self.inputWeights = [] 
     self.outputWeights = [] 

    def activate(self, network): 
     x = 0.0; 
     for weight in self.inputWeights: 
      x += weight.value * weight.fromNeuron.value 
     # sigmoid function 
     if x < -320: 
      self.value = 0 
     elif x > 320: 
      self.value = 1 
     else: 
      self.value = 1/(1 + math.exp(-x)) 

class Layer: 
    def __init__(self, neurons): 
     self.neurons = neurons 

    def activate(self, network): 
     for neuron in self.neurons: 
      neuron.activate(network) 

class Network: 
    def __init__(self, layers, learningRate): 
     self.layers = layers 
     self.learningRate = learningRate # the rate at which the network learns 
     self.weights = [] 
     for hiddenNeuron in self.layers[1].neurons: 
      for inputNeuron in self.layers[0].neurons: 
       self.weights.append(Weight(inputNeuron, hiddenNeuron)) 
      for outputNeuron in self.layers[2].neurons: 
       self.weights.append(Weight(hiddenNeuron, outputNeuron)) 

    def setInputs(self, inputs): 
     self.layers[0].neurons[0].value = float(inputs[0]) 
     self.layers[0].neurons[1].value = float(inputs[1]) 

    def setExpectedOutputs(self, expectedOutputs): 
     self.layers[2].neurons[0].idealValue = expectedOutputs[0] 

    def calculateOutputs(self, expectedOutputs): 
     self.setExpectedOutputs(expectedOutputs) 
     self.layers[1].activate(self) # activation function for hidden layer 
     self.layers[2].activate(self) # activation function for output layer   

    def calculateOutputErrors(self): 
     for neuron in self.layers[2].neurons: 
      neuron.error = (neuron.idealValue - neuron.value) * neuron.value * (1 - neuron.value) 

    def calculateHiddenErrors(self): 
     for neuron in self.layers[1].neurons: 
      error = 0.0 
      for weight in neuron.outputWeights: 
       error += weight.toNeuron.error * weight.value 
      neuron.error = error * neuron.value * (1 - neuron.value) 

    def calculateDeltas(self): 
     for weight in self.weights: 
      weight.calculateDelta(self) 

    def train(self, inputs, expectedOutputs): 
     self.setInputs(inputs) 
     self.calculateOutputs(expectedOutputs) 
     self.calculateOutputErrors() 
     self.calculateHiddenErrors() 
     self.calculateDeltas() 

    def learn(self): 
     for weight in self.weights: 
      weight.value += self.learningRate * weight.delta 

    def calculateSingleOutput(self, inputs): 
     self.setInputs(inputs) 
     self.layers[1].activate(self) 
     self.layers[2].activate(self) 
     #return round(self.layers[2].neurons[0].value, 0) 
     return self.layers[2].neurons[0].value 


#------------------------------ initialize objects etc 

inputLayer = Layer([Neuron() for n in range(2)]) 
hiddenLayer = Layer([Neuron() for n in range(10)]) 
outputLayer = Layer([Neuron() for n in range(1)]) 

learningRate = 0.4 

network = Network([inputLayer, hiddenLayer, outputLayer], learningRate) 


# let's get the training set 
os.chdir("D:/stuff") 
image = Image.open("backprop-input.gif") 
pixels = image.load() 
bbox = image.getbbox() 
width = 5#bbox[2] # image width 
height = 5#bbox[3] # image height 

trainingInputs = [] 
trainingOutputs = [] 
b = w = 0 
for x in range(0, width): 
    for y in range(0, height): 
     if (0, 0, 0, 255) == pixels[x, y]: 
      color = 0 
      b += 1 
     elif (255, 255, 255, 255) == pixels[x, y]: 
      color = 1 
      w += 1 
     trainingInputs.append([float(x), float(y)]) 
     trainingOutputs.append([float(color)]) 

print "\nOriginal image ... Black:"+str(b)+" White:"+str(w)+"\n" 

#------------------------------ let's train 

for i in range(500): 
    for j in range(len(trainingOutputs)): 
     network.train(trainingInputs[j], trainingOutputs[j]) 
     network.learn() 
    for w in network.weights: 
     w.delta = 0.0 

#------------------------------ let's check 

b = w = 0 
for x in range(0, width): 
    for y in range(0, height): 
     out = network.calculateSingleOutput([float(x), float(y)]) 
     if 0.0 == round(out): 
      color = (0, 0, 0, 255) 
      b += 1 
     elif 1.0 == round(out): 
      color = (255, 255, 255, 255) 
      w += 1 
     pixels[x, y] = color 
     #print out 

print "\nAfter learning the network thinks ... Black:"+str(b)+" White:"+str(w)+"\n" 

显然,有一些问题,我的执行。上面的代码返回:

原图...黑:21白:4

后学习网络认为... 黑:25白:0

它完成如果我尝试使用更大的训练集(为了测试目的,我正在测试上面的图像中的25个像素),那也是一样的。它返回所有像素在学习后应该是黑色的。现在

,如果我使用手动训练这样设置代替:

trainingInputs = [ 
    [0.0,0.0], 
    [1.0,0.0], 
    [2.0,0.0], 
    [0.0,1.0], 
    [1.0,1.0], 
    [2.0,1.0], 
    [0.0,2.0], 
    [1.0,2.0], 
    [2.0,2.0] 
] 
trainingOutputs = [ 
    [0.0], 
    [1.0], 
    [1.0], 
    [0.0], 
    [1.0], 
    [0.0], 
    [0.0], 
    [0.0], 
    [1.0] 
] 

#------------------------------ let's train 

for i in range(500): 
    for j in range(len(trainingOutputs)): 
     network.train(trainingInputs[j], trainingOutputs[j]) 
     network.learn() 
    for w in network.weights: 
     w.delta = 0.0 

#------------------------------ let's check 

for inputs in trainingInputs: 
    print network.calculateSingleOutput(inputs) 

的输出是例如:

0.0330125791296 # this should be 0, OK 
0.953539182136 # this should be 1, OK 
0.971854575477 # this should be 1, OK 
0.00046146137467 # this should be 0, OK 
0.896699762781 # this should be 1, OK 
0.112909223162 # this should be 0, OK 
0.00034058462280 # this should be 0, OK 
0.0929886299643 # this should be 0, OK 
0.940489647869 # this should be 1, OK 

换句话说网络猜到所有像素右侧(包括黑色和白色)。为什么说如果我使用图像中的实际像素而不是像上面那样的硬编码训练集,所有的像素应该是黑色的?

我试图改变隐藏层中的神经元数量(最多100个神经元),但没有成功。

这是一个家庭作业。

这也是我的关于backprop的previous question的延续。

+0

为什么你把它标记为MATLAB?它看起来像你只使用Python。 – gnovice 2010-11-03 20:20:21

+0

@gnovice嗯,我认为MATLAB常常用于编程神经网络和其他AI内容,所以我认为一些MATLAB程序员可能会发现我的算法中有一个错误,即使它是用Python编写的。 – 2010-11-03 20:33:49

回答

5

这已经有一段时间,但我没有得到我在这个东西的程度,所以我觉得希望它的一些已经忍受了。

从我所知道的情况来看,你用输入设置过度地加载了中间层神经元。也就是说,您的输入集由10,000个离散输入值(100px×100px)组成;你试图将这10,000个值编码成10个神经元。这种编码水平很难(我怀疑这是可能的,但肯定很难);至少,你需要大量的训练(超过500次运行)才能合理地重现它。即使有100个神经元用于中间层,您也会看到相对密集的压缩级别(100像素到1个神经元)。

至于如何处理这些问题;好吧,这很棘手。你可以大幅增加你的中间神经元的数量,并且你会得到一个合理的效果,但是这当然需要很长时间来训练。但是,我认为可能有不同的解决方案;如果可能的话,你可能会考虑使用极坐标而不是输入的笛卡尔坐标;对输入模式的快速观察表明对称性很高,并且实际上你会看到沿着角度坐标具有可重复的可预测变形的线性模式,这看起来会很好地编码在少量中间层神经元中。

这东西很棘手;为模式编码提供一个通用的解决方案(就像你原来的解决方案那样)非常复杂,通常可以(即使有大量的中间层神经元)需要大量的训练通过;另一方面,一些先进的启发式任务分解和一点问题重新定义(即,从笛卡尔坐标系到极坐标系的提前转换)可以为明确定义的问题集提供良好的解决方案。其中,当然是永久的磨擦;一般的解决方案很难实现,但稍微更具体的解决方案确实相当不错。

有趣的东西,无论如何!

+1

+1极好的建议,特别是极坐标 – Amro 2010-11-03 23:44:56

+0

@Amro:thx,对称性非常清楚地适用于极坐标。 – 2010-11-03 23:46:27

+1

@McWafflestix:在解决机器学习问题时,最重要的是具有有用的特征(预处理步骤),算法考虑其次(通常可以使用某种交叉验证为您的模型找到最佳参数) – Amro 2010-11-04 00:02:29