/demo/bpnn.py

https://bitbucket.org/dac_io/pypy · Python · 214 lines · 204 code · 0 blank · 10 comment · 0 complexity · c4a17c05def7af30c6e6ab05c37e918d MD5 · raw file

  1. #!/usr/bin/env python
  2. """
  3. Translator Demo
  4. To analyse and type-annotate the functions and class defined in
  5. this module, starting from the entry point function demo(),
  6. use the following command line:
  7. ../pypy/translator/goal/translate.py bpnn.py
  8. Insert '--help' before 'bpnn.py' for a list of translation options,
  9. or see the Overview of Command Line Options for translation at
  10. http://codespeak.net/pypy/dist/pypy/doc/config/commandline.html
  11. """
  12. # Back-Propagation Neural Networks
  13. #
  14. # Written in Python. See http://www.python.org/
  15. #
  16. # Neil Schemenauer <nascheme@enme.ucalgary.ca>
  17. #
  18. # Modifications to the original (Armin Rigo):
  19. # * import random from PyPy's lib, which is Python 2.2's plain
  20. # Python implementation
  21. # * print a doc about how to start the Translator
  22. import sys
  23. import math
  24. import time
  25. import autopath
  26. from pypy.rlib import rrandom
  27. PRINT_IT = True
  28. random = rrandom.Random(1)
  29. # calculate a random number where: a <= rand < b
  30. def rand(a, b):
  31. return (b-a)*random.random() + a
  32. # Make a matrix (we could use NumPy to speed this up)
  33. def makeMatrix(I, J, fill=0.0):
  34. m = []
  35. for i in range(I):
  36. m.append([fill]*J)
  37. return m
  38. class NN:
  39. def __init__(self, ni, nh, no):
  40. # number of input, hidden, and output nodes
  41. self.ni = ni + 1 # +1 for bias node
  42. self.nh = nh
  43. self.no = no
  44. # activations for nodes
  45. self.ai = [1.0]*self.ni
  46. self.ah = [1.0]*self.nh
  47. self.ao = [1.0]*self.no
  48. # create weights
  49. self.wi = makeMatrix(self.ni, self.nh)
  50. self.wo = makeMatrix(self.nh, self.no)
  51. # set them to random vaules
  52. for i in range(self.ni):
  53. for j in range(self.nh):
  54. self.wi[i][j] = rand(-2.0, 2.0)
  55. for j in range(self.nh):
  56. for k in range(self.no):
  57. self.wo[j][k] = rand(-2.0, 2.0)
  58. # last change in weights for momentum
  59. self.ci = makeMatrix(self.ni, self.nh)
  60. self.co = makeMatrix(self.nh, self.no)
  61. def update(self, inputs):
  62. if len(inputs) != self.ni-1:
  63. raise ValueError, 'wrong number of inputs'
  64. # input activations
  65. for i in range(self.ni-1):
  66. #self.ai[i] = 1.0/(1.0+math.exp(-inputs[i]))
  67. self.ai[i] = inputs[i]
  68. # hidden activations
  69. for j in range(self.nh):
  70. sum = 0.0
  71. for i in range(self.ni):
  72. sum = sum + self.ai[i] * self.wi[i][j]
  73. self.ah[j] = 1.0/(1.0+math.exp(-sum))
  74. # output activations
  75. for k in range(self.no):
  76. sum = 0.0
  77. for j in range(self.nh):
  78. sum = sum + self.ah[j] * self.wo[j][k]
  79. self.ao[k] = 1.0/(1.0+math.exp(-sum))
  80. return self.ao[:]
  81. def backPropagate(self, targets, N, M):
  82. if len(targets) != self.no:
  83. raise ValueError, 'wrong number of target values'
  84. # calculate error terms for output
  85. output_deltas = [0.0] * self.no
  86. for k in range(self.no):
  87. ao = self.ao[k]
  88. output_deltas[k] = ao*(1-ao)*(targets[k]-ao)
  89. # calculate error terms for hidden
  90. hidden_deltas = [0.0] * self.nh
  91. for j in range(self.nh):
  92. sum = 0.0
  93. for k in range(self.no):
  94. sum = sum + output_deltas[k]*self.wo[j][k]
  95. hidden_deltas[j] = self.ah[j]*(1-self.ah[j])*sum
  96. # update output weights
  97. for j in range(self.nh):
  98. for k in range(self.no):
  99. change = output_deltas[k]*self.ah[j]
  100. self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k]
  101. self.co[j][k] = change
  102. #print N*change, M*self.co[j][k]
  103. # update input weights
  104. for i in range(self.ni):
  105. for j in range(self.nh):
  106. change = hidden_deltas[j]*self.ai[i]
  107. self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j]
  108. self.ci[i][j] = change
  109. # calculate error
  110. error = 0.0
  111. for k in range(len(targets)):
  112. delta = targets[k]-self.ao[k]
  113. error = error + 0.5*delta*delta
  114. return error
  115. def test(self, patterns):
  116. for p in patterns:
  117. if PRINT_IT:
  118. print p[0], '->', self.update(p[0])
  119. def weights(self):
  120. if PRINT_IT:
  121. print 'Input weights:'
  122. for i in range(self.ni):
  123. print self.wi[i]
  124. print
  125. print 'Output weights:'
  126. for j in range(self.nh):
  127. print self.wo[j]
  128. def train(self, patterns, iterations=2000, N=0.5, M=0.1):
  129. # N: learning rate
  130. # M: momentum factor
  131. for i in xrange(iterations):
  132. error = 0.0
  133. for p in patterns:
  134. inputs = p[0]
  135. targets = p[1]
  136. self.update(inputs)
  137. error = error + self.backPropagate(targets, N, M)
  138. if PRINT_IT and i % 100 == 0:
  139. print 'error', error
  140. def demo():
  141. # Teach network XOR function
  142. pat = [
  143. [[0,0], [0]],
  144. [[0,1], [1]],
  145. [[1,0], [1]],
  146. [[1,1], [0]]
  147. ]
  148. # create a network with two input, two hidden, and two output nodes
  149. n = NN(2, 3, 1)
  150. # train it with some patterns
  151. n.train(pat, 2000)
  152. # test it
  153. n.test(pat)
  154. # __________ Entry point for stand-alone builds __________
  155. import time
  156. def entry_point(argv):
  157. if len(argv) > 1:
  158. N = int(argv[1])
  159. else:
  160. N = 200
  161. T = time.time()
  162. for i in range(N):
  163. demo()
  164. t1 = time.time() - T
  165. print "%d iterations, %s milliseconds per iteration" % (N, 1000.0*t1/N)
  166. return 0
  167. # _____ Define and setup target ___
  168. def target(*args):
  169. return entry_point, None
  170. if __name__ == '__main__':
  171. if len(sys.argv) == 1:
  172. sys.argv.append('1')
  173. entry_point(sys.argv)
  174. print __doc__