2014-11-04 88 views
0

我目前正在研究一個open source ANN(爲了好玩和作爲一種學習體驗),最近我做了我認爲對我的代碼做了一個相對較小的更改,但由於某種原因,它使ANN運行速度提高了16倍。 (根據我至少測試)是什麼讓我的ANN大幅減少運行時間?

ANN/ANN5.py:(老ANN)

from random import uniform 


class Neuron(object): 
    def __init__(self, parents=[]): 
     self.parents = [{ 
      'neuron': parent, 
      'weight': uniform(-1, 1), 
      'slope': uniform(-1, 1), 
     } for parent in parents] 

    def calculate(self, increment=0): 
     self.output = sum([parent['neuron'].output * (parent['weight'] + increment * parent['slope']) for parent in self.parents]) > 0 

    def mutate(self, increment): 
     for parent in self.parents: 
      parent['weight'] += increment * parent['slope'] 
      parent['slope'] = uniform(-1, 1) 

    def get_genome(self): 
     return [parent['weight'] for parent in self.parents] 

    def set_genome(self, value): 
     for i, parent in enumerate(self.parents): 
      parent['weight'] = value[i] 

    genome = property(get_genome, set_genome) 


class NeuralNetwork(object): 
    def __init__(self, inputs, outputs, hidden, rows): 
     self.bias = Neuron() 
     self.neurons = [] 
     for row in xrange(rows): 
      if row == 0: 
       self.neurons.append([Neuron(parents=[]) for input_ in xrange(inputs)]) 
      elif row == rows - 1: 
       self.neurons.append([Neuron(parents=self.neurons[row - 1] + [self.bias]) for output in xrange(outputs)]) 
      else: 
       self.neurons.append([Neuron(parents=self.neurons[row - 1] + [self.bias]) for column in xrange(hidden)]) 
     self.bias.output = True 

    def calculate(self, inputs, increment=0): 
     for i, neuron_row in enumerate(self.neurons): 
      for j, neuron in enumerate(neuron_row): 
       if i == 0: 
        neuron.output = inputs[j] 
       else: 
        neuron.calculate(increment=increment) 
     return [neuron.output for neuron in self.neurons[-1]] 

    def mutate(self, increment): 
     for neuron_row in self.neurons: 
      for neuron in neuron_row: 
       neuron.mutate(increment=increment) 

    def get_genome(self): 
     genome = [] 
     for neuron_row in self.neurons[1:]: 
      genome.append([neuron.genome for neuron in neuron_row]) 
     return genome 

    def set_genome(self, value): 
     for i, neuron_row in enumerate(self.neurons[1:]): 
      for j, neuron in enumerate(neuron_row): 
       neuron.genome = value[i][j] 

    genome = property(get_genome, set_genome) 

ANN/ANN.py:(新ANN)

from random import uniform 


class Neuron(object): 
    def __init__(self, parents=[]): 
     self.parents = [{ 
      'neuron': parent, 
      'weight': uniform(-1, 1), 
      'slope': uniform(-1, 1), 
     } for parent in parents] 

    def calculate(self, increment=0): 
     self.output = sum([parent['neuron'].output * (parent['weight'] + increment * parent['slope']) for parent in self.parents]) > 0 

    def mutate(self, increment): 
     for parent in self.parents: 
      parent['weight'] += increment * parent['slope'] 
      parent['slope'] = uniform(-1, 1) 

    def get_genome(self): 
     return [parent['weight'] for parent in self.parents] 

    def set_genome(self, value): 
     for i, parent in enumerate(self.parents): 
      parent['weight'] = value[i] 

    genome = property(get_genome, set_genome) 


class NeuralNetwork(object): 
    def __init__(self, inputs, outputs, hidden, rows): 
     self.bias = Neuron() 
     self.neurons = [[Neuron(parents=[]) for input_ in xrange(inputs)]] 
     for row in xrange(rows - 2): 
      self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(outputs)]) 
     self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(outputs)]) 
     self.bias.output = True 

    def calculate(self, inputs, increment=0): 
     for i, neuron_row in enumerate(self.neurons): 
      for j, neuron in enumerate(neuron_row): 
       if i == 0: 
        neuron.output = inputs[j] 
       else: 
        neuron.calculate(increment=increment) 
     return [neuron.output for neuron in self.neurons[-1]] 

    def mutate(self, increment): 
     for neuron_row in self.neurons: 
      for neuron in neuron_row: 
       neuron.mutate(increment=increment) 

    def get_genome(self): 
     genome = [] 
     for neuron_row in self.neurons[1:]: 
      genome.append([neuron.genome for neuron in neuron_row]) 
     return genome 

    def set_genome(self, value): 
     for i, neuron_row in enumerate(self.neurons[1:]): 
      for j, neuron in enumerate(neuron_row): 
       neuron.genome = value[i][j] 

    genome = property(get_genome, set_genome) 

的差異從ANN/ANN5.py要ANN/ANN.py:

- self.neurons = [] 
- for row in xrange(rows): 
-  if row == 0: 
-   self.neurons.append([Neuron(parents=[]) for input_ in xrange(inputs)]) 
-  elif row == rows - 1: 
-   self.neurons.append([Neuron(parents=self.neurons[row - 1] + [self.bias]) for output in xrange(outputs)]) 
-  else: 
-   self.neurons.append([Neuron(parents=self.neurons[row - 1] + [self.bias]) for column in xrange(hidden)]) 
+ self.neurons = [[Neuron(parents=[]) for input_ in xrange(inputs)]] 
+ for row in xrange(rows - 2): 
+  self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(outputs)]) 
+ self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(outputs)]) 

(全部在NeuralNetwork的__init__

tests.py:

from random import randint 
from time import time 

from ANN.ANN import NeuralNetwork 
# from ANN.ANN2 import NeuralNetwork as NeuralNetwork2 
# from ANN.ANN3 import NeuralNetwork as NeuralNetwork3 
# from ANN.ANN4 import NeuralNetwork as NeuralNetwork4 
from ANN.ANN5 import NeuralNetwork as NeuralNetwork5 


def test(NeuralNetwork=NeuralNetwork): 
    time_ = time() 
    ANNs = [] 
    for i in xrange(10): 
     ANNs.append(NeuralNetwork(inputs=49, outputs=3, hidden=49, rows=5)) 
    for i, ANN in enumerate(ANNs[:1]): 
     for j in xrange(11): 
      for k in xrange(len(ANNs)/2): 
       for l in xrange(20): 
        ANN.calculate([randint(0, 1) for _ in xrange(49)], increment=j/10) 
        ANNs[k + len(ANNs)/2 * (i < len(ANNs)/2)].calculate([randint(0, 1) for _ in xrange(49)]) 
        # print 'ANN {0} mutation {1:02d} opponent {2} turn {3:02d}'.format(i + 1, j + 1, k + 1, l + 1) 
      ANN.mutate(increment=randint(1, 100)) 
    return time() - time_ 


if __name__ == '__main__': 
    print 'time: {0}'.format(test()) 
    # print 'time 2: {0}'.format(test(NeuralNetwork2)) 
    # print 'time 3: {0}'.format(test(NeuralNetwork3)) 
    # print 'time 4: {0}'.format(test(NeuralNetwork4)) 
    print 'time 5: {0}'.format(test(NeuralNetwork5)) 

我註釋掉ANN2,ANN3和ANN4,因爲他們是更老版本的ANN的,我存儲(僅限本地,他們都不是在Github上),以便比較性能。目前,我只擔心ANN5.py和ANN.py

我爲什麼for i, ANN in enumerate(ANNs[:1]):而不是for i, ANN in enumerate(ANNs):是因爲測試與後者花費的時間太長的原因之間的性能變化,我盤算了一下,結果仍然會是完全足夠,而無需重複過程10 ANN的(我偶爾會做所有10個測試,以確保)

當我最後一次運行這個tests.py是我得到:

time: 0.454416036606 
time 5: 8.02504611015 

,它總是給人有點接近於此。

我已經做了各種測試,比較ANN.py和ANN5.py的功能,到目前爲止他們在相同的情況下做了完全相同的事情。我已經使用基因組屬性來製作兩個完全相同的ANN,一個使用ANN.py中的NeuralNetwork類,另一個使用ANN5.py中的NeuralNetwork類,並且它們總是給出相同的輸入結果。

所以我的問題是,發生了什麼事?我意識到我的問題不是很確切,但我真的不知道爲什麼會有如此巨大的性能差異。我希望的是舊ANN(ANN5.py)只是在背景中做了一些非常低效的事情,這是因爲我初始化了ANN並且新的ANN(ANN.py)正在初始化它,但是我擔心新的ANN有一些完全缺失的東西,因爲某些原因,當我手動測試這兩個時沒有出現/有任何區別。

回答

0

我有點忘了這個問題,並認爲之前發生了一些不好的事情,但最近我發現生成的基因組相當短。那是當我注意到我通過長度爲3的xrange(輸出)循環而不是長度爲49的xrange(hidden)時。

後,我改變了:

for row in xrange(rows - 2): 
    self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(outputs)]) 

要:

for row in xrange(rows - 2): 
    self.neurons.append([Neuron(parents=self.neurons[-1] + [self.bias]) for output in xrange(hidden)]) 

這又回到了類似速度的舊代碼,但至少它產生的正確尺寸的人工神經網絡。