import random import math learning_rate = 0.25 momentum_factor = 0.5 class Node: def __init__(self,no): self.no = no self.value = 0 self.targetValue= 0 self.bias = 1.0 self.biasWeight = 0 self.error = 0 def setLayer(self,layer): self.layer = layer self.weights = [] self.weightChanges = [] if layer.childLayer: for n in layer.childLayer.nodes: self.weights.append(0) self.weightChanges.append(0) class Layer: useMomentum = True useLinear = True parentLayer = None childLayer = None nodes = [] def __init__(self,nodes_num): self.parentLayer = None self.childLayer = None self.nodes = [] for i in range(nodes_num): node = Node(i) self.nodes.append(node) def setup(self): for node in self.nodes: node.setLayer(self) def randWeights(self): for node in self.nodes: node.biasWeight = random.random()*2-1 for cnode in node.layer.childLayer.nodes: node.weights[cnode.no] = random.random()*2-1 def calcuValues(self): if self.parentLayer: for node in self.nodes: value = 0 for pnode in self.parentLayer.nodes: value += pnode.value * pnode.weights[node.no] value += node.bias * node.biasWeight if self.childLayer==None and self.useLinear: node.value = value else: node.value = 1.0 / (1+math.exp(-value)) def calcuErrors(self): errs = 0 for node in self.nodes: if not self.childLayer: #output layer if self.useLinear: node.error = node.targetValue - node.value else: node.error = ((node.targetValue - node.value)* node.value*(1.0-node.value)) elif not self.parentLayer: #input layer node.error = 0 else: #hidden layer su = 0 for cnode in self.childLayer.nodes: su += cnode.error * node.weights[cnode.no] node.error = su*node.value*(1.0-node.value) def adjustWeights(self): if self.childLayer: for node in self.nodes: for cnode in self.childLayer.nodes: dw = learning_rate*cnode.error*node.value if self.useMomentum: wc = node.weightChanges[cnode.no] node.weights[cnode.no] += dw+momentum_factor*wc node.weightChanges[cnode.no] = dw else: node.weights[cnode.no] += dw for cnode in self.childLayer.nodes: cnode.baisWeight = (learning_rate * cnode.error * cnode.bias) class Network: def __init__(self,input_node_num, hidden_node_num, output_node_num): self.inputLayer = Layer(input_node_num) self.hiddenLayer= Layer(hidden_node_num) self.outputLayer = Layer(output_node_num) self.inputLayer.parentLayer = None self.inputLayer.childLayer = self.hiddenLayer self.inputLayer.setup() self.inputLayer.randWeights() self.hiddenLayer.parentLayer = self.inputLayer self.hiddenLayer.childLayer = self.outputLayer self.hiddenLayer.setup() self.hiddenLayer.randWeights() self.outputLayer.parentLayer = self.hiddenLayer self.outputLayer.childLayer = None self.outputLayer.setup() def setInput(self,no,value): node = self.inputLayer.nodes[no] node.value= value def getOutput(self,no): node = self.outputLayer.nodes[no] return node.value def setTargetOutput(self,no,value): node = self.outputLayer.nodes[no] node.targetValue = value def feedForward(self): self.inputLayer.calcuValues() self.hiddenLayer.calcuValues() self.outputLayer.calcuValues() def backPropagate(self): self.outputLayer.calcuErrors() self.hiddenLayer.calcuErrors() self.hiddenLayer.adjustWeights() self.outputLayer.adjustWeights() def getMaxOutputNo(self): max_value = self.outputLayer.nodes[0].value max_no = 0 for node in self.outputLayer.nodes: if node.value > max_value: max_value = node.value max_no = node.no return max_no def calcuError(self): err = 0 for node in self.outputLayer.nodes: try: err += (node.value - node.targetValue)**2 except OverflowError: print("OverflowError") exit() err = err / len(self.outputLayer.nodes) return err def test(): nw = Network(1,6,1) #learning total_n = 0 x,max_x = 0,math.pi for n in range(10000): x = random.randint(0,int(max_x*100)) x = x/100 nw.setInput(0,x) nw.setTargetOutput(0,math.sin(x)) while True: nw.feedForward() nw.backPropagate() e = nw.calcuError() total_n += 1 if e < 0.001: break r = nw.getOutput(nw.getMaxOutputNo()) pr = (n,x,r,math.sin(x),e) #print "%3d: %3.2f => %.5f(%.5f) err:%.5f" % pr print "total %s cycle:" % total_n #make table f = open("test.csv",'w') f.write("x,sinx,result\n") x,sp = 0,0.05 for i in range(int(max_x/sp)+1): nw.setInput(0,x) nw.feedForward() r = nw.getOutput(nw.getMaxOutputNo()) f.write("%s,%s,%s\n" % (x,math.sin(x),r)) x += sp f.close() def main(): test() main()