# Python backpropagation neural network 16 first prime numbers simulation
# Originally from http://a...content-available-to-author-only...x.com/nas/python/bpnn.py
import math
import random
import string
random.seed(0)
def rand(a, b):
return (b-a)*random.random() + a
def makeMatrix(I, J, fill=0.0):
m = []
for i in range(I):
m.append([fill]*J)
return m
# Orginally tanh, changed to unipolar sigmoid function
def sigmoid(x):
return 1 / (1 + math.exp(-x))
# derivative of unipolar sigmoid function
def dsigmoid(y):
return y - y**2
class NN:
def __init__(self, ni, nh, no):
self.ni = ni + 1 # +1 for bias node
self.nh = nh
self.no = no
self.ai = [1.0]*self.ni
self.ah = [1.0]*self.nh
self.ao = [1.0]*self.no
self.wi = makeMatrix(self.ni, self.nh)
self.wo = makeMatrix(self.nh, self.no)
for i in range(self.ni):
for j in range(self.nh):
self.wi[i][j] = rand(-0.2, 0.2)
for j in range(self.nh):
for k in range(self.no):
self.wo[j][k] = rand(-2.0, 2.0)
self.ci = makeMatrix(self.ni, self.nh)
self.co = makeMatrix(self.nh, self.no)
def update(self, inputs):
if len(inputs) != self.ni-1:
raise ValueError('wrong number of inputs')
for i in range(self.ni-1):
self.ai[i] = inputs[i]
for j in range(self.nh):
sum = 0.0
for i in range(self.ni):
sum = sum + self.ai[i] * self.wi[i][j]
self.ah[j] = sigmoid(sum)
for k in range(self.no):
sum = 0.0
for j in range(self.nh):
sum = sum + self.ah[j] * self.wo[j][k]
self.ao[k] = sigmoid(sum)
return self.ao[:]
def backPropagate(self, targets, N, M):
if len(targets) != self.no:
raise ValueError('wrong number of target values')
output_deltas = [0.0] * self.no
for k in range(self.no):
error = targets[k]-self.ao[k]
output_deltas[k] = dsigmoid(self.ao[k]) * error
hidden_deltas = [0.0] * self.nh
for j in range(self.nh):
error = 0.0
for k in range(self.no):
error = error + output_deltas[k]*self.wo[j][k]
hidden_deltas[j] = dsigmoid(self.ah[j]) * error
for j in range(self.nh):
for k in range(self.no):
change = output_deltas[k]*self.ah[j]
self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k]
self.co[j][k] = change
for i in range(self.ni):
for j in range(self.nh):
change = hidden_deltas[j]*self.ai[i]
self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j]
self.ci[i][j] = change
error = 0.0
for k in range(len(targets)):
error = error + 0.5*(targets[k]-self.ao[k])**2
return error
# changed to display prime numbers test
def test(self, patterns):
for p in patterns:
output = self.update(p[0])
number = p[0][0] * 8 + p[0][1] * 4 + p[0][2] * 2 + p[0][3]
prime = round(p[1][0]) * 32 + round(p[1][1]) * 16 + round(p[1][2]) * 8 \
+ round(p[1][3]) * 4 + round(p[1][4]) * 2 + round(p[1][5])
print('%d -> %d' % (number + 1, int(prime)))
def train(self, patterns, iterations=1000, N=0.5, M=0.1):
# N: learning rate
# M: momentum factor
for i in range(iterations):
error = 0.0
for p in patterns:
inputs = p[0]
targets = p[1]
self.update(inputs)
error = error + self.backPropagate(targets, N, M)
if i % 100 == 0:
print('error %-.5f' % error)
def demo():
# Teach network prime number function
pat = [
[[0,0,0,0], [0,0,0,0,1,0]], #2
[[0,0,0,1], [0,0,0,0,1,1]], #3
[[0,0,1,0], [0,0,0,1,0,1]], #5
[[0,0,1,1], [0,0,0,1,1,1]], #7
[[0,1,0,0], [0,0,1,0,1,1]], #11
[[0,1,0,1], [0,0,1,1,0,1]], #13
[[0,1,1,0], [0,1,0,0,0,1]], #17
[[0,1,1,1], [0,1,0,0,1,1]], #19
[[1,0,0,0], [0,1,0,1,1,1]], #23
[[1,0,0,1], [0,1,1,1,0,1]], #29
[[1,0,1,0], [0,1,1,1,1,1]], #31
[[1,0,1,1], [1,0,0,1,0,1]], #37
[[1,1,0,0], [1,0,1,0,0,1]], #41
[[1,1,0,1], [1,0,1,0,1,1]], #43
[[1,1,1,0], [1,0,1,1,1,1]], #47
[[1,1,1,1], [1,1,0,1,0,1]], #53
]
n = NN(4, 8, 6)
n.train(pat, 3000)
n.test(pat)
if __name__ == '__main__':
demo()
IyBQeXRob24gYmFja3Byb3BhZ2F0aW9uIG5ldXJhbCBuZXR3b3JrIDE2IGZpcnN0IHByaW1lIG51bWJlcnMgc2ltdWxhdGlvbgojIE9yaWdpbmFsbHkgZnJvbSBodHRwOi8vYS4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ueC5jb20vbmFzL3B5dGhvbi9icG5uLnB5CgppbXBvcnQgbWF0aAppbXBvcnQgcmFuZG9tCmltcG9ydCBzdHJpbmcKCnJhbmRvbS5zZWVkKDApCgpkZWYgcmFuZChhLCBiKToKICAgIHJldHVybiAoYi1hKSpyYW5kb20ucmFuZG9tKCkgKyBhCgpkZWYgbWFrZU1hdHJpeChJLCBKLCBmaWxsPTAuMCk6CiAgICBtID0gW10KICAgIGZvciBpIGluIHJhbmdlKEkpOgogICAgICAgIG0uYXBwZW5kKFtmaWxsXSpKKQogICAgcmV0dXJuIG0KCiMgT3JnaW5hbGx5IHRhbmgsIGNoYW5nZWQgdG8gdW5pcG9sYXIgc2lnbW9pZCBmdW5jdGlvbgpkZWYgc2lnbW9pZCh4KToKICAgIHJldHVybiAxIC8gKDEgKyBtYXRoLmV4cCgteCkpCgojIGRlcml2YXRpdmUgb2YgdW5pcG9sYXIgc2lnbW9pZCBmdW5jdGlvbgpkZWYgZHNpZ21vaWQoeSk6CiAgICByZXR1cm4geSAtIHkqKjIKCmNsYXNzIE5OOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIG5pLCBuaCwgbm8pOgogICAgICAgIHNlbGYubmkgPSBuaSArIDEgIyArMSBmb3IgYmlhcyBub2RlCiAgICAgICAgc2VsZi5uaCA9IG5oCiAgICAgICAgc2VsZi5ubyA9IG5vCgogICAgICAgIHNlbGYuYWkgPSBbMS4wXSpzZWxmLm5pCiAgICAgICAgc2VsZi5haCA9IFsxLjBdKnNlbGYubmgKICAgICAgICBzZWxmLmFvID0gWzEuMF0qc2VsZi5ubwogICAgICAgIAogICAgICAgIHNlbGYud2kgPSBtYWtlTWF0cml4KHNlbGYubmksIHNlbGYubmgpCiAgICAgICAgc2VsZi53byA9IG1ha2VNYXRyaXgoc2VsZi5uaCwgc2VsZi5ubykKCiAgICAgICAgZm9yIGkgaW4gcmFuZ2Uoc2VsZi5uaSk6CiAgICAgICAgICAgIGZvciBqIGluIHJhbmdlKHNlbGYubmgpOgogICAgICAgICAgICAgICAgc2VsZi53aVtpXVtqXSA9IHJhbmQoLTAuMiwgMC4yKQogICAgICAgIGZvciBqIGluIHJhbmdlKHNlbGYubmgpOgogICAgICAgICAgICBmb3IgayBpbiByYW5nZShzZWxmLm5vKToKICAgICAgICAgICAgICAgIHNlbGYud29bal1ba10gPSByYW5kKC0yLjAsIDIuMCkKCiAgICAgICAgc2VsZi5jaSA9IG1ha2VNYXRyaXgoc2VsZi5uaSwgc2VsZi5uaCkKICAgICAgICBzZWxmLmNvID0gbWFrZU1hdHJpeChzZWxmLm5oLCBzZWxmLm5vKQoKICAgIGRlZiB1cGRhdGUoc2VsZiwgaW5wdXRzKToKICAgICAgICBpZiBsZW4oaW5wdXRzKSAhPSBzZWxmLm5pLTE6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ3dyb25nIG51bWJlciBvZiBpbnB1dHMnKQoKICAgICAgICBmb3IgaSBpbiByYW5nZShzZWxmLm5pLTEpOgogICAgICAgICAgICBzZWxmLmFpW2ldID0gaW5wdXRzW2ldCgogICAgICAgIGZvciBqIGluIHJhbmdlKHNlbGYubmgpOgogICAgICAgICAgICBzdW0gPSAwLjAKICAgICAgICAgICAgZm9yIGkgaW4gcmFuZ2Uoc2VsZi5uaSk6CiAgICAgICAgICAgICAgICBzdW0gPSBzdW0gKyBzZWxmLmFpW2ldICogc2VsZi53aVtpXVtqXQogICAgICAgICAgICBzZWxmLmFoW2pdID0gc2lnbW9pZChzdW0pCgogICAgICAgIGZvciBrIGluIHJhbmdlKHNlbGYubm8pOgogICAgICAgICAgICBzdW0gPSAwLjAKICAgICAgICAgICAgZm9yIGogaW4gcmFuZ2Uoc2VsZi5uaCk6CiAgICAgICAgICAgICAgICBzdW0gPSBzdW0gKyBzZWxmLmFoW2pdICogc2VsZi53b1tqXVtrXQogICAgICAgICAgICBzZWxmLmFvW2tdID0gc2lnbW9pZChzdW0pCgogICAgICAgIHJldHVybiBzZWxmLmFvWzpdCgoKICAgIGRlZiBiYWNrUHJvcGFnYXRlKHNlbGYsIHRhcmdldHMsIE4sIE0pOgogICAgICAgIGlmIGxlbih0YXJnZXRzKSAhPSBzZWxmLm5vOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCd3cm9uZyBudW1iZXIgb2YgdGFyZ2V0IHZhbHVlcycpCgogICAgICAgIG91dHB1dF9kZWx0YXMgPSBbMC4wXSAqIHNlbGYubm8KICAgICAgICBmb3IgayBpbiByYW5nZShzZWxmLm5vKToKICAgICAgICAgICAgZXJyb3IgPSB0YXJnZXRzW2tdLXNlbGYuYW9ba10KICAgICAgICAgICAgb3V0cHV0X2RlbHRhc1trXSA9IGRzaWdtb2lkKHNlbGYuYW9ba10pICogZXJyb3IKCiAgICAgICAgaGlkZGVuX2RlbHRhcyA9IFswLjBdICogc2VsZi5uaAogICAgICAgIGZvciBqIGluIHJhbmdlKHNlbGYubmgpOgogICAgICAgICAgICBlcnJvciA9IDAuMAogICAgICAgICAgICBmb3IgayBpbiByYW5nZShzZWxmLm5vKToKICAgICAgICAgICAgICAgIGVycm9yID0gZXJyb3IgKyBvdXRwdXRfZGVsdGFzW2tdKnNlbGYud29bal1ba10KICAgICAgICAgICAgaGlkZGVuX2RlbHRhc1tqXSA9IGRzaWdtb2lkKHNlbGYuYWhbal0pICogZXJyb3IKCiAgICAgICAgZm9yIGogaW4gcmFuZ2Uoc2VsZi5uaCk6CiAgICAgICAgICAgIGZvciBrIGluIHJhbmdlKHNlbGYubm8pOgogICAgICAgICAgICAgICAgY2hhbmdlID0gb3V0cHV0X2RlbHRhc1trXSpzZWxmLmFoW2pdCiAgICAgICAgICAgICAgICBzZWxmLndvW2pdW2tdID0gc2VsZi53b1tqXVtrXSArIE4qY2hhbmdlICsgTSpzZWxmLmNvW2pdW2tdCiAgICAgICAgICAgICAgICBzZWxmLmNvW2pdW2tdID0gY2hhbmdlCgogICAgICAgIGZvciBpIGluIHJhbmdlKHNlbGYubmkpOgogICAgICAgICAgICBmb3IgaiBpbiByYW5nZShzZWxmLm5oKToKICAgICAgICAgICAgICAgIGNoYW5nZSA9IGhpZGRlbl9kZWx0YXNbal0qc2VsZi5haVtpXQogICAgICAgICAgICAgICAgc2VsZi53aVtpXVtqXSA9IHNlbGYud2lbaV1bal0gKyBOKmNoYW5nZSArIE0qc2VsZi5jaVtpXVtqXQogICAgICAgICAgICAgICAgc2VsZi5jaVtpXVtqXSA9IGNoYW5nZQoKICAgICAgICBlcnJvciA9IDAuMAogICAgICAgIGZvciBrIGluIHJhbmdlKGxlbih0YXJnZXRzKSk6CiAgICAgICAgICAgIGVycm9yID0gZXJyb3IgKyAwLjUqKHRhcmdldHNba10tc2VsZi5hb1trXSkqKjIKICAgICAgICByZXR1cm4gZXJyb3IKCiAgICAjIGNoYW5nZWQgdG8gZGlzcGxheSBwcmltZSBudW1iZXJzIHRlc3QKICAgIGRlZiB0ZXN0KHNlbGYsIHBhdHRlcm5zKToKICAgICAgICBmb3IgcCBpbiBwYXR0ZXJuczoKICAgICAgICAgICAgb3V0cHV0ID0gc2VsZi51cGRhdGUocFswXSkKICAgICAgICAgICAgbnVtYmVyID0gcFswXVswXSAqIDggKyBwWzBdWzFdICogNCArIHBbMF1bMl0gKiAyICsgcFswXVszXQogICAgICAgICAgICBwcmltZSA9IHJvdW5kKHBbMV1bMF0pICogMzIgKyByb3VuZChwWzFdWzFdKSAqIDE2ICsgcm91bmQocFsxXVsyXSkgKiA4IFwKICAgICAgICAgICAgKyByb3VuZChwWzFdWzNdKSAqIDQgKyByb3VuZChwWzFdWzRdKSAqIDIgKyByb3VuZChwWzFdWzVdKQogICAgICAgICAgICBwcmludCgnJWQgLT4gJWQnICUgKG51bWJlciArIDEsIGludChwcmltZSkpKQoKICAgIGRlZiB0cmFpbihzZWxmLCBwYXR0ZXJucywgaXRlcmF0aW9ucz0xMDAwLCBOPTAuNSwgTT0wLjEpOgogICAgICAgICMgTjogbGVhcm5pbmcgcmF0ZQogICAgICAgICMgTTogbW9tZW50dW0gZmFjdG9yCiAgICAgICAgZm9yIGkgaW4gcmFuZ2UoaXRlcmF0aW9ucyk6CiAgICAgICAgICAgIGVycm9yID0gMC4wCiAgICAgICAgICAgIGZvciBwIGluIHBhdHRlcm5zOgogICAgICAgICAgICAgICAgaW5wdXRzID0gcFswXQogICAgICAgICAgICAgICAgdGFyZ2V0cyA9IHBbMV0KICAgICAgICAgICAgICAgIHNlbGYudXBkYXRlKGlucHV0cykKICAgICAgICAgICAgICAgIGVycm9yID0gZXJyb3IgKyBzZWxmLmJhY2tQcm9wYWdhdGUodGFyZ2V0cywgTiwgTSkKICAgICAgICAgICAgaWYgaSAlIDEwMCA9PSAwOgogICAgICAgICAgICAgICAgcHJpbnQoJ2Vycm9yICUtLjVmJyAlIGVycm9yKQoKCmRlZiBkZW1vKCk6CiAgICAjIFRlYWNoIG5ldHdvcmsgcHJpbWUgbnVtYmVyIGZ1bmN0aW9uCiAgICBwYXQgPSBbCiAgICAgICAgW1swLDAsMCwwXSwgWzAsMCwwLDAsMSwwXV0sICMyCiAgICAgICAgW1swLDAsMCwxXSwgWzAsMCwwLDAsMSwxXV0sICMzCiAgICAgICAgW1swLDAsMSwwXSwgWzAsMCwwLDEsMCwxXV0sICM1CiAgICAgICAgW1swLDAsMSwxXSwgWzAsMCwwLDEsMSwxXV0sICM3CiAgICAgICAgW1swLDEsMCwwXSwgWzAsMCwxLDAsMSwxXV0sICMxMQogICAgICAgIFtbMCwxLDAsMV0sIFswLDAsMSwxLDAsMV1dLCAjMTMKICAgICAgICBbWzAsMSwxLDBdLCBbMCwxLDAsMCwwLDFdXSwgIzE3CiAgICAgICAgW1swLDEsMSwxXSwgWzAsMSwwLDAsMSwxXV0sICMxOQogICAgICAgIFtbMSwwLDAsMF0sIFswLDEsMCwxLDEsMV1dLCAjMjMKICAgICAgICBbWzEsMCwwLDFdLCBbMCwxLDEsMSwwLDFdXSwgIzI5CiAgICAgICAgW1sxLDAsMSwwXSwgWzAsMSwxLDEsMSwxXV0sICMzMQogICAgICAgIFtbMSwwLDEsMV0sIFsxLDAsMCwxLDAsMV1dLCAjMzcKICAgICAgICBbWzEsMSwwLDBdLCBbMSwwLDEsMCwwLDFdXSwgIzQxCiAgICAgICAgW1sxLDEsMCwxXSwgWzEsMCwxLDAsMSwxXV0sICM0MwogICAgICAgIFtbMSwxLDEsMF0sIFsxLDAsMSwxLDEsMV1dLCAjNDcKICAgICAgICBbWzEsMSwxLDFdLCBbMSwxLDAsMSwwLDFdXSwgIzUzCiAgICBdCgogICAgbiA9IE5OKDQsIDgsIDYpCiAgICBuLnRyYWluKHBhdCwgMzAwMCkKICAgIG4udGVzdChwYXQpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgZGVtbygpCg==