Skip to content

Commit 87b70b7

Browse files
committed
Merge pull request #1 from lucasb-eyer/master
Initial commit to agree on architecture.
2 parents 0232b82 + 89c3a10 commit 87b70b7

File tree

11 files changed

+231
-0
lines changed

11 files changed

+231
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# Beacon8
22
A Torch-inspired library for high-level deep learning with Theano.
3+
4+
Thorough documentation will follow very soon.

beacon8/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from layer import *

beacon8/containers/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from .Layers import Module
2+
3+
class Container(Module):
4+
5+
def __init__(self, *modules):
6+
super().__init__()
7+
8+
self.modules = []
9+
for module in modules:
10+
self.add(module)
11+
12+
def evaluate(self):
13+
super().evaluate()
14+
for module in self.modules:
15+
module.evaluate()
16+
17+
def training(self):
18+
super().training()
19+
for module in self.modules:
20+
module.training()
21+
22+
def parameters(self):
23+
params, grads = [], []
24+
25+
for module in self.modules:
26+
mod_params, mod_grads = module.parameters()
27+
params += mod_params
28+
grads += mod_grads
29+
30+
return params, grads
31+
32+
def add(self, module):
33+
self.modules.append(module)
34+
35+
def symbolic_forward(self, symbolic_input):
36+
raise NotImplementedError

beacon8/layers/Linear.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from . import Module
2+
3+
import numpy as _np
4+
import theano as _th
5+
6+
class Linear(Module):
7+
8+
def __init__(self, nin, nout, init='Xavier', with_bias=True):
9+
super().__init__()
10+
11+
self.nin = nin
12+
self.nout = nout
13+
self.init = init
14+
self.with_bias = with_bias
15+
16+
self.reset()
17+
18+
def reset(self):
19+
if self.init == 'Xavier':
20+
w_bound = _np.sqrt(4 / (self.nin + self.nout))
21+
W = _np.random.uniform(low=-w_bound, high=w_bound,
22+
size=(self.nin, self.nout))
23+
else:
24+
raise NotImplementedError
25+
26+
self.weight = _th.shared(W.astype(_th.config.floatX))
27+
28+
if self.with_bias:
29+
self.bias = _th.shared(_np.zeros(shape=self.nout, dtype=_th.config.floatX))
30+
31+
def symbolic_forward(self, symbolic_input):
32+
out = _th.tensor.dot(symbolic_input, self.weight)
33+
34+
if self.with_bias:
35+
out += self.bias
36+
37+
return out

beacon8/layers/Softmax.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from . import Module
2+
3+
import theano.tensor as _T
4+
5+
class SoftMax(Module):
6+
7+
def __init__(self):
8+
Module.__init__(self)
9+
10+
def symbolic_forward(self, symbolic_input):
11+
return _T.nnet.softmax(symbolic_input)

beacon8/layers/__init__.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import theano as _th
2+
import theano.tensor as _T
3+
import theano.config.floatX as _floatX
4+
5+
class Module:
6+
7+
def __init__(self):
8+
self.training_mode = True
9+
10+
self.fn_forward = None
11+
self.fn_accum_grads = None
12+
13+
def reset(self):
14+
pass
15+
16+
def __hash__(self):
17+
raise NotImplementedError("You *need* to reimplement hash, even if it's just python's default. See the documentation for more info.")
18+
19+
def zero_grad_parameters(self):
20+
_, grads = self.parameters()
21+
for grad in grads:
22+
grad.set_value(0 * grad.get_value())
23+
24+
def parameters(self):
25+
params, grads = [], []
26+
27+
if self.training_mode and hasattr(self, 'weight'):
28+
assert hasattr(self, 'grad_weight'), "The layer {} has a `weight` variable but no `grad_weight`, you probably forget to implement it.".format(type(self))
29+
params += [self.weight]
30+
grads += [self.grad_weight]
31+
32+
if self.training_mode and hasattr(self, 'bias'):
33+
assert hasattr(self, 'grad_bias'), "The layer {} has a `bias` variable but no `grad_bias`, you probably forget to implement it.".format(type(self))
34+
params += [self.bias]
35+
grads += [self.grad_bias]
36+
37+
return params, grads
38+
39+
def evaluate(self):
40+
self.training_mode = False
41+
42+
def training(self):
43+
self.training_mode = True
44+
45+
def symb_forward(self, symb_input):
46+
raise NotImplementedError
47+
48+
def forward(self, data):
49+
if self.fn_forward is None:
50+
symb_in = _T.TensorType(_floatX, (False,) * data.ndim)('X')
51+
symb_out = self.symb_forward(symb_in)
52+
self.fn_forward = _th.function(inputs=[symb_in], outputs=symb_out)
53+
54+
return self.fn_forward(data)
55+
56+
def accumulate_gradients(self, data_in, data_tgt, loss):
57+
if self.fn_accum_grads is None:
58+
symb_in = _T.TensorType(_floatX, (False,) * data_in.ndim)('X')
59+
symb_tgt = _T.TensorType(_floatX, (False,) * data_tgt.ndim)('T')
60+
symb_out = self.symbolic_forward(symb_in)
61+
symb_err = loss.symb_forward(symb_out, symb_tgt)
62+
63+
params, grads = self.parameters()
64+
symb_grads = theano.grad(cost=symb_err, wrt=params)
65+
66+
grads_updates = [(grad, grad + symb_grad) for grad, symb_grad in zip(grads, symb_grads)]
67+
self.fn_accum_grads = _th.function(
68+
inputs=[symb_in, symb_tgt],
69+
updates=grads_updates
70+
)
71+
72+
self.fn_accum_grads(data_in, data_tgt)

beacon8/optimizers/Momentum.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from .optimizers import Optimizer
2+
from .utils import create_param_state_as
3+
4+
5+
class Momentum(Optimizer):
6+
7+
def __init__(self, lr, momentum):
8+
super().__init__(lr=lr, momentum=momentum)
9+
10+
def get_updates(self, params, grads, lr, momentum):
11+
updates = []
12+
13+
for param, grad in zip(params, grads):
14+
param_mom = self.create_param_state_as(param)
15+
v = momentum * param_mom - lr * grad
16+
updates.append((param_mom, v))
17+
updates.append((param, param + v))
18+
19+
return updates

beacon8/optimizers/SGD.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from .optimizers import Optimizer
2+
3+
4+
class SGD(Optimizer):
5+
6+
def __init__(self, lr):
7+
super().__init__(lr=lr)
8+
9+
def get_updates(self, params, grads, lr):
10+
return [g - lr * p for g, p in zip(grads, params)]

beacon8/optimizers/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import theano.tensor as _T
2+
3+
4+
class Optimizer:
5+
6+
def __init__(self, **hyperparams):
7+
self.states = {}
8+
self.hyperparams = hyperparams
9+
10+
def update_parameters(self, model):
11+
12+
if model not in self.states:
13+
params, grads = model.parameters()
14+
# TODO: Not only scalar
15+
hyperparams = {name: _T.scalar(name) for name in self.hyperparams}
16+
updates = self.get_updates(params, grads, **hyperparams)
17+
self.states[model] = theano.function(
18+
inputs=list(hyperparams.values()),
19+
updates=updates
20+
)
21+
22+
self.states[model](**self.hyperparams)
23+
24+
def get_updates(self, params, grads):
25+
raise NotImplementedError

beacon8/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import theano as _th
2+
3+
def create_param_state_as(self, other, initial_value=0):
4+
return _th.shared(other.get_value()*0 + initial_value,
5+
broadcastable=other.broadcastable,
6+
name='state_for_' + other.name
7+
)

0 commit comments

Comments
 (0)