This conversation sounds interesting, I dont think I’ll catch up to all 100 replies up to now but I just want to leave a note that it seems like recurrent networks trained to reconstruct its own past state and the present input from its current state just naturally learn to encode sequences.
there doesn’t seem to be any more to it.
here’s the simplest network I could make that surprisingly is able to more or less learn sequences.
import numpy as np
import time
np.random.seed(0)
class Synapses:
def __init__(self, inputs, outputs, initial_sparsity=0.1):
self.weights = (np.random.sample((inputs, outputs)) < initial_sparsity).astype(np.int8)
def project(self, inputs, outputs, backwards=False):
if backwards:
inputs.values += self.weights[:, outputs.winners].sum(axis=1)
else:
outputs.values += self.weights[inputs.winners, :].sum(axis=0)
def hebbian_update(self, inputs, outputs, factor=1):
self.weights[inputs.winners[:, np.newaxis], outputs.winners] += factor
class Activation:
def __init__(self, size):
self.values = np.zeros(size, dtype=np.float32)
self.boosts = np.zeros(size, dtype=np.float32)
self.winners = np.zeros(0, dtype=np.int64)
def one_hot(self, x):
self.winners = np.array([x], dtype=np.int32)
def kwta(self, k):
self.winners = np.argsort(self.values + self.boosts)[-k:]
def noise(self, f):
self.values += np.random.sample(self.values.shape) * f
def boost_update(self, decrease=1, recover=0.01):
self.boosts *= recover
self.boosts[self.winners] -= decrease
def clear(self):
self.values[:] = 0
self.winners = np.zeros(0, dtype=np.int64)
class SequencePreddictor:
def __init__(self, n_state, n_input, k):
self.n_state = n_state
self.n_input = n_input
self.k = k
self.encoding_matrix = Synapses(n_input, n_state, initial_sparsity=n_state / n_input)
self.state_matrix = Synapses(n_state, n_state, initial_sparsity=0.5)
self.new_state = Activation(n_state)
self.previous_state = Activation(n_state)
self.previous_state_reconst = Activation(n_state)
self.input = Activation(n_input)
self.input_reconst = Activation(n_input)
def step(self, input_index, train=False):
self.previous_state, self.new_state = self.new_state, self.previous_state
self.new_state.clear()
self.state_matrix.project(self.previous_state, self.new_state,)
if input_index is None:
self.input.one_hot(self.decode())
else:
self.input.one_hot(input_index)
self.encoding_matrix.project(self.input, self.new_state)
self.new_state.noise(2)
self.new_state.kwta(self.k)
# self.new_state.boost_update(10, 0.0001)
if train:
self.previous_state_reconst.clear()
self.input_reconst.clear()
self.state_matrix.project(self.previous_state_reconst, self.new_state, backwards=True)
self.encoding_matrix.project(self.input_reconst, self.new_state, backwards=True)
self.previous_state_reconst.kwta(self.k)
self.input_reconst.kwta(1)
# plus phase
self.state_matrix.hebbian_update(self.previous_state, self.new_state, 1)
self.encoding_matrix.hebbian_update(self.input, self.new_state, 1)
# minus phase
self.state_matrix.hebbian_update(self.previous_state_reconst, self.new_state, -1)
self.encoding_matrix.hebbian_update(self.input_reconst, self.new_state, -1)
def decode(self):
self.input_reconst.clear()
self.encoding_matrix.project(self.input_reconst, self.new_state, backwards=True)
self.input_reconst.kwta(1)
return self.input_reconst.winners[0]
input_data = '''Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum. 123456789abcdefghijk'''.replace('\n', '')
EPOCHS = 1
seq_pred = SequencePreddictor(1000, 256, k=10)
for i in range(EPOCHS):
print('epoch', i)
for ch in input_data:
seq_pred.step(ord(ch), train=True)
while True:
seq_pred.step(None)
print(chr(seq_pred.decode()), end='', flush=True)
time.sleep(0.01)