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

После обучения сеть думает ... Black: 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 нейронов) без успеха.

Это домашнее задание.

Это также является продолжением моего previous question о backprop.

+0

Почему вы отметили это как MATLAB? Похоже, вы используете только Python. – gnovice

+0

@gnovice Ну, я думаю, что MATLAB часто используется для программирования нейронных сетей и других объектов AI, поэтому я подумал, что некоторые программисты MATLAB могут обнаружить ошибку в моем алгоритме, даже если она написана на Python. –

ответ

5

Прошло некоторое время, но я получил степень в этом, поэтому я думаю, что некоторые из них застряли.

Из того, что я могу сказать, вы слишком глубоко перегружаете свои нейроны среднего слоя с помощью набора входных данных. То есть ваш набор входных данных состоит из 10 000 дискретных входных значений (100 pix x 100 pix); вы пытаетесь кодировать эти 10 000 значений в 10 нейронов. Этот уровень кодирования тяжелый (я подозреваю, что это возможно, но, безусловно, сложно); по крайней мере, вам понадобится много тренировок (более 500 прогонов), чтобы заставить его воспроизводить разумно. Даже при 100 нейронах для среднего слоя вы смотрите на относительно плотный уровень сжатия (100 пикселей на 1 нейрон).

Что касается того, что делать с этими проблемами; хорошо, это сложно. Вы можете резко увеличить количество средних нейронов, и вы получите разумный эффект, но, конечно, это займет много времени, чтобы тренироваться.Однако я думаю, что может быть другое решение; если возможно, вы можете использовать полярные координаты вместо декартовых координат для ввода; быстрое наблюдение шаблона ввода указывает на высокий уровень симметрии, и эффективно вы будете смотреть на линейный рисунок с повторяющейся предсказуемой деформацией вдоль угловой координаты, которая, по-видимому, будет хорошо кодироваться в небольшом числе нейронов среднего слоя.

Этот материал сложный; для общего решения для кодирования рисунка (как ваше оригинальное решение) очень сложно, и обычно (даже с большим количеством нейронов среднего слоя) требуется много тренировочных пропусков; с другой стороны, некоторая предварительная эвристическая разбивка задачи и небольшое переосмысление проблемы (то есть переход от декартовых координат к полярным координатам) могут дать хорошие решения для хорошо определенных наборов задач. В этом, конечно же, вечный руб; общие решения трудно найти, но немного более конкретные решения могут быть довольно приятными.

Интересный материал, в любом случае!

+1

+1 отличный совет, особенно полярные координаты – Amro

+0

@Amro: thx, симметрия очень четко поддается полярным координатам. –

+1

@McWafflestix: при решении проблем машинного обучения самое главное - иметь полезные функции (шаг предварительной обработки), во-вторых, алгоритм соображений занимает второе место (обычно вы можете использовать какую-то перекрестную проверку, чтобы найти лучшие параметры для вашей модели) – Amro