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