-
Notifications
You must be signed in to change notification settings - Fork 0
/
autoencoder.py
131 lines (106 loc) · 4.42 KB
/
autoencoder.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
import numpy as np
import mlpython.learners.generic as mlgen
import mlpython.learners.classification as mlclass
import mlpython.mlproblems.generic as mlpb
import mlpython.mlproblems.classification as mlpbclass
from mlpython.mathutils.nonlinear import sigmoid
class Autoencoder(mlgen.Learner):
"""
Autoencoder trained with unsupervised learning.
Option ``lr`` is the learning rate.
Option ``hidden_size`` is the size of the hidden layer.
Option ``noise_prob`` is the noise or corruption probability of
setting each input to 0.
Option ``seed`` is the seed of the random number generator.
Option ``n_epochs`` number of training epochs.
"""
def __init__(self,
lr=0.1, # learning rate
hidden_size=50, # hidden layer size
noise_prob=0.1, # probability of setting an input to 0
seed=1234, # seed for random number generator
n_epochs=10 # nb. of training iterations
):
self.n_epochs = n_epochs
self.hidden_size = hidden_size
self.lr = lr
self.noise_prob = noise_prob
self.seed = seed
self.rng = np.random.mtrand.RandomState(self.seed) # create random number generator
def initialize(self,W,b):
self.W = W
self.b = b
def train(self,trainset):
"""
Train autoencoder for ``self.n_epochs`` iterations.
Use ``self.W.T`` as the output weight matrix (i.e. use tied weights).
"""
# Initialize parameters
input_size = trainset.metadata['input_size']
self.W = (self.rng.rand(input_size,self.hidden_size)-0.5)/(max(input_size,self.hidden_size))
self.b = np.zeros((self.hidden_size,))
self.c = np.zeros((input_size,))
# And gradients.
self.grad_W = np.zeros((input_size,self.hidden_size))
self.grad_b = np.zeros((self.hidden_size,))
self.grad_c = np.zeros((input_size,))
for it in range(self.n_epochs):
for input,target in trainset:
# fprop
new_input = self.apply_noise(input)
self.h = self.encode(new_input)
output = self.decode(input_size)
# bprop
# Use the real input (not noisy)
self.grad_c = output - input
half_grad_w = np.dot(self.grad_c[:,np.newaxis], self.h[:,np.newaxis].T)
self.grad_b = np.dot(self.W.T, self.grad_c) * (self.h - self.h**2)
self.grad_W = half_grad_w + (np.dot(self.grad_b[:,np.newaxis], new_input[:,np.newaxis].T)).T
# Updating the parameters
self.update()
print "Epoch #%d"%it
def apply_noise(self, input):
"""
Change some of the input values to 0
with probability self.noise_prob.
Return the noisy output.
"""
mask = np.random.binomial(1, 1-self.noise_prob, len(input))
noisy_input = mask * input
return noisy_input
def encode(self, input):
"""
Encode the input vector
and return the hidden layer.
"""
h = np.zeros(self.hidden_size)
preactivation = np.dot(self.W.T, input) + self.b
sigmoid(preactivation, h)
return h
def decode(self, input_size):
"""
Decode the hidden layer
and return the output.
"""
output = np.zeros(input_size)
preactivation = np.dot(self.W, self.h) + self.c
sigmoid(preactivation, output)
return output
def update(self):
"""
Update the weights and biases
"""
# Update the weight matrix:
self.W -= self.lr * self.grad_W
# Update the bias matrices:
self.b -= self.lr * np.array(self.grad_b)
self.c -= self.lr * np.array(self.grad_c)
def show_filters(self):
from matplotlib.pylab import show, draw, ion
import mlpython.misc.visualize as mlvis
mlvis.show_filters(0.5*self.W.T,
200,
16,
8,
10,20,2)
show()