-
Notifications
You must be signed in to change notification settings - Fork 74
/
elman.py
133 lines (100 loc) · 4.34 KB
/
elman.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
# -----------------------------------------------------------------------------
# Elman reccurent network
# Copyright (C) 2011 Nicolas P. Rougier
#
# Distributed under the terms of the BSD License.
# -----------------------------------------------------------------------------
# This is an implementation of the multi-layer perceptron with retropropagation
# learning.
# -----------------------------------------------------------------------------
import numpy as np
def sigmoid(x):
''' Sigmoid like function using tanh '''
return np.tanh(x)
def dsigmoid(x):
''' Derivative of sigmoid above '''
return 1.0-x**2
class Elman:
''' Elamn network '''
def __init__(self, *args):
''' Initialization of the perceptron with given sizes. '''
self.shape = args
n = len(args)
# Build layers
self.layers = []
# Input layer (+1 unit for bias
# +size of first hidden layer)
self.layers.append(np.ones(self.shape[0]+1+self.shape[1]))
# Hidden layer(s) + output layer
for i in range(1,n):
self.layers.append(np.ones(self.shape[i]))
# Build weights matrix
self.weights = []
for i in range(n-1):
self.weights.append(np.zeros((self.layers[i].size,
self.layers[i+1].size)))
# dw will hold last change in weights (for momentum)
self.dw = [0,]*len(self.weights)
# Reset weights
self.reset()
def reset(self):
''' Reset weights '''
for i in range(len(self.weights)):
Z = np.random.random((self.layers[i].size,self.layers[i+1].size))
self.weights[i][...] = (2*Z-1)*0.25
def propagate_forward(self, data):
''' Propagate data from input layer to output layer. '''
# Set input layer with data
self.layers[0][:self.shape[0]] = data
# and first hidden layer
self.layers[0][self.shape[0]:-1] = self.layers[1]
# Propagate from layer 0 to layer n-1 using sigmoid as activation function
for i in range(1,len(self.shape)):
# Propagate activity
self.layers[i][...] = sigmoid(np.dot(self.layers[i-1],self.weights[i-1]))
# Return output
return self.layers[-1]
def propagate_backward(self, target, lrate=0.1, momentum=0.1):
''' Back propagate error related to target using lrate. '''
deltas = []
# Compute error on output layer
error = target - self.layers[-1]
delta = error*dsigmoid(self.layers[-1])
deltas.append(delta)
# Compute error on hidden layers
for i in range(len(self.shape)-2,0,-1):
delta = np.dot(deltas[0],self.weights[i].T)*dsigmoid(self.layers[i])
deltas.insert(0,delta)
# Update weights
for i in range(len(self.weights)):
layer = np.atleast_2d(self.layers[i])
delta = np.atleast_2d(deltas[i])
dw = np.dot(layer.T,delta)
self.weights[i] += lrate*dw + momentum*self.dw[i]
self.dw[i] = dw
# Return error
return (error**2).sum()
# -----------------------------------------------------------------------------
if __name__ == '__main__':
import matplotlib
import matplotlib.pyplot as plt
# Example 1: learning a simple time serie
# -------------------------------------------------------------------------
network = Elman(4,8,4)
samples = np.zeros(6, dtype=[('input', float, 4), ('output', float, 4)])
samples[0] = (1,0,0,0), (0,1,0,0)
samples[1] = (0,1,0,0), (0,0,1,0)
samples[2] = (0,0,1,0), (0,0,0,1)
samples[3] = (0,0,0,1), (0,0,1,0)
samples[4] = (0,0,1,0), (0,1,0,0)
samples[5] = (0,1,0,0), (1,0,0,0)
for i in range(5000):
n = i%samples.size
network.propagate_forward(samples['input'][n])
network.propagate_backward(samples['output'][n])
for i in range(samples.size):
o = network.propagate_forward( samples['input'][i] )
print 'Sample %d: %s -> %s' % (i, samples['input'][i], samples['output'][i])
print ' Network output: %s' % (o == o.max()).astype(float)
print